source: sasview/src/sas/perspectives/fitting/plugin_models/sum_Ap1_1_Ap2.py @ cbe8c5c

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 cbe8c5c was b9a5f0e, checked in by krzywon, 10 years ago

90% complete with the conversion.

  • Property mode set to 100644
File size: 15.7 KB
Line 
1# A sample of an experimental model function for Sum(APmodel1,(1-A)Pmodel2)
2import copy
3from sas.models.pluginmodel import Model1DPlugin
4import os
5import sys
6"""
7## *****************************************************************************
8Please select the 'Compile' from the menubar after the modification and saving.
9Note that we recommend to save the file as a different file name.
10Otherwise, it could be removed in the future on re-installation of the SasView.
11## *****************************************************************************
12"""
13
14# Available model names for this sum model
15"""
16BCCrystalModel, BEPolyelectrolyte, BarBellModel, BinaryHSModel, BroadPeakModel,
17CSParallelepipedModel, CappedCylinderModel, CoreShellCylinderModel,
18CoreShellEllipsoidModel, CoreShellModel, CorrLengthModel, CylinderModel,
19DABModel, DebyeModel, EllipsoidModel, EllipticalCylinderModel, FCCrystalModel,
20FlexCylEllipXModel, FlexibleCylinderModel, FractalCoreShellModel, FractalModel,
21FuzzySphereModel, GaussLorentzGelModel, GuinierModel, GuinierPorodModel,
22HardsphereStructure, HayterMSAStructure, HollowCylinderModel, LamellarFFHGModel,
23LamellarModel, LamellarPCrystalModel, LamellarPSHGModel, LamellarPSModel,
24LineModel, LorentzModel, MultiShellModel, ParallelepipedModel, PeakGaussModel,
25PeakLorentzModel, PearlNecklaceModel, Poly_GaussCoil, PolymerExclVolume,
26PorodModel, PowerLawAbsModel, SCCrystalModel, SphereModel, SquareWellStructure,
27StackedDisksModel, StickyHSStructure, TeubnerStreyModel, TriaxialEllipsoidModel,
28TwoLorentzianModel, TwoPowerLawModel, VesicleModel
29"""
30## This model is DIFFERENT from the Easy Custom Sum(p1 + p2)
31## by definition of the scale factor *****************************************
32#
33#     Custom model = scale_factor * P1 + (1 - scale_factor) * P2
34#
35## User can REPLACE model names below arrowed two lines (twice per line)
36from sas.models.CylinderModel import CylinderModel as P1          #<========
37from sas.models.PolymerExclVolume import PolymerExclVolume as P2  #<========
38
39#####DO NOT CHANGE ANYTHING BELOW THIS LINE
40#####---------------------------------------------------------------------------
41class Model(Model1DPlugin):
42    """
43    Use for A*p1(Q)+(1-A)*p2(Q);
44    Note: P(Q) refers to 'form factor' model.
45    """
46    name = "" 
47    def __init__(self):
48        Model1DPlugin.__init__(self, name=self.name)
49        """
50        :param p_model1: a form factor, P(Q)
51        :param p_model2: another form factor, P(Q)
52        """
53        p_model1 = P1()
54        p_model2 = P2()
55        ## Setting  model name model description
56        self.description = ""
57        self.fill_description(p_model1, p_model2)
58        # Set the name same as the file name
59        self.name = self.get_fname()     ##DO NOT CHANGE THIS LINE!!!
60        ## Define parameters
61        self.params = {}
62
63        ## Parameter details [units, min, max]
64        self.details = {}
65        ## Magnetic Panrameters
66        self.magnetic_params = []
67       
68        # non-fittable parameters
69        self.non_fittable = p_model1.non_fittable 
70        self.non_fittable += p_model2.non_fittable 
71           
72        ##models
73        self.p_model1= p_model1
74        self.p_model2= p_model2
75       
76       
77        ## dispersion
78        self._set_dispersion()
79        ## Define parameters
80        self._set_params()
81        ## New parameter:Scaling factor
82        self.params['scale_factor'] = 0.5
83       
84        ## Parameter details [units, min, max]
85        self._set_details()
86        self.details['scale_factor'] = ['',     None, None]
87
88       
89        #list of parameter that can be fitted
90        self._set_fixed_params() 
91        ## parameters with orientation
92        for item in self.p_model1.orientation_params:
93            new_item = "p1_" + item
94            if not new_item in self.orientation_params:
95                self.orientation_params.append(new_item)
96           
97        for item in self.p_model2.orientation_params:
98            new_item = "p2_" + item
99            if not new_item in self.orientation_params:
100                self.orientation_params.append(new_item)
101        ## magnetic params
102        for item in self.p_model1.magnetic_params:
103            new_item = "p1_" + item
104            if not new_item in self.magnetic_params:
105                self.magnetic_params.append(new_item)
106           
107        for item in self.p_model2.magnetic_params:
108            new_item = "p2_" + item
109            if not new_item in self.magnetic_params:
110                self.magnetic_params.append(new_item)
111        # set multiplicity 1: muti_func Not supported.
112        multiplicity1 = 1
113        multiplicity2 = 1
114        ## functional multiplicity of the model
115        self.multiplicity1 = multiplicity1 
116        self.multiplicity2 = multiplicity2   
117        self.multiplicity_info = []   
118       
119    def _clone(self, obj):
120        """
121            Internal utility function to copy the internal
122            data members to a fresh copy.
123        """
124        obj.params     = copy.deepcopy(self.params)
125        obj.description     = copy.deepcopy(self.description)
126        obj.details    = copy.deepcopy(self.details)
127        obj.dispersion = copy.deepcopy(self.dispersion)
128        obj.p_model1  = self.p_model1.clone()
129        obj.p_model2  = self.p_model2.clone()
130        #obj = copy.deepcopy(self)
131        return obj
132   
133    def _get_name(self, name1, name2):
134        """
135        Get combined name from two model names
136        """
137        name = "A*"
138        p1_name = self._get_upper_name(name1)
139        if not p1_name:
140            p1_name = name1
141        name += p1_name
142        name += "+(1-A)*"
143        p2_name = self._get_upper_name(name2)
144        if not p2_name:
145            p2_name = name2
146        name += p2_name
147        return name
148   
149    def _get_upper_name(self, name=None):
150        """
151        Get uppercase string from model name
152        """
153        if name == None:
154            return ""
155        upper_name = ""
156        str_name = str(name)
157        for index in range(len(str_name)):
158            if str_name[index].isupper():
159                upper_name += str_name[index]
160        return upper_name
161       
162    def _set_dispersion(self):
163        """
164           combined the two models dispersions
165           Polydispersion should not be applied to s_model
166        """
167        ##set dispersion only from p_model
168        for name , value in self.p_model1.dispersion.iteritems():
169            #if name.lower() not in self.p_model1.orientation_params:
170            new_name = "p1_" + name
171            self.dispersion[new_name]= value
172        for name , value in self.p_model2.dispersion.iteritems():
173            #if name.lower() not in self.p_model2.orientation_params:
174            new_name = "p2_" + name
175            self.dispersion[new_name]= value
176           
177    def function(self, x=0.0): 
178        """
179        """
180        return 0
181                               
182    def getProfile(self):
183        """
184        Get SLD profile of p_model if exists
185       
186        : return: (r, beta) where r is a list of radius of the transition points
187                beta is a list of the corresponding SLD values
188        : Note: This works only for func_shell# = 2 (exp function)
189                and is not supporting for p2
190        """
191        try:
192            x,y = self.p_model1.getProfile()
193        except:
194            x = None
195            y = None
196           
197        return x, y
198   
199    def _set_params(self):
200        """
201            Concatenate the parameters of the two models to create
202            this model parameters
203        """
204
205        for name , value in self.p_model1.params.iteritems():
206            # No 2D-supported
207            #if name not in self.p_model1.orientation_params:
208            new_name = "p1_" + name
209            self.params[new_name]= value
210           
211        for name , value in self.p_model2.params.iteritems():
212            # No 2D-supported
213            #if name not in self.p_model2.orientation_params:
214            new_name = "p2_" + name
215            self.params[new_name]= value
216               
217        # Set "scale" as initializing
218        self._set_scale_factor()
219     
220           
221    def _set_details(self):
222        """
223            Concatenate details of the two models to create
224            this model details
225        """
226        for name ,detail in self.p_model1.details.iteritems():
227            new_name = "p1_" + name
228            #if new_name not in self.orientation_params:
229            self.details[new_name]= detail
230           
231        for name ,detail in self.p_model2.details.iteritems():
232            new_name = "p2_" + name
233            #if new_name not in self.orientation_params:
234            self.details[new_name]= detail
235   
236    def _set_scale_factor(self):
237        """
238        Not implemented
239        """
240        pass
241       
242               
243    def setParam(self, name, value):
244        """
245        Set the value of a model parameter
246   
247        :param name: name of the parameter
248        :param value: value of the parameter
249        """
250        # set param to p1+p2 model
251        self._setParamHelper(name, value)
252       
253        ## setParam to p model
254        model_pre = name.split('_', 1)[0]
255        new_name = name.split('_', 1)[1]
256        if model_pre == "p1":
257            if new_name in self.p_model1.getParamList():
258                self.p_model1.setParam(new_name, value)
259        elif model_pre == "p2":
260             if new_name in self.p_model2.getParamList():
261                self.p_model2.setParam(new_name, value)
262        elif name.lower() == 'scale_factor':
263            self.params['scale_factor'] = value
264        else:
265            raise ValueError, "Model does not contain parameter %s" % name
266           
267    def getParam(self, name):
268        """
269        Set the value of a model parameter
270
271        :param name: name of the parameter
272       
273        """
274        # Look for dispersion parameters
275        toks = name.split('.')
276        if len(toks)==2:
277            for item in self.dispersion.keys():
278                # 2D not supported
279                if item.lower()==toks[0].lower():# and \
280                            #item.lower() not in self.orientation_params \
281                            #and toks[0].lower() not in self.orientation_params:
282                    for par in self.dispersion[item]:
283                        if par.lower() == toks[1].lower():
284                            return self.dispersion[item][par]
285        else:
286            # Look for standard parameter
287            for item in self.params.keys():
288                if item.lower()==name.lower():#and \
289                            #item.lower() not in self.orientation_params \
290                            #and toks[0].lower() not in self.orientation_params:
291                    return self.params[item]
292        return 
293        #raise ValueError, "Model does not contain parameter %s" % name
294       
295    def _setParamHelper(self, name, value):
296        """
297        Helper function to setparam
298        """
299        # Look for dispersion parameters
300        toks = name.split('.')
301        if len(toks)== 2:
302            for item in self.dispersion.keys():
303                if item.lower()== toks[0].lower():# and \
304                            #item.lower() not in self.orientation_params:
305                    for par in self.dispersion[item]:
306                        if par.lower() == toks[1].lower():#and \
307                                #item.lower() not in self.orientation_params:
308                            self.dispersion[item][par] = value
309                            return
310        else:
311            # Look for standard parameter
312            for item in self.params.keys():
313                if item.lower()== name.lower():#and \
314                            #item.lower() not in self.orientation_params:
315                    self.params[item] = value
316                    return
317           
318        raise ValueError, "Model does not contain parameter %s" % name
319             
320   
321    def _set_fixed_params(self):
322        """
323             fill the self.fixed list with the p_model fixed list
324        """
325        for item in self.p_model1.fixed:
326            new_item = "p1" + item
327            self.fixed.append(new_item)
328        for item in self.p_model2.fixed:
329            new_item = "p2" + item
330            self.fixed.append(new_item)
331
332        self.fixed.sort()
333               
334                   
335    def run(self, x = 0.0):
336        """
337        Evaluate the model
338       
339        :param x: input q-value (float or [float, float] as [r, theta])
340        :return: (scattering function value)
341        """
342        self._set_scale_factor()
343        return (self.params['scale_factor'] * self.p_model1.run(x) + \
344                (1 - self.params['scale_factor']) * self.p_model2.run(x))
345   
346    def runXY(self, x = 0.0):
347        """
348        Evaluate the model
349       
350        :param x: input q-value (float or [float, float] as [qx, qy])
351        :return: scattering function value
352        """ 
353        self._set_scale_factor()
354        return (self.params['scale_factor'] * self.p_model1.runXY(x) + \
355                (1 - self.params['scale_factor']) * self.p_model2.runXY(x))
356   
357    ## Now (May27,10) directly uses the model eval function
358    ## instead of the for-loop in Base Component.
359    def evalDistribution(self, x = []):
360        """
361        Evaluate the model in cartesian coordinates
362       
363        :param x: input q[], or [qx[], qy[]]
364        :return: scattering function P(q[])
365        """
366        self._set_scale_factor()
367        return (self.params['scale_factor'] * self.p_model1.evalDistribution(x) + \
368                (1 - self.params['scale_factor']) * self.p_model2.evalDistribution(x))
369
370    def set_dispersion(self, parameter, dispersion):
371        """
372        Set the dispersion object for a model parameter
373       
374        :param parameter: name of the parameter [string]
375        :dispersion: dispersion object of type DispersionModel
376        """
377        value= None
378        new_pre = parameter.split("_", 1)[0]
379        new_parameter = parameter.split("_", 1)[1]
380        try:
381            if new_pre == 'p1' and \
382                            new_parameter in self.p_model1.dispersion.keys():
383                value= self.p_model1.set_dispersion(new_parameter, dispersion)
384            if new_pre == 'p2' and \
385                             new_parameter in self.p_model2.dispersion.keys():
386                value= self.p_model2.set_dispersion(new_parameter, dispersion)
387            self._set_dispersion()
388            return value
389        except:
390            raise 
391
392    def fill_description(self, p_model1, p_model2):
393        """
394        Fill the description for P(Q)+P(Q)
395        """
396        description = ""
397        description +="This model gives the summation of (A*%s) and ((1-A)*%s).\n"% \
398                                        ( p_model1.name, p_model2.name )
399        self.description += description
400   
401    ## DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!!       
402    def get_fname(self):
403        """
404        Get the model name same as the file name
405        """
406        path = sys._getframe().f_code.co_filename
407        basename  = os.path.basename(path)
408        name, _ = os.path.splitext(basename)
409        return name
410           
411### FOR TEST               
412if __name__ == "__main__": 
413    m1= Model() 
414    out1 = m1.runXY(0.01)
415    m2= Model()
416    out2 = 0.5 * m2.p_model1.runXY(0.01) + 0.5 * m2.p_model2.runXY(0.01)
417    print "Testing at Q = 0.01:"
418    print out1, " = ", out2
419    if out1 == out2:
420        print "===> Simple Test: Passed!"
421    else:
422        print "===> Simple Test: Failed!"
Note: See TracBrowser for help on using the repository browser.