source: sasview/sansmodels/src/sans/models/ReflectivityIIModel.py @ 2d9c4039

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

fixed a bug, not properly displaying sldprofile when a negative exponent was set.

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