Changeset ac98886 in sasmodels
- Timestamp:
- Aug 14, 2016 11:15:15 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:
- 725ee36
- Parents:
- bde38b5
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/mixture.py
r7ae2b7f rac98886 11 11 *ProductModel(P, S)*. 12 12 """ 13 from __future__ import print_function 14 13 15 from copy import copy 14 16 import numpy as np # type: ignore … … 16 18 from .modelinfo import Parameter, ParameterTable, ModelInfo 17 19 from .kernel import KernelModel, Kernel 20 from .details import make_details 18 21 19 22 try: 20 23 from typing import List 21 from .details import CallDetails22 24 except ImportError: 23 25 pass … … 43 45 # to support vector parameters 44 46 prefix = chr(ord('A')+k) + '_' 45 combined_pars.append(Parameter(prefix+'scale')) 47 scale = Parameter(prefix+'scale', default=1.0, 48 description="model intensity for " + part.name) 49 combined_pars.append(scale) 46 50 for p in part.parameters.kernel_parameters: 47 51 p = copy(p) … … 51 55 p.length_control = prefix + p.length_control 52 56 combined_pars.append(p) 57 #print("pars",combined_pars) 53 58 parameters = ParameterTable(combined_pars) 59 parameters.max_pd = sum(part.parameters.max_pd for part in parts) 54 60 55 61 model_info = ModelInfo() … … 70 76 # Remember the component info blocks so we can build the model 71 77 model_info.composition = ('mixture', parts) 78 model_info.demo = {} 79 return model_info 72 80 73 81 … … 78 86 self.parts = parts 79 87 80 def __call__(self, q_vectors):88 def make_kernel(self, q_vectors): 81 89 # type: (List[np.ndarray]) -> MixtureKernel 82 90 # Note: may be sending the q_vectors to the n times even though they … … 104 112 self.info = model_info 105 113 self.kernels = kernels 106 107 def __call__(self, call_details, value, weight, cutoff): 114 self.dtype = self.kernels[0].dtype 115 116 def __call__(self, call_details, values, cutoff, magnetic): 108 117 # type: (CallDetails, np.ndarray, np.ndarry, float) -> np.ndarray 109 scale, background = value [0:2]118 scale, background = values[0:2] 110 119 total = 0.0 111 120 # remember the parts for plotting later 112 121 self.results = [] 113 for kernel, kernel_details in zip(self.kernels, call_details.parts): 114 part_result = kernel(kernel_details, value, weight, cutoff) 115 total += part_result 116 self.results.append(part_result) 122 offset = 2 # skip scale & background 123 parts = MixtureParts(self.info, self.kernels, call_details, values) 124 for kernel, kernel_details, kernel_values in parts: 125 #print("calling kernel", kernel.info.name) 126 result = kernel(kernel_details, kernel_values, cutoff, magnetic) 127 #print(kernel.info.name, result) 128 total += result 129 self.results.append(result) 117 130 118 131 return scale*total + background … … 123 136 k.release() 124 137 138 139 class MixtureParts(object): 140 def __init__(self, model_info, kernels, call_details, values): 141 self.model_info = model_info 142 self.parts = model_info.composition[1] 143 self.kernels = kernels 144 self.call_details = call_details 145 self.values = values 146 self.spin_index = model_info.parameters.npars + 2 147 #call_details.show(values) 148 149 def __iter__(self): 150 # type: () -> PartIterable 151 self.part_num = 0 152 self.par_index = 2 153 self.mag_index = self.spin_index + 3 154 return self 155 156 def next(self): 157 # type: () -> Tuple[List[Callable], CallDetails, np.ndarray] 158 if self.part_num >= len(self.parts): 159 raise StopIteration() 160 info = self.parts[self.part_num] 161 kernel = self.kernels[self.part_num] 162 call_details = self._part_details(info, self.par_index) 163 values = self._part_values(info, self.par_index, self.mag_index) 164 values = values.astype(kernel.dtype) 165 #call_details.show(values) 166 167 self.part_num += 1 168 self.par_index += info.parameters.npars + 1 169 self.mag_index += 3 * len(info.parameters.magnetism_index) 170 171 return kernel, call_details, values 172 173 def _part_details(self, info, par_index): 174 # type: (ModelInfo, int) -> CallDetails 175 full = self.call_details 176 # par_index is index into values array of the current parameter, 177 # which includes the initial scale and background parameters. 178 # We want the index into the weight length/offset for each parameter. 179 # Exclude the initial scale and background, so subtract two, but each 180 # component has its own scale factor which we need to skip when 181 # constructing the details for the kernel, so add one, giving a 182 # net subtract one. 183 index = slice(par_index - 1, par_index - 1 + info.parameters.npars) 184 length = full.length[index] 185 offset = full.offset[index] 186 # The complete weight vector is being sent to each part so that 187 # offsets don't need to be adjusted. 188 part = make_details(info, length, offset, full.num_weights) 189 return part 190 191 def _part_values(self, info, par_index, mag_index): 192 # type: (ModelInfo, int, int) -> np.ndarray 193 #print(info.name, par_index, self.values[par_index:par_index + info.parameters.npars + 1]) 194 scale = self.values[par_index] 195 pars = self.values[par_index + 1:par_index + info.parameters.npars + 1] 196 nmagnetic = len(info.parameters.magnetism_index) 197 if nmagnetic: 198 spin_state = self.values[self.spin_index:self.spin_index + 3] 199 mag_index = self.values[mag_index:mag_index + 3 * nmagnetic] 200 else: 201 spin_state = [] 202 mag_index = [] 203 nvalues = self.model_info.parameters.nvalues 204 nweights = self.call_details.num_weights 205 weights = self.values[nvalues:nvalues+2*nweights] 206 zero = self.values.dtype.type(0.) 207 values = [[scale, zero], pars, spin_state, mag_index, weights] 208 # Pad value array to a 32 value boundary 209 spacer = (32 - sum(len(v) for v in values)%32)%32 210 values.append([zero]*spacer) 211 values = np.hstack(values).astype(self.kernels[0].dtype) 212 return values
Note: See TracChangeset
for help on using the changeset viewer.