Changeset 2c4a190 in sasmodels
- Timestamp:
- Dec 13, 2018 9:08:26 AM (6 years ago)
- Branches:
- master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 8803a38
- Parents:
- c6084f1
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
example/multiscatfit.py
r49d1f8b8 r2c4a190 15 15 16 16 # Show the model without fitting 17 PYTHONPATH=..:../ explore:../../bumps:../../sasview/src python multiscatfit.py17 PYTHONPATH=..:../../bumps:../../sasview/src python multiscatfit.py 18 18 19 19 # Run the fit 20 PYTHONPATH=..:../ explore:../../bumps:../../sasview/src ../../bumps/run.py \20 PYTHONPATH=..:../../bumps:../../sasview/src ../../bumps/run.py \ 21 21 multiscatfit.py --store=/tmp/t1 22 22 … … 55 55 ) 56 56 57 # Tie the model to the data 58 M = Experiment(data=data, model=model) 59 60 # Stack mulitple scattering on top of the existing resolution function. 61 M.resolution = MultipleScattering(resolution=M.resolution, probability=0.) 62 57 63 # SET THE FITTING PARAMETERS 58 64 model.radius_polar.range(15, 3000) … … 65 71 model.scale.range(0, 0.1) 66 72 67 # Mulitple scattering probability parameter 68 # HACK: the probability is stuffed in as an extra parameter to the experiment. 69 probability = Parameter(name="probability", value=0.0) 70 probability.range(0.0, 0.9) 73 # The multiple scattering probability parameter is in the resolution function 74 # instead of the scattering function, so access it through M.resolution 75 M.scattering_probability.range(0.0, 0.9) 71 76 72 M = Experiment(data=data, model=model, extra_pars={'probability': probability}) 73 74 # Stack mulitple scattering on top of the existing resolution function. 75 # Because resolution functions in sasview don't have fitting parameters, 76 # we instead allow the multiple scattering calculator to take a function 77 # instead of a probability. This function returns the current value of 78 # the parameter. ** THIS IS TEMPORARY ** when multiple scattering is 79 # properly integrated into sasmodels and sasview, its fittable parameter 80 # will be treated like the model parameters. 81 M.resolution = MultipleScattering(resolution=M.resolution, 82 probability=lambda: probability.value, 83 ) 84 M._kernel_inputs = M.resolution.q_calc 77 # Let bumps know that we are fitting this experiment 85 78 problem = FitProblem(M) 86 79 -
sasmodels/bumps_model.py
r49d1f8b8 r2c4a190 35 35 # when bumps is not on the path. 36 36 from bumps.names import Parameter # type: ignore 37 from bumps.parameter import Reference # type: ignore 37 38 except ImportError: 38 39 pass … … 139 140 def __init__(self, data, model, cutoff=1e-5, name=None, extra_pars=None): 140 141 # type: (Data, Model, float) -> None 142 # Allow resolution function to define fittable parameters. We do this 143 # by creating reference parameters within the resolution object rather 144 # than modifying the object itself to use bumps parameters. We need 145 # to reset the parameters each time the object has changed. These 146 # additional parameters need to be returned from the fitting engine. 147 # To make them available to the user, they are added as top-level 148 # attributes to the experiment object. The only change to the 149 # resolution function is that it needs an optional 'fittable' attribute 150 # which maps the internal name to the user visible name for the 151 # for the parameter. 152 self._resolution = None 153 self._resolution_pars = {} 141 154 # remember inputs so we can inspect from outside 142 155 self.name = data.filename if name is None else name … … 145 158 self._interpret_data(data, model.sasmodel) 146 159 self._cache = {} 160 # CRUFT: no longer need extra parameters 161 # Multiple scattering probability is now retrieved directly from the 162 # multiple scattering resolution function. 147 163 self.extra_pars = extra_pars 148 164 … … 162 178 return len(self.Iq) 163 179 180 @property 181 def resolution(self): 182 return self._resolution 183 184 @resolution.setter 185 def resolution(self, value): 186 self._resolution = value 187 188 # Remove old resolution fitting parameters from experiment 189 for name in self._resolution_pars: 190 delattr(self, name) 191 192 # Create new resolution fitting parameters 193 res_pars = getattr(self._resolution, 'fittable', {}) 194 self._resolution_pars = { 195 name: Reference(self._resolution, refname, name=name) 196 for refname, name in res_pars.items() 197 } 198 199 # Add new resolution fitting parameters as experiment attributes 200 for name, ref in self._resolution_pars.items(): 201 setattr(self, name, ref) 202 164 203 def parameters(self): 165 204 # type: () -> Dict[str, Parameter] … … 168 207 """ 169 208 pars = self.model.parameters() 170 if self.extra_pars :209 if self.extra_pars is not None: 171 210 pars.update(self.extra_pars) 211 pars.update(self._resolution_pars) 172 212 return pars 173 213 -
sasmodels/direct_model.py
r7b9e4dd r2c4a190 242 242 else: 243 243 Iq, dIq = None, None 244 #self._theory = np.zeros_like(q)245 q_vectors = [res.q_calc]246 244 elif self.data_type == 'Iqxy': 247 245 #if not model.info.parameters.has_2d: … … 260 258 res = resolution2d.Pinhole2D(data=data, index=index, 261 259 nsigma=3.0, accuracy=accuracy) 262 #self._theory = np.zeros_like(self.Iq)263 q_vectors = res.q_calc264 260 elif self.data_type == 'Iq': 265 261 index = (data.x >= data.qmin) & (data.x <= data.qmax) … … 286 282 else: 287 283 res = resolution.Perfect1D(data.x[index]) 288 289 #self._theory = np.zeros_like(self.Iq)290 q_vectors = [res.q_calc]291 284 elif self.data_type == 'Iq-oriented': 292 285 index = (data.x >= data.qmin) & (data.x <= data.qmax) … … 304 297 qx_width=data.dxw[index], 305 298 qy_width=data.dxl[index]) 306 q_vectors = res.q_calc307 299 else: 308 300 raise ValueError("Unknown data type") # never gets here … … 310 302 # Remember function inputs so we can delay loading the function and 311 303 # so we can save/restore state 312 self._kernel_inputs = q_vectors313 304 self._kernel = None 314 305 self.Iq, self.dIq, self.index = Iq, dIq, index … … 347 338 # type: (ParameterSet, float) -> np.ndarray 348 339 if self._kernel is None: 349 self._kernel = self._model.make_kernel(self._kernel_inputs) 340 # TODO: change interfaces so that resolution returns kernel inputs 341 # Maybe have resolution always return a tuple, or maybe have 342 # make_kernel accept either an ndarray or a pair of ndarrays. 343 kernel_inputs = self.resolution.q_calc 344 if isinstance(kernel_inputs, np.ndarray): 345 kernel_inputs = (kernel_inputs,) 346 self._kernel = self._model.make_kernel(kernel_inputs) 350 347 351 348 # Need to pull background out of resolution for multiple scattering -
sasmodels/multiscat.py
rb3703f5 r2c4a190 342 342 343 343 *probability* is related to the expected number of scattering 344 events in the sample $\lambda$ as $p = 1 = e^{-\lambda}$. As a 345 hack to allow probability to be a fitted parameter, the "value" 346 can be a function that takes no parameters and returns the current 347 value of the probability. *coverage* determines how many scattering 348 steps to consider. The default is 0.99, which sets $n$ such that 349 $1 \ldots n$ covers 99% of the Poisson probability mass function. 344 events in the sample $\lambda$ as $p = 1 - e^{-\lambda}$. 345 *coverage* determines how many scattering steps to consider. The 346 default is 0.99, which sets $n$ such that $1 \ldots n$ covers 99% 347 of the Poisson probability mass function. 350 348 351 349 *is2d* is True then 2D scattering is used, otherwise it accepts … … 399 397 self.qmin = qmin 400 398 self.nq = nq 401 self.probability = probability399 self.probability = 0. if probability is None else probability 402 400 self.coverage = coverage 403 401 self.is2d = is2d … … 456 454 self.Iqxy = None # type: np.ndarray 457 455 456 # Label probability as a fittable parameter, and give its external name 457 # Note that the external name must be a valid python identifier, since 458 # is will be set as an experiment attribute. 459 self.fittable = {'probability': 'scattering_probability'} 460 458 461 def apply(self, theory): 459 462 if self.is2d: … … 463 466 Iq_calc = Iq_calc.reshape(self.nq, self.nq) 464 467 468 # CRUFT: don't need probability as a function anymore 465 469 probability = self.probability() if callable(self.probability) else self.probability 466 470 coverage = self.coverage
Note: See TracChangeset
for help on using the changeset viewer.