source: sasview/sansmodels/src/sans/models/MultiplicationModel.py @ db08737

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

added sld plot for onion model and etc…

  • Property mode set to 100644
File size: 10.1 KB
RevLine 
[c9636f7]1
2from sans.models.BaseComponent import BaseComponent
3import numpy, math
[a68efd1]4import copy
[3740b11]5from sans.models.pluginmodel import Model1DPlugin
[c9636f7]6class MultiplicationModel(BaseComponent):
7    """
[1affe64]8        Use for P(Q)*S(Q); function call must be in the order of P(Q) and then S(Q):
[c52f66f]9        The model parameters are combined from both models, P(Q) and S(Q), except 1) 'effect_radius' of S(Q)
10        which will be calculated from P(Q) via calculate_ER(),
11        and 2) 'scale' in P model which is synchronized w/ volfraction in S
12        then P*S is multiplied by a new param, 'scale_factor'.
[1affe64]13        The polydispersion is applicable only to P(Q), not to S(Q).
14        Note: P(Q) refers to 'form factor' model while S(Q) does to 'structure factor'.
[c9636f7]15    """
[1affe64]16    def __init__(self, p_model, s_model ):
[c9636f7]17        BaseComponent.__init__(self)
[1affe64]18        """
19            @param p_model: form factor, P(Q)
20            @param s_model: structure factor, S(Q)
21        """
[c9636f7]22
[8cfdd5e]23        ## Setting  model name model description
[996fd35]24        self.description=""
[1affe64]25        self.name = p_model.name +" * "+ s_model.name
26        self.description= self.name+"\n"
27        self.fill_description(p_model, s_model)
[c52f66f]28
29        ## Define parameters
30        self.params = {}
31
32        ## Parameter details [units, min, max]
33        self.details = {}
34                     
[1affe64]35        ##models
36        self.p_model= p_model
37        self.s_model= s_model
[5eb9154]38       
39       
[c9636f7]40        ## dispersion
41        self._set_dispersion()
42        ## Define parameters
43        self._set_params()
[c52f66f]44        ## New parameter:Scaling factor
45        self.params['scale_factor'] = 1
46       
[c9636f7]47        ## Parameter details [units, min, max]
48        self._set_details()
[c52f66f]49        self.details['scale_factor'] = ['',     None, None]
50       
[c9636f7]51        #list of parameter that can be fitted
52        self._set_fixed_params() 
[5fc8e22]53        ## parameters with orientation
[1affe64]54        for item in self.p_model.orientation_params:
[5fc8e22]55            self.orientation_params.append(item)
56           
[1affe64]57        for item in self.s_model.orientation_params:
[5fc8e22]58            if not item in self.orientation_params:
[8b677ec]59                self.orientation_params.append(item)
[5fc8e22]60               
[5eb9154]61       
[a68efd1]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     = copy.deepcopy(self.params)
68        obj.description     = copy.deepcopy(self.description)
69        obj.details    = copy.deepcopy(self.details)
70        obj.dispersion = copy.deepcopy(self.dispersion)
[1affe64]71        obj.p_model  = self.p_model.clone()
72        obj.s_model  = self.s_model.clone()
[fe9c19b4]73        #obj = copy.deepcopy(self)
[a68efd1]74        return obj
75   
76   
[c9636f7]77    def _set_dispersion(self):
78        """
79           combined the two models dispersions
[1affe64]80           Polydispersion should not be applied to s_model
[c9636f7]81        """
[1affe64]82        ##set dispersion only from p_model
83        for name , value in self.p_model.dispersion.iteritems():
[a1b2471]84            self.dispersion[name]= value
85                                     
86    def getProfile(self):
87        """
88        Get SLD profile of p_model if exists
89       
90        : return: (r, beta) where r is a list of radius of the transition points
91                beta is a list of the corresponding SLD values
92        : Note: This works only for func_shell# = 2 (exp function).
93        """
94        try:
95            x,y = self.p_model.getProfile()
96        except:
97            x = None
98            y = None
99           
100        return x, y
101   
[c9636f7]102    def _set_params(self):
103        """
104            Concatenate the parameters of the two models to create
105            this model parameters
106        """
[1affe64]107
108        for name , value in self.p_model.params.iteritems():
[c52f66f]109            if not name in self.params.keys() and name != 'scale':
110                self.params[name]= value
[3740b11]111           
[1affe64]112        for name , value in self.s_model.params.iteritems():
113            #Remove the effect_radius from the (P*S) model parameters.
114            if not name in self.params.keys() and name != 'effect_radius':
115                self.params[name]= value
[c52f66f]116               
117        # Set "scale and effec_radius to P and S model as initializing
118        # since run P*S comes from P and S separately.
119        self._set_scale_factor()
120        self._set_effect_radius()       
[c9636f7]121           
122    def _set_details(self):
123        """
124            Concatenate details of the two models to create
125            this model details
126        """
[1affe64]127        for name ,detail in self.p_model.details.iteritems():
[c52f66f]128            if name != 'scale':
129                self.details[name]= detail
[c9636f7]130           
[1affe64]131        for name , detail in self.s_model.details.iteritems():
[c52f66f]132            if not name in self.details.keys() or name != 'effect_radius':
[1affe64]133                self.details[name]= detail
[c52f66f]134   
135    def _set_scale_factor(self):
136        """
137            Set scale=volfraction to P model
138        """
139        value = self.params['volfraction']
140        if value != None: 
141            self.p_model.setParam( 'scale', value)
142           
143           
144    def _set_effect_radius(self):
145        """
146            Set effective radius to S(Q) model
147        """
148        effective_radius = self.p_model.calculate_ER()
149        #Reset the effective_radius of s_model just before the run
150        if effective_radius != None and effective_radius != NotImplemented:
151            self.s_model.setParam('effect_radius',effective_radius)
[c9636f7]152               
[8cfdd5e]153    def setParam(self, name, value):
154        """
155            Set the value of a model parameter
156       
157            @param name: name of the parameter
158            @param value: value of the parameter
159        """
[c52f66f]160        # set param to P*S model
[3740b11]161        self._setParamHelper( name, value)
[c52f66f]162       
163        ## setParam to p model
164        # set 'scale' in P(Q) equal to volfraction
165        if name == 'volfraction':
166            self._set_scale_factor()
167        elif name in self.p_model.getParamList():
[1affe64]168            self.p_model.setParam( name, value)
[c52f66f]169       
170        ## setParam to s model
171        # This is a little bit abundant: Todo: find better way         
172        self._set_effect_radius()
[1affe64]173        if name in self.s_model.getParamList():
174            self.s_model.setParam( name, value)
[c52f66f]175           
[5eb9154]176
[c52f66f]177        #self._setParamHelper( name, value)
[8cfdd5e]178       
179    def _setParamHelper(self, name, value):
180        """
181            Helper function to setparam
182        """
183        # Look for dispersion parameters
184        toks = name.split('.')
185        if len(toks)==2:
186            for item in self.dispersion.keys():
187                if item.lower()==toks[0].lower():
188                    for par in self.dispersion[item]:
189                        if par.lower() == toks[1].lower():
190                            self.dispersion[item][par] = value
191                            return
192        else:
193            # Look for standard parameter
194            for item in self.params.keys():
195                if item.lower()==name.lower():
196                    self.params[item] = value
197                    return
198           
199        raise ValueError, "Model does not contain parameter %s" % name
200             
201   
[c9636f7]202    def _set_fixed_params(self):
203        """
[1affe64]204             fill the self.fixed list with the p_model fixed list
[c9636f7]205        """
[1affe64]206        for item in self.p_model.fixed:
[c9636f7]207            self.fixed.append(item)
[8b677ec]208
[c9636f7]209        self.fixed.sort()
[5eb9154]210               
211               
[c9636f7]212    def run(self, x = 0.0):
213        """ Evaluate the model
214            @param x: input q-value (float or [float, float] as [r, theta])
215            @return: (DAB value)
216        """
[c52f66f]217        # set effective radius and scaling factor before run
218        self._set_effect_radius()
219        self._set_scale_factor()
220        return self.params['scale_factor']*self.p_model.run(x)*self.s_model.run(x)
[1affe64]221
[c9636f7]222    def runXY(self, x = 0.0):
223        """ Evaluate the model
224            @param x: input q-value (float or [float, float] as [qx, qy])
225            @return: DAB value
[c52f66f]226        """ 
227        # set effective radius and scaling factor before run
228        self._set_effect_radius()
229        self._set_scale_factor()
230        return self.params['scale_factor']*self.p_model.runXY(x)* self.s_model.runXY(x)
[06c7fcc]231   
232    ## Now (May27,10) directly uses the model eval function
233    ## instead of the for-loop in Base Component.
234    def evalDistribution(self, x = []):
235        """ Evaluate the model in cartesian coordinates
236            @param x: input q[], or [qx[], qy[]]
237            @return: scattering function P(q[])
238        """
239        # set effective radius and scaling factor before run
240        self._set_effect_radius()
241        self._set_scale_factor()
242        return self.params['scale_factor']*self.p_model.evalDistribution(x)* self.s_model.evalDistribution(x)
[5eb9154]243
[c9636f7]244    def set_dispersion(self, parameter, dispersion):
245        """
246            Set the dispersion object for a model parameter
247            @param parameter: name of the parameter [string]
248            @dispersion: dispersion object of type DispersionModel
249        """
[db39b2a]250        value= None
251        try:
[1affe64]252            if parameter in self.p_model.dispersion.keys():
253                value= self.p_model.set_dispersion(parameter, dispersion)
[8077fc4]254            self._set_dispersion()
[db39b2a]255            return value
256        except:
257            raise 
[c9636f7]258
[1affe64]259    def fill_description(self, p_model, s_model):
[8b677ec]260        """
261            Fill the description for P(Q)*S(Q)
262        """
263        description = ""
[1affe64]264        description += "Note:1) The effect_radius (effective radius) of %s \n"% (s_model.name)
[8b677ec]265        description +="             is automatically calculated from size parameters (radius...).\n"
266        description += "         2) For non-spherical shape, this approximation is valid \n"
[1affe64]267        description += "            only for limited systems. Thus, use it at your own risk.\n"
268        description +="See %s description and %s description \n"%( p_model.name, s_model.name )
269        description += "        for details of individual models."
[8b677ec]270        self.description += description
[c9636f7]271   
Note: See TracBrowser for help on using the repository browser.