source: sasview/sansmodels/src/sans/models/ReflectivityModel.py @ ccb7363

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 ccb7363 was 1352c78, checked in by Jae Cho <jhjcho@…>, 13 years ago

fixed profile plot problem

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