source: sasmodels/sasmodels/sesans.py @ 7c1cce3

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

oriented sesans: split transform into oriented and unoriented versions

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