source: sasview/src/sas/models/MultiplicationModel.py @ a342928

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 a342928 was fb3f9af, checked in by butler, 9 years ago

Fixes more sphinx doc build errors

  • Property mode set to 100644
File size: 11.5 KB
RevLine 
[c9636f7]1
[79492222]2from sas.models.BaseComponent import BaseComponent
[7fdb332]3#import numpy, math
[a68efd1]4import copy
[79492222]5#from sas.models.pluginmodel import Model1DPlugin
[c9636f7]6class MultiplicationModel(BaseComponent):
[ac7be54]7    r"""
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
[fb3f9af]12        then P*S is multiplied by a new parameter, 'scale_factor'.
[1affe64]13        The polydispersion is applicable only to P(Q), not to S(Q).
[fb3f9af]14
15        .. note:: P(Q) refers to 'form factor' model while S(Q) does to 'structure factor'.
[c9636f7]16    """
[1affe64]17    def __init__(self, p_model, s_model ):
[c9636f7]18        BaseComponent.__init__(self)
[1affe64]19        """
[7fdb332]20        :param p_model: form factor, P(Q)
21        :param s_model: structure factor, S(Q)
[1affe64]22        """
[c9636f7]23
[8cfdd5e]24        ## Setting  model name model description
[7fdb332]25        self.description = ""
[1affe64]26        self.name = p_model.name +" * "+ s_model.name
[7fdb332]27        self.description= self.name + "\n"
[1affe64]28        self.fill_description(p_model, s_model)
[c52f66f]29
30        ## Define parameters
31        self.params = {}
32
33        ## Parameter details [units, min, max]
34        self.details = {}
[35aface]35       
[1affe64]36        ##models
[7fdb332]37        self.p_model = p_model
38        self.s_model = s_model       
[318b5bbb]39        self.magnetic_params = []
[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)
[318b5bbb]56        for item in self.p_model.magnetic_params: 
57            self.magnetic_params.append(item) 
[1affe64]58        for item in self.s_model.orientation_params:
[5fc8e22]59            if not item in self.orientation_params:
[8b677ec]60                self.orientation_params.append(item)
[35aface]61        # get multiplicity if model provide it, else 1.
62        try:
63            multiplicity = p_model.multiplicity
64        except:
65            multiplicity = 1
66        ## functional multiplicity of the model
[8960479]67        self.multiplicity = multiplicity   
68         
69        # non-fittable parameters
70        self.non_fittable = p_model.non_fittable 
71        self.multiplicity_info = [] 
72        self.fun_list = {}
73        if self.non_fittable > 1:
74            try:
75                self.multiplicity_info = p_model.multiplicity_info
76                self.fun_list = p_model.fun_list
77            except:
78                pass
79        else:
80            self.multiplicity_info = []
81           
[a68efd1]82    def _clone(self, obj):
83        """
[fb3f9af]84        Internal utility function to copy the internal data members to a
85        fresh copy.
[a68efd1]86        """
87        obj.params     = copy.deepcopy(self.params)
88        obj.description     = copy.deepcopy(self.description)
89        obj.details    = copy.deepcopy(self.details)
90        obj.dispersion = copy.deepcopy(self.dispersion)
[1affe64]91        obj.p_model  = self.p_model.clone()
92        obj.s_model  = self.s_model.clone()
[fe9c19b4]93        #obj = copy.deepcopy(self)
[a68efd1]94        return obj
95   
96   
[c9636f7]97    def _set_dispersion(self):
98        """
[fb3f9af]99        combine the two models' dispersions. Polydispersity should not be
100        applied to s_model
[c9636f7]101        """
[1affe64]102        ##set dispersion only from p_model
103        for name , value in self.p_model.dispersion.iteritems():
[7fdb332]104            self.dispersion[name] = value
[a1b2471]105                                     
106    def getProfile(self):
107        """
108        Get SLD profile of p_model if exists
109       
[fb3f9af]110        :return: (r, beta) where r is a list of radius of the transition points\
111                beta is a list of the corresponding SLD values
112
113        .. note:: This works only for func_shell num = 2 (exp function).
[a1b2471]114        """
115        try:
[7fdb332]116            x, y = self.p_model.getProfile()
[a1b2471]117        except:
118            x = None
119            y = None
120           
121        return x, y
122   
[c9636f7]123    def _set_params(self):
124        """
[fb3f9af]125        Concatenate the parameters of the two models to create
126        these model parameters
[c9636f7]127        """
[1affe64]128
129        for name , value in self.p_model.params.iteritems():
[c52f66f]130            if not name in self.params.keys() and name != 'scale':
[7fdb332]131                self.params[name] = value
[3740b11]132           
[1affe64]133        for name , value in self.s_model.params.iteritems():
134            #Remove the effect_radius from the (P*S) model parameters.
135            if not name in self.params.keys() and name != 'effect_radius':
[7fdb332]136                self.params[name] = value
[c52f66f]137               
138        # Set "scale and effec_radius to P and S model as initializing
139        # since run P*S comes from P and S separately.
140        self._set_scale_factor()
141        self._set_effect_radius()       
[c9636f7]142           
143    def _set_details(self):
144        """
[fb3f9af]145        Concatenate details of the two models to create
146        this model's details
[c9636f7]147        """
[7fdb332]148        for name, detail in self.p_model.details.iteritems():
[c52f66f]149            if name != 'scale':
[7fdb332]150                self.details[name] = detail
[c9636f7]151           
[1affe64]152        for name , detail in self.s_model.details.iteritems():
[c52f66f]153            if not name in self.details.keys() or name != 'effect_radius':
[7fdb332]154                self.details[name] = detail
[c52f66f]155   
156    def _set_scale_factor(self):
157        """
[fb3f9af]158        Set scale=volfraction for P model
[c52f66f]159        """
160        value = self.params['volfraction']
161        if value != None: 
[e08bd5b]162            factor = self.p_model.calculate_VR()
[a8a55f2]163            if factor == None or factor == NotImplemented or factor == 0.0:
[7fdb332]164                val = value
[2d6f1f1]165            else:
166                val = value / factor
[a8a55f2]167            self.p_model.setParam('scale', value)
168            self.s_model.setParam('volfraction', val)
[c52f66f]169           
170    def _set_effect_radius(self):
171        """
[fb3f9af]172        Set effective radius to S(Q) model
[c52f66f]173        """
[ccb7363]174        if not 'effect_radius' in self.s_model.params.keys():
175            return
[c52f66f]176        effective_radius = self.p_model.calculate_ER()
177        #Reset the effective_radius of s_model just before the run
178        if effective_radius != None and effective_radius != NotImplemented:
[7fdb332]179            self.s_model.setParam('effect_radius', effective_radius)
[c9636f7]180               
[8cfdd5e]181    def setParam(self, name, value):
182        """
[7fdb332]183        Set the value of a model parameter
[8cfdd5e]184       
[7fdb332]185        :param name: name of the parameter
186        :param value: value of the parameter
[8cfdd5e]187        """
[c52f66f]188        # set param to P*S model
[3740b11]189        self._setParamHelper( name, value)
[c52f66f]190       
191        ## setParam to p model
192        # set 'scale' in P(Q) equal to volfraction
193        if name == 'volfraction':
194            self._set_scale_factor()
195        elif name in self.p_model.getParamList():
[1affe64]196            self.p_model.setParam( name, value)
[c52f66f]197       
198        ## setParam to s model
199        # This is a little bit abundant: Todo: find better way         
200        self._set_effect_radius()
[1affe64]201        if name in self.s_model.getParamList():
[2d6f1f1]202            if name != 'volfraction':
203                self.s_model.setParam( name, value)
[c52f66f]204           
[5eb9154]205
[c52f66f]206        #self._setParamHelper( name, value)
[8cfdd5e]207       
208    def _setParamHelper(self, name, value):
209        """
[fb3f9af]210        Helper function to setparam
[8cfdd5e]211        """
212        # Look for dispersion parameters
213        toks = name.split('.')
214        if len(toks)==2:
215            for item in self.dispersion.keys():
216                if item.lower()==toks[0].lower():
217                    for par in self.dispersion[item]:
218                        if par.lower() == toks[1].lower():
219                            self.dispersion[item][par] = value
220                            return
221        else:
222            # Look for standard parameter
223            for item in self.params.keys():
[ae4c139]224                if item.lower() == name.lower():
[8cfdd5e]225                    self.params[item] = value
226                    return
227           
228        raise ValueError, "Model does not contain parameter %s" % name
229             
230   
[c9636f7]231    def _set_fixed_params(self):
232        """
[fb3f9af]233        Fill the self.fixed list with the p_model fixed list
[c9636f7]234        """
[1affe64]235        for item in self.p_model.fixed:
[c9636f7]236            self.fixed.append(item)
[8b677ec]237
[c9636f7]238        self.fixed.sort()
[5eb9154]239               
240               
[c9636f7]241    def run(self, x = 0.0):
[7fdb332]242        """
243        Evaluate the model
[fb3f9af]244       
[7fdb332]245        :param x: input q-value (float or [float, float] as [r, theta])
246        :return: (scattering function value)
[c9636f7]247        """
[c52f66f]248        # set effective radius and scaling factor before run
249        self._set_effect_radius()
250        self._set_scale_factor()
[7fdb332]251        return self.params['scale_factor'] * self.p_model.run(x) * \
252                            self.s_model.run(x)
[1affe64]253
[c9636f7]254    def runXY(self, x = 0.0):
[fb3f9af]255        """
256        Evaluate the model
257       
258        :param x: input q-value (float or [float, float] as [qx, qy])
259        :return: scattering function value
[c52f66f]260        """ 
261        # set effective radius and scaling factor before run
262        self._set_effect_radius()
263        self._set_scale_factor()
[7fdb332]264        out = self.params['scale_factor'] * self.p_model.runXY(x) * \
265                        self.s_model.runXY(x)
266        return out
[06c7fcc]267   
268    ## Now (May27,10) directly uses the model eval function
269    ## instead of the for-loop in Base Component.
270    def evalDistribution(self, x = []):
[7fdb332]271        """
272        Evaluate the model in cartesian coordinates
[fb3f9af]273       
[7fdb332]274        :param x: input q[], or [qx[], qy[]]
275        :return: scattering function P(q[])
[06c7fcc]276        """
277        # set effective radius and scaling factor before run
278        self._set_effect_radius()
279        self._set_scale_factor()
[7fdb332]280        out = self.params['scale_factor'] * self.p_model.evalDistribution(x) * \
281                        self.s_model.evalDistribution(x)
282        return out
[5eb9154]283
[c9636f7]284    def set_dispersion(self, parameter, dispersion):
285        """
[7fdb332]286        Set the dispersion object for a model parameter
[fb3f9af]287       
[7fdb332]288        :param parameter: name of the parameter [string]
289        :dispersion: dispersion object of type DispersionModel
[c9636f7]290        """
[7fdb332]291        value = None
[db39b2a]292        try:
[1affe64]293            if parameter in self.p_model.dispersion.keys():
[7fdb332]294                value = self.p_model.set_dispersion(parameter, dispersion)
[8077fc4]295            self._set_dispersion()
[db39b2a]296            return value
297        except:
298            raise 
[c9636f7]299
[1affe64]300    def fill_description(self, p_model, s_model):
[8b677ec]301        """
[fb3f9af]302        Fill the description for P(Q)*S(Q)
[8b677ec]303        """
304        description = ""
[7fdb332]305        description += "Note:1) The effect_radius (effective radius) of %s \n"%\
306                                                                (s_model.name)
307        description += "             is automatically calculated "
308        description += "from size parameters (radius...).\n"
309        description += "         2) For non-spherical shape, "
310        description += "this approximation is valid \n"
311        description += "            only for limited systems. "
312        description += "Thus, use it at your own risk.\n"
313        description += "See %s description and %s description \n"% \
314                                                ( p_model.name, s_model.name )
[1affe64]315        description += "        for details of individual models."
[8b677ec]316        self.description += description
[c9636f7]317   
Note: See TracBrowser for help on using the repository browser.