source: sasview/src/sas/models/ReflectivityModel.py @ 6bd3a8d1

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 6bd3a8d1 was 79492222, checked in by krzywon, 10 years ago

Changed the file and folder names to remove all SANS references.

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