Changeset 61a4bd4 in sasmodels
- Timestamp:
- Sep 4, 2017 12:09:27 PM (7 years ago)
- Branches:
- master, core_shell_microgels, costrafo411, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 481ff64
- Parents:
- 65314f7
- Location:
- sasmodels
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/core.py
rfb9a3b6 r61a4bd4 126 126 127 127 128 def load_model_info(model_name, force_mixture=False): 128 # def load_model_info(model_name, force_mixture=False): 129 # # type: (str) -> modelinfo.ModelInfo 130 # """ 131 # Load a model definition given the model name. 132 133 # *model_name* is the name of the model, or perhaps a model expression 134 # such as sphere*hardsphere or sphere+cylinder. 135 136 # *force_mixture* if true, MixtureModel will be used for combining models. 137 # Otherwise either MixtureModel will be used for addition and ProductModel 138 # will be used for multiplication 139 140 # This returns a handle to the module defining the model. This can be 141 # used with functions in generate to build the docs or extract model info. 142 # """ 143 # parts = model_name.split('+') 144 # if len(parts) > 1: 145 # # Always use MixtureModel for addition 146 # model_info_list = [load_model_info(p) for p in parts] 147 # return mixture.make_mixture_info(model_info_list) 148 149 # parts = model_name.split('*') 150 # if len(parts) > 1: 151 # if force_mixture: 152 # # Use MixtureModel for multiplication if forced 153 # model_info_list = [load_model_info(p) for p in parts] 154 # return mixture.make_mixture_info(model_info_list, operation='*') 155 # if len(parts) > 2: 156 # raise ValueError("use P*S to apply structure factor S to model P") 157 # # Use ProductModel 158 # P_info, Q_info = [load_model_info(p) for p in parts] 159 # return product.make_product_info(P_info, Q_info) 160 161 # kernel_module = generate.load_kernel_module(model_name) 162 # return modelinfo.make_model_info(kernel_module) 163 164 def load_model_info(model_string): 129 165 # type: (str) -> modelinfo.ModelInfo 130 166 """ … … 134 170 such as sphere*hardsphere or sphere+cylinder. 135 171 136 *force_mixture* if true, MixtureModel will be used for combining models.137 Otherwise either MixtureModel will be used for addition and ProductModel138 will be used for multiplication139 140 172 This returns a handle to the module defining the model. This can be 141 173 used with functions in generate to build the docs or extract model info. 142 174 """ 143 parts = model_name.split('+') 144 if len(parts) > 1: 145 # Always use MixtureModel for addition 146 model_info_list = [load_model_info(p) for p in parts] 147 return mixture.make_mixture_info(model_info_list) 148 149 parts = model_name.split('*') 150 if len(parts) > 1: 151 if force_mixture: 152 # Use MixtureModel for multiplication if forced 153 model_info_list = [load_model_info(p) for p in parts] 154 return mixture.make_mixture_info(model_info_list, operation='*') 155 if len(parts) > 2: 156 raise ValueError("use P*S to apply structure factor S to model P") 157 # Use ProductModel 158 P_info, Q_info = [load_model_info(p) for p in parts] 159 return product.make_product_info(P_info, Q_info) 160 161 kernel_module = generate.load_kernel_module(model_name) 162 return modelinfo.make_model_info(kernel_module) 175 # TODO: parse an expression like form@structure to create a P(Q)*S(Q) model 176 product_parts = [] 177 addition_parts = [] 178 179 addition_parts_names = model_string.split('+') 180 if len(addition_parts_names) >= 2: 181 addition_parts = [load_model_info(part) for part in addition_parts_names] 182 elif len(addition_parts_names) == 1: 183 product_parts_names = model_string.split('*') 184 if len(product_parts_names) >= 2: 185 product_parts = [load_model_info(part) for part in product_parts_names] 186 elif len(product_parts_names) == 1: 187 kernel_module = generate.load_kernel_module(product_parts_names[0]) 188 return modelinfo.make_model_info(kernel_module) 189 190 model = None 191 if len(product_parts) > 1: 192 model = mixture.make_mixture_info(product_parts, operation='*') 193 if len(addition_parts) > 1: 194 if model is not None: 195 addition_parts.append(model) 196 model = mixture.make_mixture_info(addition_parts, operation='+') 197 return model 163 198 164 199 -
sasmodels/mixture.py
rfb9a3b6 r61a4bd4 30 30 Create info block for mixture model. 31 31 """ 32 flatten = []33 for part in parts:34 if part.composition and part.composition[0] == 'mixture':35 flatten.extend(part.composition[1])36 else:37 flatten.append(part)38 parts = flatten39 40 32 # Build new parameter list 41 33 combined_pars = [] 42 34 demo = {} 35 36 model_num = 0 37 all_parts = copy(parts) 38 is_flat = False 39 while not is_flat: 40 is_flat = True 41 for part in all_parts: 42 if part.composition and part.composition[0] == 'mixture' and \ 43 len(part.composition[1]) > 1: 44 all_parts += part.composition[1] 45 all_parts.remove(part) 46 is_flat = False 47 48 # When creating a mixture model that is a sum of product models (ie (1*2)+(3*4)) 49 # the parameters for models 1 & 2 will be prefixed with A & B respectively, 50 # but so will the parameters for models 3 & 4. We need to rename models 3 & 4 51 # so that they are prefixed with C & D to avoid overlap of parameter names. 52 used_prefixes = [] 53 for part in parts: 54 i = 0 55 if part.composition and part.composition[0] == 'mixture': 56 npars_list = [info.parameters.npars for info in part.composition[1]] 57 for npars in npars_list: 58 # List of params of one of the constituent models of part 59 submodel_pars = part.parameters.kernel_parameters[i:i+npars] 60 # Prefix of the constituent model 61 prefix = submodel_pars[0].name[0] 62 if prefix not in used_prefixes: # Haven't seen this prefix so far 63 used_prefixes.append(prefix) 64 i += npars 65 continue 66 while prefix in used_prefixes: 67 # This prefix has been already used, so change it to the 68 # next letter that hasn't been used 69 prefix = chr(ord(prefix) + 1) 70 used_prefixes.append(prefix) 71 prefix += "_" 72 # Update the parameters of this constituent model to use the 73 # new prefix 74 for par in submodel_pars: 75 par.id = prefix + par.id[2:] 76 par.name = prefix + par.name[2:] 77 if par.length_control is not None: 78 par.length_control = prefix + par.length_control[2:] 79 i += npars 80 81 model_num = len(all_parts) - len(parts) 82 if model_num != 0: 83 model_num += 1 84 43 85 for k, part in enumerate(parts): 44 86 # Parameter prefix per model, A_, B_, ... 45 87 # Note that prefix must also be applied to id and length_control 46 88 # to support vector parameters 47 prefix = chr(ord('A')+k) + '_' 89 prefix = chr(ord('A')+k+model_num) + '_' 90 if part.composition and part.composition[0] == 'mixture': 91 # Parameter already has a prefix as it's part of a composition model 92 prefix = '' 93 model_num -= 1 94 48 95 if operation == '+': 49 96 # If model is a sum model, each constituent model gets its own scale parameter 50 scale = Parameter(prefix+'scale', default=1.0, 97 scale_prefix = prefix 98 if prefix == '' and part.operation == '*': 99 # `part` is a composition product model. Find the prefixes of 100 # it's parameters to form a new prefix for the scale, eg: 101 # a model with A*B*C will have ABC_scale 102 sub_prefixes = [] 103 for param in part.parameters.kernel_parameters: 104 # Prefix of constituent model 105 sub_prefix = param.id.split('_')[0] 106 if sub_prefix not in sub_prefixes: 107 sub_prefixes.append(sub_prefix) 108 # Concatenate sub_prefixes to form prefix for the scale 109 scale_prefix = ''.join(sub_prefixes) + '_' 110 scale = Parameter(scale_prefix + 'scale', default=1.0, 51 111 description="model intensity for " + part.name) 52 112 combined_pars.append(scale) … … 67 127 model_info.id = operation.join(part.id for part in parts) 68 128 model_info.operation = operation 69 model_info.name = operation.join(part.name for part in parts)129 model_info.name = '(' + operation.join(part.name for part in parts) + ')' 70 130 model_info.filename = None 71 131 model_info.title = 'Mixture model with ' + model_info.name
Note: See TracChangeset
for help on using the changeset viewer.