Changeset 6d6508e in sasmodels for sasmodels/product.py
- Timestamp:
- Apr 7, 2016 6:57:33 PM (8 years ago)
- Branches:
- master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- d2fc9a4
- Parents:
- 3707eee
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/product.py
rea05c87 r6d6508e 13 13 import numpy as np 14 14 15 from .core import call_ER_VR 15 from .details import dispersion_mesh 16 from .modelinfo import suffix_parameter, ParameterTable, Parameter, ModelInfo 16 17 17 SCALE=0 18 BACKGROUND=1 19 RADIUS_EFFECTIVE=2 20 VOLFRACTION=3 18 # TODO: make estimates available to constraints 19 #ESTIMATED_PARAMETERS = [ 20 # ["est_effect_radius", "A", 0.0, [0, np.inf], "", "Estimated effective radius"], 21 # ["est_volume_ratio", "", 1.0, [0, np.inf], "", "Estimated volume ratio"], 22 #] 21 23 22 24 # TODO: core_shell_sphere model has suppressed the volume ratio calculation … … 26 28 Create info block for product model. 27 29 """ 28 p_id, p_name, p_pars = p_info['id'], p_info['name'], p_info['parameters'] 29 s_id, s_name, s_pars = s_info['id'], s_info['name'], s_info['parameters'] 30 # We require models to start with scale and background 31 assert s_pars[SCALE].name == 'scale' 32 assert s_pars[BACKGROUND].name == 'background' 33 # We require structure factors to start with effect radius and volfraction 34 assert s_pars[RADIUS_EFFECTIVE].name == 'radius_effective' 35 assert s_pars[VOLFRACTION].name == 'volfraction' 36 # Combine the parameter sets. We are skipping the first three 37 # parameters of S since scale, background are defined in P and 38 # effect_radius is set from P.ER(). 39 pars = p_pars + s_pars[3:] 40 # check for duplicates; can't use assertion since they may never be checked 41 if len(set(p.name for p in pars)) != len(pars): 42 raise ValueError("Duplicate parameters in %s and %s"%(p_id)) 43 model_info = {} 44 model_info['id'] = '*'.join((p_id, s_id)) 45 model_info['name'] = ' X '.join((p_name, s_name)) 46 model_info['filename'] = None 47 model_info['title'] = 'Product of %s and structure factor %s'%(p_name, s_name) 48 model_info['description'] = model_info['title'] 49 model_info['docs'] = model_info['title'] 50 model_info['category'] = "custom" 51 model_info['parameters'] = pars 52 #model_info['single'] = p_info['single'] and s_info['single'] 53 model_info['structure_factor'] = False 54 model_info['variant_info'] = None 55 #model_info['tests'] = [] 56 #model_info['source'] = [] 30 p_id, p_name, p_partable = p_info.id, p_info.name, p_info.parameters 31 s_id, s_name, s_partable = s_info.id, s_info.name, s_info.parameters 32 p_set = set(p.id for p in p_partable) 33 s_set = set(p.id for p in s_partable) 34 35 if p_set & s_set: 36 # there is some overlap between the parameter names; tag the 37 # overlapping S parameters with name_S 38 s_pars = [(suffix_parameter(par, "_S") if par.id in p_set else par) 39 for par in s_partable.kernel_parameters] 40 pars = p_partable.kernel_parameters + s_pars 41 else: 42 pars= p_partable.kernel_parameters + s_partable.kernel_parameters 43 44 model_info = ModelInfo() 45 model_info.id = '*'.join((p_id, s_id)) 46 model_info.name = ' X '.join((p_name, s_name)) 47 model_info.filename = None 48 model_info.title = 'Product of %s and %s'%(p_name, s_name) 49 model_info.description = model_info.title 50 model_info.docs = model_info.title 51 model_info.category = "custom" 52 model_info.parameters = ParameterTable(pars) 53 #model_info.single = p_info.single and s_info.single 54 model_info.structure_factor = False 55 model_info.variant_info = None 56 #model_info.tests = [] 57 #model_info.source = [] 57 58 # Iq, Iqxy, form_volume, ER, VR and sesans 58 model_info ['composition']= ('product', [p_info, s_info])59 model_info.composition = ('product', [p_info, s_info]) 59 60 return model_info 60 61 … … 86 87 class ProductKernel(object): 87 88 def __init__(self, model_info, p_kernel, s_kernel): 88 dim = '2d' if p_kernel.q_input.is_2d else '1d'89 90 # Need to know if we want 2D and magnetic parameters when constructing91 # a parameter map.92 par_map = {}93 p_info = p_kernel.info['par_type']94 s_info = s_kernel.info['par_type']95 vol_pars = set(p_info['volume'])96 if dim == '2d':97 num_p_fixed = len(p_info['fixed-2d'])98 num_p_pd = len(p_info['pd-2d'])99 num_s_fixed = len(s_info['fixed-2d'])100 num_s_pd = len(s_info['pd-2d']) - 1 # exclude effect_radius101 # volume parameters are amongst the pd pars for P, not S102 vol_par_idx = [k for k,v in enumerate(p_info['pd-2d'])103 if v in vol_pars]104 else:105 num_p_fixed = len(p_info['fixed-1d'])106 num_p_pd = len(p_info['pd-1d'])107 num_s_fixed = len(s_info['fixed-1d'])108 num_s_pd = len(s_info['pd-1d']) - 1 # exclude effect_radius109 # volume parameters are amongst the pd pars for P, not S110 vol_par_idx = [k for k,v in enumerate(p_info['pd-1d'])111 if v in vol_pars]112 113 start = 0114 par_map['p_fixed'] = np.arange(start, start+num_p_fixed)115 # User doesn't set scale, background or effect_radius for S in P*S,116 # so borrow values from end of p_fixed. This makes volfraction the117 # first S parameter.118 start += num_p_fixed119 par_map['s_fixed'] = np.hstack(([start,start],120 np.arange(start, start+num_s_fixed-2)))121 par_map['volfraction'] = num_p_fixed122 start += num_s_fixed-2123 # vol pars offset from the start of pd pars124 par_map['vol_pars'] = [start+k for k in vol_par_idx]125 par_map['p_pd'] = np.arange(start, start+num_p_pd)126 start += num_p_pd-1127 par_map['s_pd'] = np.hstack((start,128 np.arange(start, start+num_s_pd-1)))129 130 self.fixed_pars = model_info['partype']['fixed-' + dim]131 self.pd_pars = model_info['partype']['pd-' + dim]132 89 self.info = model_info 133 90 self.p_kernel = p_kernel 134 91 self.s_kernel = s_kernel 135 self.par_map = par_map136 92 137 def __call__(self, fixed_pars, pd_pars, cutoff=1e-5): 138 pars = fixed_pars + pd_pars 139 scale = pars[SCALE] 140 background = pars[BACKGROUND] 141 s_volfraction = pars[self.par_map['volfraction']] 142 p_fixed = [pars[k] for k in self.par_map['p_fixed']] 143 s_fixed = [pars[k] for k in self.par_map['s_fixed']] 144 p_pd = [pars[k] for k in self.par_map['p_pd']] 145 s_pd = [pars[k] for k in self.par_map['s_pd']] 146 vol_pars = [pars[k] for k in self.par_map['vol_pars']] 147 93 def __call__(self, details, weights, values, cutoff): 148 94 effect_radius, vol_ratio = call_ER_VR(self.p_kernel.info, vol_pars) 149 95 … … 155 101 s_pd[0] = [effect_radius], [1.0] 156 102 157 p_res = self.p_kernel(p_ fixed, p_pd, cutoff)158 s_res = self.s_kernel(s_ fixed, s_pd, cutoff)103 p_res = self.p_kernel(p_details, p_weights, p_values, cutoff) 104 s_res = self.s_kernel(s_details, s_weights, s_values, cutoff) 159 105 #print s_fixed, s_pd, p_fixed, p_pd 160 106 … … 165 111 self.q_kernel.release() 166 112 113 def call_ER_VR(model_info, vol_pars): 114 """ 115 Return effect radius and volume ratio for the model. 116 """ 117 value, weight = dispersion_mesh(vol_pars) 118 119 individual_radii = model_info.ER(*value) if model_info.ER else 1.0 120 whole, part = model_info.VR(*value) if model_info.VR else (1.0, 1.0) 121 122 effect_radius = np.sum(weight*individual_radii) / np.sum(weight) 123 volume_ratio = np.sum(weight*part)/np.sum(weight*whole) 124 return effect_radius, volume_ratio
Note: See TracChangeset
for help on using the changeset viewer.