source: sasview/park_integration/temp_code_exchange.py @ c41e268

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since c41e268 was b9d5f88, checked in by Mathieu Doucet <doucetm@…>, 15 years ago

park_integration: add temp code for team to consider. File to be removed.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1"""
2    This file is intended to be a temporary file to communicate in-progress code
3    to the developers.
4    This file should be removed after its content has been used by the team.
5"""
6
7
8# This code belongs in AbstractFitEngine
9class FitData1D:
10    def setFitRange(self,qmin=None,qmax=None):
11        """
12            Change the fit range.
13            Take into account the fact that if smearing is applied,
14            a wider range in unsmeared Q might be necessary to cover
15            the smeared (observed) Q range.       
16        """
17       
18        # Skip Q=0 point, (especially for y(q=0)=None at x[0]).
19        #ToDo: Fix this.
20        if qmin==0.0 and not numpy.isfinite(self.data.y[qmin]):
21            self.qmin = min(self.data.x[self.data.x!=0])
22        elif qmin!=None:                       
23            self.qmin = qmin           
24
25        if qmax !=None:
26            self.qmax = qmax
27           
28        # Range used for input to smearing
29        self._qmin_unsmeared = self.qmin
30        self._qmax_unsmeared = self.qmax   
31       
32        # Determine the range needed in unsmeared-Q to cover
33        # the smeared Q range
34        if self.smearer.__class__.__name__ == 'SlitSmearer':
35            # The entries in the slit smearer matrix remain
36            # large across all bins, so we keep the full Q range.
37            self._qmin_unsmeared = min(self.data.x)
38            self._qmax_unsmeared = max(self.data.x)
39        elif self.smearer.__class__.__name__ == 'QSmearer':
40            # Take 3 sigmas as the offset between smeared and unsmeared space.
41            try:
42                offset = 3.0*max(self.smearer.width)
43                self._qmin_unsmeared = max([min(self.data.x), self.qmin-offset])
44                self._qmax_unsmeared = min([max(self.data.x), self.qmax+offset])
45            except:
46                logging.error("FitData1D.setFitRange: %s" % sys.exc_value)
47       
48
49    def residuals(self, fn):
50        """
51            Compute residuals.
52           
53            If self.smearer has been set, use if to smear
54            the data before computing chi squared.
55           
56            This is a version based on the current version of residuals.
57           
58            It takes into account the fact that the unsmearing range
59            might need to be wider than the smeared (observed) range.
60           
61            @param fn: function that return model value
62            @return residuals
63        """
64        x,y = [numpy.asarray(v) for v in (self.x,self.y)]
65        if self.dy ==None or self.dy==[]:
66            dy= numpy.zeros(len(y)) 
67        else:
68            dy= numpy.asarray(dy)
69     
70        dy[dy==0]=1
71        idx_unsmeared = (x>=self._qmin_unsmeared) & (x <= self._qmax_unsmeared)
72 
73        # Compute theory data f(x)
74        idx=[]
75        tempy=[]
76        tempfx=[]
77        tempdy=[]
78   
79        _first_bin = None
80        for i_x in range(len(x)):
81            try:
82                if idx_unsmeared[i_x]==True:
83                    if _first_bin is None:
84                        _first_bin = i_x
85                   
86                    value= fn(x[i_x])
87                    idx.append(x[i_x]>=self.qmin and x[i_x]<=self.qmax)
88                    tempfx.append( value)
89                    tempy.append(y[i_x])
90                    tempdy.append(dy[i_x])
91            except:
92                ## skip error for model.run(x)
93                pass
94                 
95        ## Smear theory data
96        # The tempfx array has a length limited by the Q range.
97        if self.smearer is not None:
98            tempfx = self.smearer(tempfx, _first_bin)
99       
100        newy = numpy.asarray(tempy)
101        newfx= numpy.asarray(tempfx)
102        newdy= numpy.asarray(tempdy)
103       
104        ## Sanity check
105        if numpy.size(newdy)!= numpy.size(newfx):
106            raise RuntimeError, "FitData1D: invalid error array %d <> %d" % (numpy.size(newdy), numpy.size(newfx))
107
108        return (newy[idx]-newfx[idx])/newdy[idx]
109     
110     
111    def residuals_alt(self, fn):
112        """
113            Compute residuals.
114           
115            If self.smearer has been set, use if to smear
116            the data before computing chi squared.
117           
118            This is a more streamlined version of the above. To use this version,
119            the _BaseSmearer class below needs to be modified to have its __call__
120            method have the following signature:
121           
122            __call__(self, iq, first_bin, last_bin)
123           
124            This is because we are storing results in arrays of a length
125            corresponding to the full Q-range.
126           
127            It takes into account the fact that the unsmearing range
128            might need to be wider than the smeared (observed) range.           
129           
130            @param fn: function that return model value
131            @return residuals
132        """
133        # Make sure the arrays are numpy arrays, which are
134        # expected by the fitter.
135        x,y = [numpy.asarray(v) for v in (self.x,self.y)]
136        if self.dy ==None or self.dy==[]:
137            dy= numpy.zeros(len(y)) 
138        else:
139            dy= numpy.asarray(dy)
140     
141        dy[dy==0]=1
142        idx = (x>=self.qmin) & (x <= self.qmax)
143        idx_unsmeared = (x>=self._qmin_unsmeared) & (x <= self._qmax_unsmeared)
144 
145        # Compute theory data f(x)
146        fx= numpy.zeros(len(x))
147   
148        # First and last bins of the array, corresponding to
149        # the Q range to be smeared
150        _first_bin = None
151        _last_bin  = None
152        for i_x in range(len(x)):
153            try:
154                if idx_unsmeared[i_x]==True:
155                    if _first_bin is None:
156                        _first_bin = i_x
157                    else:
158                        _last_bin  = i_x
159                   
160                    value = fn(x[i_x])
161                    fx[i_x] = value
162            except:
163                ## skip error for model.run(x)
164                ## Should properly log the error
165                pass
166                 
167        # Smear theory data
168        if self.smearer is not None:
169            fx = self.smearer(fx, _first_bin, _last_bin)
170       
171        # Sanity check
172        if numpy.size(dy)!= numpy.size(fx):
173            raise RuntimeError, "FitData1D: invalid error array %d <> %d" % (numpy.size(dy), numpy.size(fx))
174
175        # Return the residuals for the smeared (observed) Q range
176        return (y[idx]-fx[idx])/dy[idx]
177     
178# The following code belongs in DataLoader.qsmearing
179class _BaseSmearer(object):
180   
181    def __init__(self):
182        self.nbins = 0
183        self._weights = None
184       
185    def _compute_matrix(self): return NotImplemented
186
187    def __call__(self, iq, first_bin=0):
188        """
189            Return the smeared I(q) value at the given q.
190            The smeared I(q) is computed using a predetermined
191            smearing matrix for a particular binning.
192       
193            @param q: I(q) array
194            @param first_bin: first bin of the given iq array if shorter than full data length
195            @return: smeared I(q)
196        """
197        # Sanity check
198        if len(iq)+first_bin > self.nbins:
199            raise RuntimeError, "Invalid I(q) vector: inconsistent array length %s > %s" % (str(len(iq)+first_bin), str(self.nbins))
200       
201        if self._weights == None:
202            self._compute_matrix()
203           
204        iq_smeared = numpy.zeros(len(iq))
205        # Loop over q-values
206        idwb=[]
207       
208        for q_i in range(len(iq)):
209            sum = 0.0
210            counts = 0.0 
211            for i in range(len(iq)):
212                if iq[i]==0 or self._weights[q_i+first_bin][i+first_bin]==0:
213                    continue
214                else:
215                    sum += iq[i] * self._weights[q_i+first_bin][i+first_bin] 
216                    counts += self._weights[q_i+first_bin][i+first_bin]
217           
218            if counts == 0:
219                iq_smeared[q_i] = 0
220            else:
221                iq_smeared[q_i] = sum/counts
222        return iq_smeared             
Note: See TracBrowser for help on using the repository browser.