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

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 43ecc75f was 06c7fcc, checked in by Jae Cho <jhjcho@…>, 15 years ago

now uses runXY method in C, not in BaseComponent? which is very slow.

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