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

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

Added polydispersion in a couple of params in spheresldmodel

  • Property mode set to 100644
File size: 13.0 KB
Line 
1   
2from sans.models.BaseComponent import BaseComponent
3from sans.models.SphereSLDModel import SphereSLDModel
4from copy import deepcopy
5from math import floor
6#from scipy.special import erf
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 SphericalSLDModel(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,
19        assumes 0<= n_shells <=10.
20        """
21
22        ## Setting  model name model description
23        self.description=""
24        model = SphereSLDModel()
25        self.model = model
26        self.name = "SphericalSLDModel"
27        self.description=model.description
28        self.n_shells = multfactor
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_shells'] = self.n_shells
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),...]]
55        self.multiplicity_info = [max_nshells,"No. of Shells:",[],['Radius']]
56       
57   
58    def _clone(self, obj):
59        """
60        Internal utility function to copy the internal
61        data members to a fresh copy.
62        """
63        obj.params     = deepcopy(self.params)
64        obj.non_fittable     = deepcopy(self.non_fittable)
65        obj.description     = deepcopy(self.description)
66        obj.details    = deepcopy(self.details)
67        obj.dispersion = deepcopy(self.dispersion)
68        obj.model  = self.model.clone()
69
70        return obj
71   
72   
73    def _set_dispersion(self):
74        """
75        model dispersions
76        """ 
77        ##set dispersion from model
78        for name , value in self.model.dispersion.iteritems():   
79             
80            nshell = -1
81            if name.split('_')[0] == 'thick':
82                while nshell<1:
83                    nshell += 1
84                    if name.split('_')[1] == 'inter%s' % str(nshell):
85                        self.dispersion[name]= value
86                    else: 
87                        continue
88            else:
89                self.dispersion[name]= value
90
91    def _set_params(self):
92        """
93        Concatenate the parameters of the model to create
94        this model parameters
95        """
96        # rearrange the parameters for the given # of shells
97        for name , value in self.model.params.iteritems():
98            n = 0
99            pos = len(name.split('_'))-1
100            first_name = name.split('_')[0]
101            last_name = name.split('_')[pos]
102            if first_name == 'npts':
103                self.params[name]=value
104                continue
105            elif first_name == 'func':
106                n= -1
107                while n<self.n_shells:
108                    n += 1
109                    if last_name == 'inter%s' % str(n): 
110                        self.params[name]=value
111                        continue
112            elif last_name[0:5] == 'inter':
113                n= -1
114                while n<self.n_shells:
115                    n += 1
116                    if last_name == 'inter%s' % str(n):
117                        self.params[name]= value
118                        continue
119            elif last_name[0:4] == 'flat':
120                while n<self.n_shells:
121                    n += 1
122                    if last_name == 'flat%s' % str(n):
123                        self.params[name]= value
124                        continue
125            elif name == 'n_shells':
126                continue
127            else:
128                self.params[name]= value
129 
130        self.model.params['n_shells'] = self.n_shells   
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        """
140        for name ,detail in self.model.details.iteritems():
141            if name in self.params.iterkeys():
142                self.details[name]= detail
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': 
156                        self.model.setParam(key, 0)
157                        continue
158
159                for nshell in range(self.n_shells,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_solv']
164                            self.model.setParam(key, value)
165                        except: pass
166   
167    def _get_func_list(self):
168        """
169        Get the list of functions in each layer (shell)
170        """
171        #func_list = {}
172        return func_list
173       
174    def getProfile(self):
175        """
176        Get SLD profile
177       
178        : return: (z, beta) where z is a list of depth of the transition points
179                beta is a list of the corresponding SLD values
180        """
181        # max_pts for each layers
182        n_sub = self.params['npts_inter']
183        z = []
184        beta = []
185        z0 = 0
186        sub_range = floor(n_sub/2.0)
187        # two sld points for core
188        z.append(0)
189        beta.append(self.params['sld_core0']) 
190        z.append(self.params['rad_core0']) 
191        beta.append(self.params['sld_core0']) 
192        z0 += self.params['rad_core0']
193        # for layers from the core
194        for n in range(1,self.n_shells+2):
195            i = n
196            # j=0 for interface, j=1 for flat layer
197            for j in range(0,2):
198                # interation for sub-layers
199                for n_s in range(0,n_sub+1):
200                    if j==1:
201                        if i==self.n_shells+1:
202                            break
203                        # shift half sub thickness for the first point
204                        z0 -= dz#/2.0
205                        z.append(z0)
206                        #z0 -= dz/2.0
207                        z0 += self.params['thick_flat%s'% str(i)]
208                       
209                        sld_i = self.params['sld_flat%s'% str(i)]
210                        beta.append(self.params['sld_flat%s'% str(i)])
211                        dz = 0
212                    else:
213                        dz = self.params['thick_inter%s'% str(i-1)]/n_sub
214                        nu = self.params['nu_inter%s'% str(i-1)]
215                        # decide which sld is which, sld_r or sld_l
216                        if i == 1:
217                            sld_l = self.params['sld_core0']
218                        else:
219                            sld_l = self.params['sld_flat%s'% str(i-1)]
220                        if i == self.n_shells+1:
221                            sld_r = self.params['sld_solv']
222                        else:
223                            sld_r = self.params['sld_flat%s'% str(i)]
224                        # get function type
225                        func_idx = self.params['func_inter%s'% str(i-1)]
226                        # calculate the sld
227                        sld_i = self._get_sld(func_idx, n_sub, n_s, nu,
228                                              sld_l, sld_r)
229                    # append to the list
230                    z.append(z0)
231                    beta.append(sld_i)
232                    z0 += dz
233                    if j==1: break
234        # put sld of solvent
235        z.append(z0)
236        beta.append(self.params['sld_solv']) 
237        z_ext = z0/5.0
238        z.append(z0+z_ext)
239        beta.append(self.params['sld_solv']) 
240        # return sld profile (r, beta)
241        return z, beta
242   
243    def _get_sld(self, func_idx, n_sub, n_s, nu, sld_l, sld_r):
244        """
245        Get the function asked to build sld profile
246        : param func_idx: func type number
247        : param n_sub: total number of sub_layer
248        : param n_s: index of sub_layer
249        : param nu: coefficient of the function
250        : param sld_l: sld on the left side
251        : param sld_r: sld on the right side
252        : return: sld value, float
253        """
254        from sans.models.SLDCalFunc import SLDCalFunc
255        # sld_cal init
256        sld_cal = SLDCalFunc()
257        # set params
258        sld_cal.setParam('fun_type',func_idx)
259        sld_cal.setParam('npts_inter',n_sub)
260        sld_cal.setParam('shell_num',n_s)
261        sld_cal.setParam('nu_inter',nu)
262        sld_cal.setParam('sld_left',sld_l)
263        sld_cal.setParam('sld_right',sld_r)
264        # return sld value
265        return sld_cal.run()
266   
267    def setParam(self, name, value):
268        """
269        Set the value of a model parameter
270   
271        : param name: name of the parameter
272        : param value: value of the parameter
273        """
274        # set param to new model
275        self._setParamHelper( name, value)
276       
277        ## setParam to model
278        if name=='sld_solv':
279            # the sld_*** model.params not in params must set to
280            # value of sld_solv
281            for key in self.model.params.iterkeys():
282                if key not in self.params.keys()and key.split('_')[0] == 'sld':
283                        self.model.setParam(key, value)
284           
285        self.model.setParam( name, value)
286
287    def _setParamHelper(self, name, value):
288        """
289        Helper function to setParam
290        """
291        toks = name.split('.')
292        if len(toks)==2:
293            for item in self.dispersion.keys():
294                if item.lower()==toks[0].lower():
295                    for par in self.dispersion[item]:
296                        if par.lower() == toks[1].lower():
297                            self.dispersion[item][par] = value
298                            return
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        for item in self.model.fixed:
313            if item.split('.')[0] in self.params.keys(): 
314                self.fixed.append(item)
315
316        self.fixed.sort()
317        pass         
318
319    def run(self, x = 0.0):
320        """
321        Evaluate the model
322       
323        :param x: input q, or [q,phi]
324       
325        :return: scattering function P(q)
326       
327        """
328
329        return self.model.run(x)
330
331    def runXY(self, x = 0.0):
332        """
333        Evaluate the model
334       
335        : param x: input q-value (float or [float, float] as [qx, qy])
336        : return: scattering function value
337        """ 
338
339        return self.model.runXY(x)
340   
341    ## Now (May27,10) directly uses the model eval function
342    ## instead of the for-loop in Base Component.
343    def evalDistribution(self, x = []):
344        """
345        Evaluate the model in cartesian coordinates
346       
347        : param x: input q[], or [qx[], qy[]]
348        : return: scattering function P(q[])
349        """
350        # set effective radius and scaling factor before run
351        return self.model.evalDistribution(x)
352    def calculate_ER(self):
353        """
354        """
355        return self.model.calculate_ER()
356    def set_dispersion(self, parameter, dispersion):
357        """
358        Set the dispersion object for a model parameter
359       
360        : param parameter: name of the parameter [string]
361        :dispersion: dispersion object of type DispersionModel
362        """
363        value= None
364        try:
365            if parameter in self.model.dispersion.keys():
366                value= self.model.set_dispersion(parameter, dispersion)
367            self._set_dispersion()
368            return value
369        except:
370            raise 
Note: See TracBrowser for help on using the repository browser.