source: sasview/fittingview/src/sans/perspectives/fitting/plugin_models/sum_Ap1_1_Ap2.py @ 4ce74b44

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 4ce74b44 was 4ce74b44, checked in by Jae Cho <jhjcho@…>, 12 years ago

fixing pylint warnings

  • Property mode set to 100644
File size: 15.2 KB
Line 
1# A sample of an experimental model function for Sum(APmodel1,(1-A)Pmodel2)
2import copy
3from sans.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 SansView.
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 sans.models.CylinderModel import CylinderModel as P1          #<========
37from sans.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       
66        # non-fittable parameters
67        self.non_fittable = p_model1.non_fittable 
68        self.non_fittable += p_model2.non_fittable 
69           
70        ##models
71        self.p_model1= p_model1
72        self.p_model2= p_model2
73       
74       
75        ## dispersion
76        self._set_dispersion()
77        ## Define parameters
78        self._set_params()
79        ## New parameter:Scaling factor
80        self.params['scale_factor'] = 0.5
81       
82        ## Parameter details [units, min, max]
83        self._set_details()
84        self.details['scale_factor'] = ['',     None, None]
85
86       
87        #list of parameter that can be fitted
88        self._set_fixed_params() 
89        ## parameters with orientation
90        for item in self.p_model1.orientation_params:
91            new_item = "p1_" + item
92            if not new_item in self.orientation_params:
93                self.orientation_params.append(new_item)
94           
95        for item in self.p_model2.orientation_params:
96            new_item = "p2_" + item
97            if not new_item in self.orientation_params:
98                self.orientation_params.append(new_item)
99        # set multiplicity 1: muti_func Not supported.
100        multiplicity1 = 1
101        multiplicity2 = 1
102        ## functional multiplicity of the model
103        self.multiplicity1 = multiplicity1 
104        self.multiplicity2 = multiplicity2   
105        self.multiplicity_info = []   
106       
107    def _clone(self, obj):
108        """
109            Internal utility function to copy the internal
110            data members to a fresh copy.
111        """
112        obj.params     = copy.deepcopy(self.params)
113        obj.description     = copy.deepcopy(self.description)
114        obj.details    = copy.deepcopy(self.details)
115        obj.dispersion = copy.deepcopy(self.dispersion)
116        obj.p_model1  = self.p_model1.clone()
117        obj.p_model2  = self.p_model2.clone()
118        #obj = copy.deepcopy(self)
119        return obj
120   
121    def _get_name(self, name1, name2):
122        """
123        Get combined name from two model names
124        """
125        name = "A*"
126        p1_name = self._get_upper_name(name1)
127        if not p1_name:
128            p1_name = name1
129        name += p1_name
130        name += "+(1-A)*"
131        p2_name = self._get_upper_name(name2)
132        if not p2_name:
133            p2_name = name2
134        name += p2_name
135        return name
136   
137    def _get_upper_name(self, name=None):
138        """
139        Get uppercase string from model name
140        """
141        if name == None:
142            return ""
143        upper_name = ""
144        str_name = str(name)
145        for index in range(len(str_name)):
146            if str_name[index].isupper():
147                upper_name += str_name[index]
148        return upper_name
149       
150    def _set_dispersion(self):
151        """
152           combined the two models dispersions
153           Polydispersion should not be applied to s_model
154        """
155        ##set dispersion only from p_model
156        for name , value in self.p_model1.dispersion.iteritems():
157            #if name.lower() not in self.p_model1.orientation_params:
158            new_name = "p1_" + name
159            self.dispersion[new_name]= value
160        for name , value in self.p_model2.dispersion.iteritems():
161            #if name.lower() not in self.p_model2.orientation_params:
162            new_name = "p2_" + name
163            self.dispersion[new_name]= value
164           
165    def function(self, x=0.0): 
166        """
167        """
168        return 0
169                               
170    def getProfile(self):
171        """
172        Get SLD profile of p_model if exists
173       
174        : return: (r, beta) where r is a list of radius of the transition points
175                beta is a list of the corresponding SLD values
176        : Note: This works only for func_shell# = 2 (exp function)
177                and is not supporting for p2
178        """
179        try:
180            x,y = self.p_model1.getProfile()
181        except:
182            x = None
183            y = None
184           
185        return x, y
186   
187    def _set_params(self):
188        """
189            Concatenate the parameters of the two models to create
190            this model parameters
191        """
192
193        for name , value in self.p_model1.params.iteritems():
194            # No 2D-supported
195            #if name not in self.p_model1.orientation_params:
196            new_name = "p1_" + name
197            self.params[new_name]= value
198           
199        for name , value in self.p_model2.params.iteritems():
200            # No 2D-supported
201            #if name not in self.p_model2.orientation_params:
202            new_name = "p2_" + name
203            self.params[new_name]= value
204               
205        # Set "scale" as initializing
206        self._set_scale_factor()
207     
208           
209    def _set_details(self):
210        """
211            Concatenate details of the two models to create
212            this model details
213        """
214        for name ,detail in self.p_model1.details.iteritems():
215            new_name = "p1_" + name
216            #if new_name not in self.orientation_params:
217            self.details[new_name]= detail
218           
219        for name ,detail in self.p_model2.details.iteritems():
220            new_name = "p2_" + name
221            #if new_name not in self.orientation_params:
222            self.details[new_name]= detail
223   
224    def _set_scale_factor(self):
225        """
226        Not implemented
227        """
228        pass
229       
230               
231    def setParam(self, name, value):
232        """
233        Set the value of a model parameter
234   
235        :param name: name of the parameter
236        :param value: value of the parameter
237        """
238        # set param to p1+p2 model
239        self._setParamHelper(name, value)
240       
241        ## setParam to p model
242        model_pre = name.split('_', 1)[0]
243        new_name = name.split('_', 1)[1]
244        if model_pre == "p1":
245            if new_name in self.p_model1.getParamList():
246                self.p_model1.setParam(new_name, value)
247        elif model_pre == "p2":
248             if new_name in self.p_model2.getParamList():
249                self.p_model2.setParam(new_name, value)
250        elif name.lower() == 'scale_factor':
251            self.params['scale_factor'] = value
252        else:
253            raise ValueError, "Model does not contain parameter %s" % name
254           
255    def getParam(self, name):
256        """
257        Set the value of a model parameter
258
259        :param name: name of the parameter
260       
261        """
262        # Look for dispersion parameters
263        toks = name.split('.')
264        if len(toks)==2:
265            for item in self.dispersion.keys():
266                # 2D not supported
267                if item.lower()==toks[0].lower():# and \
268                            #item.lower() not in self.orientation_params \
269                            #and toks[0].lower() not in self.orientation_params:
270                    for par in self.dispersion[item]:
271                        if par.lower() == toks[1].lower():
272                            return self.dispersion[item][par]
273        else:
274            # Look for standard parameter
275            for item in self.params.keys():
276                if item.lower()==name.lower():#and \
277                            #item.lower() not in self.orientation_params \
278                            #and toks[0].lower() not in self.orientation_params:
279                    return self.params[item]
280        return 
281        #raise ValueError, "Model does not contain parameter %s" % name
282       
283    def _setParamHelper(self, name, value):
284        """
285        Helper function to setparam
286        """
287        # Look for dispersion parameters
288        toks = name.split('.')
289        if len(toks)== 2:
290            for item in self.dispersion.keys():
291                if item.lower()== toks[0].lower():# and \
292                            #item.lower() not in self.orientation_params:
293                    for par in self.dispersion[item]:
294                        if par.lower() == toks[1].lower():#and \
295                                #item.lower() not in self.orientation_params:
296                            self.dispersion[item][par] = value
297                            return
298        else:
299            # Look for standard parameter
300            for item in self.params.keys():
301                if item.lower()== name.lower():#and \
302                            #item.lower() not in self.orientation_params:
303                    self.params[item] = value
304                    return
305           
306        raise ValueError, "Model does not contain parameter %s" % name
307             
308   
309    def _set_fixed_params(self):
310        """
311             fill the self.fixed list with the p_model fixed list
312        """
313        for item in self.p_model1.fixed:
314            new_item = "p1" + item
315            self.fixed.append(new_item)
316        for item in self.p_model2.fixed:
317            new_item = "p2" + item
318            self.fixed.append(new_item)
319
320        self.fixed.sort()
321               
322                   
323    def run(self, x = 0.0):
324        """
325        Evaluate the model
326       
327        :param x: input q-value (float or [float, float] as [r, theta])
328        :return: (scattering function value)
329        """
330        self._set_scale_factor()
331        return (self.params['scale_factor'] * self.p_model1.run(x) + \
332                (1 - self.params['scale_factor']) * self.p_model2.run(x))
333   
334    def runXY(self, x = 0.0):
335        """
336        Evaluate the model
337       
338        :param x: input q-value (float or [float, float] as [qx, qy])
339        :return: scattering function value
340        """ 
341        self._set_scale_factor()
342        return (self.params['scale_factor'] * self.p_model1.runXY(x) + \
343                (1 - self.params['scale_factor']) * self.p_model2.runXY(x))
344   
345    ## Now (May27,10) directly uses the model eval function
346    ## instead of the for-loop in Base Component.
347    def evalDistribution(self, x = []):
348        """
349        Evaluate the model in cartesian coordinates
350       
351        :param x: input q[], or [qx[], qy[]]
352        :return: scattering function P(q[])
353        """
354        self._set_scale_factor()
355        return (self.params['scale_factor'] * self.p_model1.evalDistribution(x) + \
356                (1 - self.params['scale_factor']) * self.p_model2.evalDistribution(x))
357
358    def set_dispersion(self, parameter, dispersion):
359        """
360        Set the dispersion object for a model parameter
361       
362        :param parameter: name of the parameter [string]
363        :dispersion: dispersion object of type DispersionModel
364        """
365        value= None
366        new_pre = parameter.split("_", 1)[0]
367        new_parameter = parameter.split("_", 1)[1]
368        try:
369            if new_pre == 'p1' and \
370                            new_parameter in self.p_model1.dispersion.keys():
371                value= self.p_model1.set_dispersion(new_parameter, dispersion)
372            if new_pre == 'p2' and \
373                             new_parameter in self.p_model2.dispersion.keys():
374                value= self.p_model2.set_dispersion(new_parameter, dispersion)
375            self._set_dispersion()
376            return value
377        except:
378            raise 
379
380    def fill_description(self, p_model1, p_model2):
381        """
382        Fill the description for P(Q)+P(Q)
383        """
384        description = ""
385        description +="This model gives the summation of (A*%s) and ((1-A)*%s).\n"% \
386                                        ( p_model1.name, p_model2.name )
387        self.description += description
388   
389    ## DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!!       
390    def get_fname(self):
391        """
392        Get the model name same as the file name
393        """
394        path = sys._getframe().f_code.co_filename
395        basename  = os.path.basename(path)
396        name, _ = os.path.splitext(basename)
397        return name
398           
399### FOR TEST               
400if __name__ == "__main__": 
401    m1= Model() 
402    out1 = m1.runXY(0.01)
403    m2= Model()
404    out2 = 0.5 * m2.p_model1.runXY(0.01) + 0.5 * m2.p_model2.runXY(0.01)
405    print "Testing at Q = 0.01:"
406    print out1, " = ", out2
407    if out1 == out2:
408        print "===> Simple Test: Passed!"
409    else:
410        print "===> Simple Test: Failed!"
Note: See TracBrowser for help on using the repository browser.