source: sasview/sansmodels/src/sans/models/ReflectivityModel.py @ 35aface

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 35aface was 35aface, checked in by Jae Cho <jhjcho@…>, 14 years ago

addede new models and attr. non_fittable

  • Property mode set to 100644
File size: 12.4 KB
Line 
1   
2from sans.models.BaseComponent import BaseComponent
3from sans.models.ReflModel import ReflModel
4import copy
5from math import floor
6from scipy.special import erf
7func_list = {'Erf':0, 'Linear':1, 'RParabolic':2, \
8                     'LParabola':3, 'RCubic':4, 'LCubic':5}
9max_nshells = 10
10class ReflectivityModel(BaseComponent):
11    """
12    This multi-model is based on Parratt formalism and provides the capability
13    of changing the number of layers between 0 and 10.
14    """
15    def __init__(self, multfactor=1):
16        BaseComponent.__init__(self)
17        """
18        :param multfactor: number of layers in the model, assumes 0<= n_shells <=10.
19        """
20
21        ## Setting  model name model description
22        self.description=""
23        model = ReflModel()
24        self.model = model
25        self.name = "ReflectivityModel"
26        self.description=model.description
27        self.n_layers = multfactor
28        ## Define parameters
29        self.params = {}
30
31        ## Parameter details [units, min, max]
32        self.details = {}
33       
34        # non-fittable parameters
35        self.non_fittable = model.non_fittable
36       
37        # list of function in order of the function number
38        self.fun_list = self._get_func_list()
39        ## dispersion
40        self._set_dispersion()
41        ## Define parameters
42        self._set_params()
43       
44        ## Parameter details [units, min, max]
45        self._set_details()
46       
47        #list of parameter that can be fitted
48        self._set_fixed_params() 
49        self.model.params['n_layers'] = self.n_layers
50       
51        ## functional multiplicity of the model
52        self.multiplicity = max_nshells
53   
54    def _clone(self, obj):
55        """
56        Internal utility function to copy the internal
57        data members to a fresh copy.
58        """
59        obj.params     = copy.deepcopy(self.params)
60        obj.non_fittable     = copy.deepcopy(self.non_fittable)
61        obj.description     = copy.deepcopy(self.description)
62        obj.details    = copy.deepcopy(self.details)
63        obj.dispersion = copy.deepcopy(self.dispersion)
64        obj.model  = self.model.clone()
65
66        return obj
67   
68   
69    def _set_dispersion(self):
70        """
71        model dispersions
72        """ 
73        ##set dispersion from model
74        self.dispersion = {}
75                   
76
77    def _set_params(self):
78        """
79        Concatenate the parameters of the model to create
80        this model parameters
81        """
82        # rearrange the parameters for the given # of shells
83        for name , value in self.model.params.iteritems():
84            n = 0
85            pos = len(name.split('_'))-1
86            if name.split('_')[0] == 'func':
87                n= -1
88                while n<self.n_layers:
89                    n += 1
90                    if name.split('_')[pos] == 'inter%s' % str(n):
91                        self.params[name]=value
92                        continue
93                #continue
94            elif name.split('_')[pos][0:5] == 'inter':
95                n= -1
96                while n<self.n_layers:
97                    n += 1
98                    if name.split('_')[pos] == 'inter%s' % str(n):
99                        self.params[name]= value
100                        continue
101            elif name.split('_')[pos][0:4] == 'flat':
102                while n<self.n_layers:
103                    n += 1
104                    if name.split('_')[pos] == 'flat%s' % str(n):
105                        self.params[name]= value
106                        continue
107            elif name == 'n_layers':
108                continue
109            else:
110                self.params[name]= value
111               
112        self.model.params['n_layers'] = self.n_layers   
113
114        # set constrained values for the original model params
115        self._set_xtra_model_param()       
116
117    def _set_details(self):
118        """
119        Concatenate details of the original model to create
120        this model details
121        """
122        for name ,detail in self.model.details.iteritems():
123            if name in self.params.iterkeys():
124                self.details[name]= detail
125           
126   
127    def _set_xtra_model_param(self):
128        """
129        Set params of original model that are hidden from this model
130        """
131        # look for the model parameters that are not in param list
132        for key in self.model.params.iterkeys():
133            if key not in self.params.keys():
134                if  key.split('_')[0] == 'thick':
135                    self.model.setParam(key, 0)
136                    continue
137                if  key.split('_')[0] == 'func':
138                    self.model.setParam(key, 0)
139                    continue
140                for nshell in range(self.n_layers,max_nshells):
141                    if key.split('_')[1] == 'flat%s' % str(nshell+1):
142                        try:
143                            value = self.model.params['sld_medium']
144                            self.model.setParam(key, value)
145                        except: pass
146   
147    def _get_func_list(self):
148        """
149        Get the list of functions in each layer (shell)
150        """
151        #func_list = {}
152        return func_list
153       
154    def getProfile(self):
155        """
156        Get SLD profile
157       
158        : return: (z, beta) where z is a list of depth of the transition points
159                beta is a list of the corresponding SLD values
160        """
161        # max_pts for each layers
162        n_sub = 21
163        z = []
164        beta = []
165        sub_range = floor(n_sub/2.0)
166        z.append(0)
167        beta.append(self.params['sld_sub0']) 
168       
169        z0 = 0
170        # for layers from the top
171        for n in range(1,self.n_layers+2):
172            i = n
173
174            for j in range(0,2):
175                for n_s in range(-sub_range,sub_range+1):
176                    if j==1:
177                        if i==self.n_layers+1:
178                            break
179                        # shift half sub thickness for the first point
180                        z0 += dz/2.0
181                        z.append(z0)
182                        #z0 -= dz/2.0
183                        z0 += self.params['thick_flat%s'% str(i)]
184                       
185                        sld_i = self.params['sld_flat%s'% str(i)]
186                        beta.append(self.params['sld_flat%s'% str(i)])
187                    else:
188                       
189                        dz = self.params['thick_inter%s'% str(i-1)]/n_sub
190                       
191                        if n_s == -sub_range:
192                            # shift half sub thickness for the first point
193                            z0 -= dz/2.0
194                        #exec "dz = self.params['thick_inter[%s-1]'% str(i)]/9"
195                        #print "%d = %g \n"% (i,self.params['thick_inter3'])
196                        z0 += dz
197
198                        if i == 1:
199                            sld_l = self.params['sld_sub0']
200                        else:
201                            sld_l = self.params['sld_flat%s'% str(i-1)]
202                        if i == self.n_layers+1:
203                            sld_r = self.params['sld_medium']
204                        else:
205                            sld_r = self.params['sld_flat%s'% str(i)]
206                        func_idx = self.params['func_inter%s'% str(i-1)]
207                        func = self._get_func(n_s, n_sub, func_idx)
208                        if sld_r>sld_l:
209                            sld_i = (sld_r-sld_l)*func+sld_l
210                        elif sld_r<sld_l:
211                            sld_i = (sld_l-sld_r)*(1-func)+sld_r
212                        else:
213                             sld_i = sld_r
214                    z.append(z0)
215                    beta.append(sld_i)
216                    if j==1: break
217        # put substrate and superstrate profile
218        # shift half sub thickness for the first point
219        z0 += dz/2.0
220        z.append(z0)
221        beta.append(self.params['sld_medium']) 
222        z_ext = z0/6.0
223       
224        # put the extra points for the substrate
225        # and superstrate
226        z.append(z0+z_ext)
227        beta.append(self.params['sld_medium']) 
228        z.insert(0,-z_ext)
229        beta.insert(0,self.params['sld_sub0']) 
230        z = [z0 - x for x in z]
231        z.reverse()
232        beta.reverse() 
233        return z, beta
234   
235    def _get_func(self, index, n_sub, func_idx):
236        """
237        Get the function asked to buil sld profile
238        : param index: index of sub_layer
239        : param n_sub: total number of sub_layer
240        : param func_idx: an integer to identify a function
241       
242        : return out: the output from the function, float
243        """
244        # cal bin_size
245        bin_size = 1.0/n_sub
246        # erf
247        if func_idx == 0:
248            out = erf(index/(n_sub/5.0))/2.0 + 0.5
249            return out
250        else:
251            index += 0.5
252        # linear
253        if func_idx == 1:
254            out = ((index + floor(n_sub/2.0))*bin_size)
255        # r_parabolic
256        elif func_idx == 2:
257            out = ((index + floor(n_sub/2.0))*bin_size)* \
258                    ((index + floor(n_sub/2.0))*bin_size)
259        # l_parabolic
260        elif func_idx == 3:
261            out = 1.0-(((index + floor(n_sub/2.0))*bin_size) - 1.0) *\
262                    (((index + floor(n_sub/2.0))*bin_size) - 1.0)
263        # r_cubic
264        elif func_idx == 4:
265            out = ((index + floor(n_sub/2.0))*bin_size)* \
266                    ((index + floor(n_sub/2.0))*bin_size)* \
267                    ((index + floor(n_sub/2.0))*bin_size)
268        # l_cubic
269        elif func_idx == 5:
270            out = 1.0+(((index + floor(n_sub/2.0)))*bin_size - 1.0) *\
271                    (((index + floor(n_sub/2.0)))*bin_size - 1.0) *\
272                    (((index + floor(n_sub/2.0)))*bin_size - 1.0)
273        # return output
274        return out
275   
276    def setParam(self, name, value):
277        """
278        Set the value of a model parameter
279   
280        : param name: name of the parameter
281        : param value: value of the parameter
282        """
283        # set param to new model
284        self._setParamHelper( name, value)
285       
286        ## setParam to model
287        if name=='sld_medium':
288            # the sld_*** model.params not in params must set to value of sld_solv
289            for key in self.model.params.iterkeys():
290                if key not in self.params.keys()and key.split('_')[0] == 'sld':
291                        self.model.setParam(key, value)
292           
293        self.model.setParam( name, value)
294
295    def _setParamHelper(self, name, value):
296        """
297        Helper function to setParam
298        """
299
300        # Look for standard parameter
301        for item in self.params.keys():
302            if item.lower()==name.lower():
303                self.params[item] = value
304                return
305       
306        raise ValueError, "Model does not contain parameter %s" % name
307             
308   
309    def _set_fixed_params(self):
310        """
311        Fill the self.fixed list with the model fixed list
312        """
313        pass         
314
315    def run(self, x = 0.0):
316        """
317        Evaluate the model
318       
319        :param x: input q, or [q,phi]
320       
321        :return: scattering function P(q)
322       
323        """
324
325        return self.model.run(x)
326
327    def runXY(self, x = 0.0):
328        """
329        Evaluate the model
330       
331        : param x: input q-value (float or [float, float] as [qx, qy])
332        : return: scattering function value
333        """ 
334
335        return self.model.runXY(x)
336   
337    ## Now (May27,10) directly uses the model eval function
338    ## instead of the for-loop in Base Component.
339    def evalDistribution(self, x = []):
340        """
341        Evaluate the model in cartesian coordinates
342       
343        : param x: input q[], or [qx[], qy[]]
344        : return: scattering function P(q[])
345        """
346        # set effective radius and scaling factor before run
347        return self.model.evalDistribution(x)
348    def calculate_ER(self):
349        """
350        """
351        return self.model.calculate_ER()
352    def set_dispersion(self, parameter, dispersion):
353        """
354        Set the dispersion object for a model parameter
355       
356        : param parameter: name of the parameter [string]
357        :dispersion: dispersion object of type DispersionModel
358        """
359        pass
Note: See TracBrowser for help on using the repository browser.