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

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 52b8b74 was 4b3d25b, checked in by Jae Cho <jhjcho@…>, 14 years ago

new model and some bug fixes

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