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

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 fd1aec6f was 499fe7a, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Fixing code style problems

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