source: sasmodels/sasmodels/sesans.py @ 65ceb7d

costrafo411
Last change on this file since 65ceb7d was 65ceb7d, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

Merge branch 'master' into costrafo411

  • Property mode set to 100644
File size: 5.0 KB
RevLine 
[c97724e]1"""
[d459d4e]2Conversion of scattering cross section from SANS (I(q), or rather, ds/dO) in absolute
3units (cm-1)into SESANS correlation function G using a Hankel transformation, then converting
4the SESANS correlation function into polarisation from the SESANS experiment
[c97724e]5
[d459d4e]6Everything is in units of metres except specified otherwise (NOT TRUE!!!)
7Everything is in conventional units (nm for spin echo length)
[c97724e]8
9Wim Bouwman (w.g.bouwman@tudelft.nl), June 2013
10"""
11
12from __future__ import division
13
[7ae2b7f]14import numpy as np  # type: ignore
15from numpy import pi, exp  # type: ignore
[54f1d96]16from scipy.special import j0
[94d13f1]17
[54f1d96]18class SesansTransform(object):
[94d13f1]19    """
20    Spin-Echo SANS transform calculator.  Similar to a resolution function,
21    the SesansTransform object takes I(q) for the set of *q_calc* values and
[7c1cce3]22    produces a transformed dataset.
[94d13f1]23
24    *SElength* (A) is the set of spin-echo lengths in the measured data.
25
26    *zaccept* (1/A) is the maximum acceptance of scattering vector in the spin
27    echo encoding dimension (for ToF: Q of min(R) and max(lam)).
28
29    *Rmax* (A) is the maximum size sensitivity; larger radius requires more
30    computation time.
31    """
32    #: SElength from the data in the original data units; not used by transform
33    #: but the GUI uses it, so make sure that it is present.
[54f1d96]34    q = None  # type: np.ndarray
35
[94d13f1]36    #: q values to calculate when computing transform
37    q_calc = None  # type: np.ndarray
38
[54f1d96]39    # transform arrays
[94d13f1]40    _H = None  # type: np.ndarray
41    _H0 = None # type: np.ndarray
[54f1d96]42
[9f91afe]43    def __init__(self, z, SElength, lam, zaccept, Rmax):
[94d13f1]44        # type: (np.ndarray, float, float) -> None
45        #import logging; logging.info("creating SESANS transform")
46        self.q = z
[9f91afe]47        self._set_hankel(SElength, lam, zaccept, Rmax)
[54f1d96]48
49    def apply(self, Iq):
[7c1cce3]50        G0 = np.dot(self._H0, Iq)
51        G = np.dot(self._H.T, Iq)
52        P = G - G0
[54f1d96]53        return P
54
[9f91afe]55    def _set_hankel(self, SElength, lam, zaccept, Rmax):
[94d13f1]56        # type: (np.ndarray, float, float) -> None
57        # Force float32 arrays, otherwise run into memory problems on some machines
58        SElength = np.asarray(SElength, dtype='float32')
[54f1d96]59
[94d13f1]60        #Rmax = #value in text box somewhere in FitPage?
61        q_max = 2*pi / (SElength[1] - SElength[0])
62        q_min = 0.1 * 2*pi / (np.size(SElength) * SElength[-1])
63        q = np.arange(q_min, q_max, q_min, dtype='float32')
64        dq = q_min
[54f1d96]65
[94d13f1]66        H0 = np.float32(dq/(2*pi)) * q
[54f1d96]67
[94d13f1]68        repq = np.tile(q, (SElength.size, 1)).T
69        repSE = np.tile(SElength, (q.size, 1))
70        H = np.float32(dq/(2*pi)) * j0(repSE*repq) * repq
71
[9f91afe]72        replam = np.tile(lam, (q.size, 1))
73        reptheta = np.arcsin(repq*replam/2*np.pi)
74        mask = reptheta > zaccept
75        H[mask] = 0
76
[94d13f1]77        self.q_calc = q
78        self._H, self._H0 = H, H0
[e4e5e29]79
[7c1cce3]80class OrientedSesansTransform(object):
81    """
82    Oriented Spin-Echo SANS transform calculator.  Similar to a resolution
83    function, the OrientedSesansTransform object takes I(q) for the set
84    of *q_calc* values and produces a transformed dataset.
85
86    *SElength* (A) is the set of spin-echo lengths in the measured data.
87
88    *zaccept* (1/A) is the maximum acceptance of scattering vector in the spin
89    echo encoding dimension (for ToF: Q of min(R) and max(lam)).
90
91    *Rmax* (A) is the maximum size sensitivity; larger radius requires more
92    computation time.
93    """
94    #: SElength from the data in the original data units; not used by transform
95    #: but the GUI uses it, so make sure that it is present.
96    q = None  # type: np.ndarray
97
98    #: q values to calculate when computing transform
99    q_calc = None  # type: np.ndarray
100
101    # transform arrays
102    _cosmat = None  # type: np.ndarray
103    _cos0 = None # type: np.ndarray
104    _Iq_shape = None # type: Tuple[int, int]
105
106    def __init__(self, z, SElength, zaccept, Rmax):
107        # type: (np.ndarray, float, float) -> None
108        #import logging; logging.info("creating SESANS transform")
109        self.q = z
110        self._set_cosmat(SElength, zaccept, Rmax)
111
112    def apply(self, Iq):
113        dq = self.q_calc[0][0]
114        Iq = np.reshape(Iq, self._Iq_shape)
115        G0 = self._cos0 * np.sum(Iq) * dq
[2cdc35b]116        G = np.sum(np.dot(Iq, self._cosmat), axis=0) * dq
[7c1cce3]117        P = G - G0
118        return P
119
[e4e5e29]120    def _set_cosmat(self, SElength, zaccept, Rmax):
121        # type: (np.ndarray, float, float) -> None
122        # Force float32 arrays, otherwise run into memory problems on some machines
123        SElength = np.asarray(SElength, dtype='float32')
[a86e249]124
[e4e5e29]125        # Rmax = #value in text box somewhere in FitPage?
126        q_max = 2 * pi / (SElength[1] - SElength[0])
127        q_min = 0.1 * 2 * pi / (np.size(SElength) * SElength[-1])
[2cdc35b]128        q_min *= 100
[e4e5e29]129
130        q = np.arange(q_min, q_max, q_min, dtype='float32')
131        dq = q_min
132
133        cos0 = np.float32(dq / (2 * pi))
[2cdc35b]134        cosmat = np.float32(dq / (2 * pi)) * np.cos(q[:, None] * SElength[None, :])
[e4e5e29]135
[7c1cce3]136        qx, qy = np.meshgrid(q, q)
137        self._Iq_shape = qx.shape
138        self.q_calc = qx.flatten(), qy.flatten()
139        self._cosmat, self._cos0 = cosmat, cos0
Note: See TracBrowser for help on using the repository browser.