# A sample of an experimental model function for Sum(Pmodel1,Pmodel2)
import copy
from sas.models.pluginmodel import Model1DPlugin
import os
import sys
"""
## *****************************************************************************
Please select the 'Compile' from the menubar after the modification and saving.
Note that we recommend to save the file as a different file name.
Otherwise, it could be removed in the future on re-installation of the SasView.
## *****************************************************************************
"""
# Available model names for this sum model
"""
BCCrystalModel, BEPolyelectrolyte, BarBellModel, BinaryHSModel, BroadPeakModel,
CSParallelepipedModel, CappedCylinderModel, CoreShellCylinderModel,
CoreShellEllipsoidModel, CoreShellModel, CorrLengthModel, CylinderModel,
DABModel, DebyeModel, EllipsoidModel, EllipticalCylinderModel, FCCrystalModel,
FlexCylEllipXModel, FlexibleCylinderModel, FractalCoreShellModel, FractalModel,
FuzzySphereModel, GaussLorentzGelModel, GuinierModel, GuinierPorodModel,
HardsphereStructure, HayterMSAStructure, HollowCylinderModel, LamellarFFHGModel,
LamellarModel, LamellarPCrystalModel, LamellarPSHGModel, LamellarPSModel,
LineModel, LorentzModel, MultiShellModel, ParallelepipedModel, PeakGaussModel,
PeakLorentzModel, PearlNecklaceModel, Poly_GaussCoil, PolymerExclVolume,
PorodModel, PowerLawAbsModel, SCCrystalModel, SphereModel, SquareWellStructure,
StackedDisksModel, StickyHSStructure, TeubnerStreyModel, TriaxialEllipsoidModel,
TwoLorentzianModel, TwoPowerLawModel, VesicleModel
"""
## This is same as the Easy Custom Sum(p1 + p2)
#
# Custom model = scale_factor * (P1 + P2)
#
## User can REPLACE model names below two arrowed lines (two names per line)
from sas.models.CylinderModel import CylinderModel as P1 #<========
from sas.models.PolymerExclVolume import PolymerExclVolume as P2 #<========
# If you want to add your custom model, change the filename to your custom model
# FILE NAME without the extension(.py). And un-comment the line(ie., remove '#')
# from filename import Model as P2 #<========
#####DO NOT CHANGE ANYTHING BELOW THIS LINE
#####---------------------------------------------------------------------------
[docs]class Model(Model1DPlugin):
"""
Use for p1(Q)+p2(Q);
Note: P(Q) refers to 'form factor' model.
"""
name = ""
def __init__(self):
Model1DPlugin.__init__(self, name=self.name)
"""
:param p_model1: a form factor, P(Q)
:param p_model2: another form factor, P(Q)
"""
p_model1 = P1()
p_model2 = P2()
## Setting model name model description
self.description=""
self.description = p_model1.name+"\n"
self.description += p_model2.name+"\n"
self.fill_description(p_model1, p_model2)
# Set the name same as the file name
self.name = self.get_fname() ##DO NOT CHANGE THIS LINE!!!
## Define parameters
self.params = {}
## Parameter details [units, min, max]
self.details = {}
# non-fittable parameters
self.non_fittable = p_model1.non_fittable
self.non_fittable += p_model2.non_fittable
##models
self.p_model1= p_model1
self.p_model2= p_model2
## dispersion
self._set_dispersion()
## Define parameters
self._set_params()
## New parameter:Scaling factor
self.params['scale_factor'] = 1
## Parameter details [units, min, max]
self._set_details()
self.details['scale_factor'] = ['', None, None]
## Magnetic Panrameters
self.magnetic_params = []
#list of parameter that can be fitted
self._set_fixed_params()
## parameters with orientation
for item in self.p_model1.orientation_params:
new_item = "p1_" + item
if not new_item in self.orientation_params:
self.orientation_params.append(new_item)
for item in self.p_model2.orientation_params:
new_item = "p2_" + item
if not new_item in self.orientation_params:
self.orientation_params.append(new_item)
## magnetic params
for item in self.p_model1.magnetic_params:
new_item = "p1_" + item
if not new_item in self.magnetic_params:
self.magnetic_params.append(new_item)
for item in self.p_model2.magnetic_params:
new_item = "p2_" + item
if not new_item in self.magnetic_params:
self.magnetic_params.append(new_item)
# set multiplicity 1: muti_func Not supported.
multiplicity1 = 1
multiplicity2 = 1
## functional multiplicity of the model
self.multiplicity1 = multiplicity1
self.multiplicity2 = multiplicity2
self.multiplicity_info = []
def _clone(self, obj):
"""
Internal utility function to copy the internal
data members to a fresh copy.
"""
obj.params = copy.deepcopy(self.params)
obj.description = copy.deepcopy(self.description)
obj.details = copy.deepcopy(self.details)
obj.dispersion = copy.deepcopy(self.dispersion)
obj.p_model1 = self.p_model1.clone()
obj.p_model2 = self.p_model2.clone()
#obj = copy.deepcopy(self)
return obj
def _get_name(self, name1, name2):
"""
Get combined name from two model names
"""
p1_name = self._get_upper_name(name1)
if not p1_name:
p1_name = name1
name = p1_name
name += "+"
p2_name = self._get_upper_name(name2)
if not p2_name:
p2_name = name2
name += p2_name
return name
def _get_upper_name(self, name=None):
"""
Get uppercase string from model name
"""
if name == None:
return ""
upper_name = ""
str_name = str(name)
for index in range(len(str_name)):
if str_name[index].isupper():
upper_name += str_name[index]
return upper_name
def _set_dispersion(self):
"""
combined the two models dispersions
Polydispersion should not be applied to s_model
"""
##set dispersion only from p_model
for name , value in self.p_model1.dispersion.iteritems():
#if name.lower() not in self.p_model1.orientation_params:
new_name = "p1_" + name
self.dispersion[new_name]= value
for name , value in self.p_model2.dispersion.iteritems():
#if name.lower() not in self.p_model2.orientation_params:
new_name = "p2_" + name
self.dispersion[new_name]= value
[docs] def function(self, x=0.0):
"""
"""
return 0
[docs] def getProfile(self):
"""
Get SLD profile of p_model if exists
: return: (r, beta) where r is a list of radius of the transition points
beta is a list of the corresponding SLD values
: Note: This works only for func_shell# = 2 (exp function)
and is not supporting for p2
"""
try:
x,y = self.p_model1.getProfile()
except:
x = None
y = None
return x, y
def _set_params(self):
"""
Concatenate the parameters of the two models to create
this model parameters
"""
for name , value in self.p_model1.params.iteritems():
# No 2D-supported
#if name not in self.p_model1.orientation_params:
new_name = "p1_" + name
self.params[new_name]= value
for name , value in self.p_model2.params.iteritems():
# No 2D-supported
#if name not in self.p_model2.orientation_params:
new_name = "p2_" + name
self.params[new_name]= value
# Set "scale" as initializing
self._set_scale_factor()
def _set_details(self):
"""
Concatenate details of the two models to create
this model details
"""
for name ,detail in self.p_model1.details.iteritems():
new_name = "p1_" + name
#if new_name not in self.orientation_params:
self.details[new_name]= detail
for name ,detail in self.p_model2.details.iteritems():
new_name = "p2_" + name
#if new_name not in self.orientation_params:
self.details[new_name]= detail
def _set_scale_factor(self):
"""
Not implemented
"""
pass
[docs] def setParam(self, name, value):
"""
Set the value of a model parameter
:param name: name of the parameter
:param value: value of the parameter
"""
# set param to p1+p2 model
self._setParamHelper(name, value)
## setParam to p model
model_pre = name.split('_', 1)[0]
new_name = name.split('_', 1)[1]
if model_pre == "p1":
if new_name in self.p_model1.getParamList():
self.p_model1.setParam(new_name, value)
elif model_pre == "p2":
if new_name in self.p_model2.getParamList():
self.p_model2.setParam(new_name, value)
elif name.lower() == 'scale_factor':
self.params['scale_factor'] = value
else:
raise ValueError, "Model does not contain parameter %s" % name
[docs] def getParam(self, name):
"""
Set the value of a model parameter
:param name: name of the parameter
"""
# Look for dispersion parameters
toks = name.split('.')
if len(toks)==2:
for item in self.dispersion.keys():
# 2D not supported
if item.lower()==toks[0].lower():# and \
#item.lower() not in self.orientation_params \
#and toks[0].lower() not in self.orientation_params:
for par in self.dispersion[item]:
if par.lower() == toks[1].lower():
return self.dispersion[item][par]
else:
# Look for standard parameter
for item in self.params.keys():
if item.lower()==name.lower():#and \
#item.lower() not in self.orientation_params \
#and toks[0].lower() not in self.orientation_params:
return self.params[item]
return
#raise ValueError, "Model does not contain parameter %s" % name
def _setParamHelper(self, name, value):
"""
Helper function to setparam
"""
# Look for dispersion parameters
toks = name.split('.')
if len(toks)== 2:
for item in self.dispersion.keys():
if item.lower()== toks[0].lower():# and \
#item.lower() not in self.orientation_params:
for par in self.dispersion[item]:
if par.lower() == toks[1].lower():#and \
#item.lower() not in self.orientation_params:
self.dispersion[item][par] = value
return
else:
# Look for standard parameter
for item in self.params.keys():
if item.lower()== name.lower():#and \
#item.lower() not in self.orientation_params:
self.params[item] = value
return
raise ValueError, "Model does not contain parameter %s" % name
def _set_fixed_params(self):
"""
fill the self.fixed list with the p_model fixed list
"""
for item in self.p_model1.fixed:
new_item = "p1" + item
self.fixed.append(new_item)
for item in self.p_model2.fixed:
new_item = "p2" + item
self.fixed.append(new_item)
self.fixed.sort()
[docs] def run(self, x = 0.0):
"""
Evaluate the model
:param x: input q-value (float or [float, float] as [r, theta])
:return: (scattering function value)
"""
self._set_scale_factor()
return self.params['scale_factor'] * \
(self.p_model1.run(x) + self.p_model2.run(x))
[docs] def runXY(self, x = 0.0):
"""
Evaluate the model
:param x: input q-value (float or [float, float] as [qx, qy])
:return: scattering function value
"""
self._set_scale_factor()
return self.params['scale_factor'] * \
(self.p_model1.runXY(x) + self.p_model2.runXY(x))
## Now (May27,10) directly uses the model eval function
## instead of the for-loop in Base Component.
[docs] def evalDistribution(self, x = []):
"""
Evaluate the model in cartesian coordinates
:param x: input q[], or [qx[], qy[]]
:return: scattering function P(q[])
"""
self._set_scale_factor()
return self.params['scale_factor'] * \
(self.p_model1.evalDistribution(x) + \
self.p_model2.evalDistribution(x))
[docs] def set_dispersion(self, parameter, dispersion):
"""
Set the dispersion object for a model parameter
:param parameter: name of the parameter [string]
:dispersion: dispersion object of type DispersionModel
"""
value= None
new_pre = parameter.split("_", 1)[0]
new_parameter = parameter.split("_", 1)[1]
try:
if new_pre == 'p1' and \
new_parameter in self.p_model1.dispersion.keys():
value= self.p_model1.set_dispersion(new_parameter, dispersion)
if new_pre == 'p2' and \
new_parameter in self.p_model2.dispersion.keys():
value= self.p_model2.set_dispersion(new_parameter, dispersion)
self._set_dispersion()
return value
except:
raise
[docs] def fill_description(self, p_model1, p_model2):
"""
Fill the description for P(Q)+P(Q)
"""
description = ""
description +="This model gives the summation of %s and %s.\n"% \
( p_model1.name, p_model2.name )
self.description += description
## DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!!
[docs] def get_fname(self):
"""
Get the model name same as the file name
"""
path = sys._getframe().f_code.co_filename
basename = os.path.basename(path)
name, _ = os.path.splitext(basename)
return name
if __name__ == "__main__":
m1= Model()
#m1.setParam("p1_scale", 25)
#m1.setParam("p1_length", 1000)
#m1.setParam("p2_scale", 100)
#m1.setParam("p2_rg", 100)
out1 = m1.runXY(0.01)
m2= Model()
#m2.p_model1.setParam("scale", 25)
#m2.p_model1.setParam("length", 1000)
#m2.p_model2.setParam("scale", 100)
#m2.p_model2.setParam("rg", 100)
out2 = m2.p_model1.runXY(0.01) + m2.p_model2.runXY(0.01)
print "Testing at Q = 0.01:"
print out1, " = ", out2
if out1 == out2:
print "===> Simple Test: Passed!"
else:
print "===> Simple Test: Failed!"