source: sasview/sansmodels/src/sans/models/SphericalSLDModel.py @ 2e0053e

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 2e0053e was 2e0053e, checked in by Mathieu Doucet <doucetm@…>, 12 years ago

Fixing code style problems

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