source: sasview/sansmodels/src/sans/models/ReflectivityIIModel.py @ 14ecd871

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 14ecd871 was 0145a25, checked in by Jae Cho <jhjcho@…>, 13 years ago

minor changes for plot labeling

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