Changeset fa5fd8d in sasmodels
- Timestamp:
- Apr 12, 2016 6:02:41 PM (9 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:
- 04045f4
- Parents:
- 7ae2b7f
- Location:
- sasmodels
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/core.py
r7ae2b7f rfa5fd8d 102 102 103 103 def build_model(model_info, dtype=None, platform="ocl"): 104 # type: (modelinfo.ModelInfo, DType, str) -> KernelModel104 # type: (modelinfo.ModelInfo, np.dtype, str) -> KernelModel 105 105 """ 106 106 Prepare the model for the default execution platform. … … 134 134 raise ValueError('unknown mixture type %s'%composition_type) 135 135 136 # If it is a python model, return it immediately 137 if callable(model_info.Iq): 138 return kernelpy.PyModel(model_info) 139 136 140 ## for debugging: 137 141 ## 1. uncomment open().write so that the source will be saved next time … … 144 148 source = generate.make_source(model_info) 145 149 if dtype is None: 146 dtype = 'single' if model_info.single else 'double' 147 if callable(model_info.Iq): 148 return kernelpy.PyModel(model_info) 150 dtype = generate.F32 if model_info.single else generate.F64 149 151 if (platform == "dll" 150 152 or not HAVE_OPENCL -
sasmodels/models/onion.py
r2afc26d rfa5fd8d 299 299 ["sld_solvent", "1e-6/Ang^2", 6.4, [-inf, inf], "", 300 300 "Solvent scattering length density"], 301 ["n ", "", 1, [0, 10], "volume",301 ["n_shells", "", 1, [0, 10], "volume", 302 302 "number of shells"], 303 ["sld_in[n ]", "1e-6/Ang^2", 1.7, [-inf, inf], "",303 ["sld_in[n_shells]", "1e-6/Ang^2", 1.7, [-inf, inf], "", 304 304 "scattering length density at the inner radius of shell k"], 305 ["sld_out[n ]", "1e-6/Ang^2", 2.0, [-inf, inf], "",305 ["sld_out[n_shells]", "1e-6/Ang^2", 2.0, [-inf, inf], "", 306 306 "scattering length density at the outer radius of shell k"], 307 ["thickness[n ]", "Ang", 40., [0, inf], "volume",307 ["thickness[n_shells]", "Ang", 40., [0, inf], "volume", 308 308 "Thickness of shell k"], 309 ["A[n ]", "", 1.0, [-inf, inf], "",309 ["A[n_shells]", "", 1.0, [-inf, inf], "", 310 310 "Decay rate of shell k"], 311 311 ] … … 317 317 318 318 profile_axes = ['Radius (A)', 'SLD (1e-6/A^2)'] 319 def profile(core_sld, core_radius, solvent_sld, n, in_sld, out_sld, thickness, A): 319 def profile(core_sld, core_radius, solvent_sld, n_shells, 320 in_sld, out_sld, thickness, A): 320 321 """ 321 SLD profile322 Returns shape profile with x=radius, y=SLD. 322 323 """ 323 324 324 total_radius = 1.25*(sum(thickness[:n ]) + core_radius + 1)325 total_radius = 1.25*(sum(thickness[:n_shells]) + core_radius + 1) 325 326 dr = total_radius/400 # 400 points for a smooth plot 326 327 … … 335 336 336 337 # add in the shells 337 for k in range(n ):338 for k in range(n_shells): 338 339 # Left side of each shells 339 340 r0 = r[-1] … … 362 363 beta.append(solvent_sld) 363 364 364 return np.asarray(r), np.asarray(beta) 365 return np.asarray(r), np.asarray(beta)*1e-6 365 366 366 367 def ER(core_radius, n, thickness): -
sasmodels/sasview_model.py
r7ae2b7f rfa5fd8d 30 30 from . import modelinfo 31 31 32 try: 33 from typing import Dict, Mapping, Any, Sequence, Tuple, NamedTuple, List, Optional 34 from .modelinfo import ModelInfo, Parameter 35 from .kernel import KernelModel 36 MultiplicityInfoType = NamedTuple( 37 'MuliplicityInfo', 38 [("number", int), ("control", str), ("choices", List[str]), 39 ("x_axis_label", str)]) 40 except ImportError: 41 pass 42 43 # TODO: separate x_axis_label from multiplicity info 44 # The x-axis label belongs with the profile generating function 45 MultiplicityInfo = collections.namedtuple( 46 'MultiplicityInfo', 47 ["number", "control", "choices", "x_axis_label"], 48 ) 49 50 # TODO: figure out how to say that the return type is a subclass 32 51 def load_standard_models(): 52 # type: () -> List[type] 33 53 """ 34 54 Load and return the list of predefined models. … … 47 67 48 68 def load_custom_model(path): 69 # type: (str) -> type 49 70 """ 50 71 Load a custom model given the model path. … … 56 77 57 78 def _make_standard_model(name): 79 # type: (str) -> type 58 80 """ 59 81 Load the sasview model defined by *name*. … … 64 86 """ 65 87 kernel_module = generate.load_kernel_module(name) 66 #model_info = modelinfo.make_model_info(kernel_module) 67 model_info = modelinfo.make_model_info("hello") 88 model_info = modelinfo.make_model_info(kernel_module) 68 89 return _make_model_from_info(model_info) 69 90 70 91 71 92 def _make_model_from_info(model_info): 93 # type: (ModelInfo) -> type 72 94 """ 73 95 Convert *model_info* into a SasView model wrapper. 74 96 """ 75 def __init__(self, multfactor=1): 76 SasviewModel.__init__(self) 77 attrs = dict(__init__=__init__, _model_info=model_info) 97 def __init__(self, multiplicity=None): 98 SasviewModel.__init__(self, multiplicity=multiplicity) 99 attrs = _generate_model_attributes(model_info) 100 attrs['__init__'] = __init__ 78 101 ConstructedModel = type(model_info.name, (SasviewModel,), attrs) 79 102 return ConstructedModel 80 103 104 def _generate_model_attributes(model_info): 105 # type: (ModelInfo) -> Dict[str, Any] 106 """ 107 Generate the class attributes for the model. 108 109 This should include all the information necessary to query the model 110 details so that you do not need to instantiate a model to query it. 111 112 All the attributes should be immutable to avoid accidents. 113 """ 114 attrs = {} # type: Dict[str, Any] 115 attrs['_model_info'] = model_info 116 attrs['name'] = model_info.name 117 attrs['description'] = model_info.description 118 attrs['category'] = None 119 120 # TODO: allow model to override axis labels input/output name/unit 121 122 parameters = model_info.parameters 123 124 #self.is_multifunc = False 125 non_fittable = [] # type: List[str] 126 for p in parameters.kernel_parameters: 127 if p.is_control: 128 non_fittable.append(p.name) 129 profile_axes = model_info.profile_axes 130 multiplicity_info = MultiplicityInfo( 131 p.limits[1], p.name, p.choices, profile_axes[0] 132 ) 133 break 134 else: 135 multiplicity_info = MultiplicityInfo(0, "", [], "") 136 137 attrs['is_structure_factor'] = model_info.structure_factor 138 attrs['is_form_factor'] = model_info.ER is not None 139 attrs['is_multiplicity_model'] = multiplicity_info[0] > 1 140 attrs['multiplicity_info'] = multiplicity_info 141 142 143 orientation_params = [] 144 magnetic_params = [] 145 fixed = [] 146 for p in parameters.user_parameters(): 147 if p.type == 'orientation': 148 orientation_params.append(p.name) 149 orientation_params.append(p.name+".width") 150 fixed.append(p.name+".width") 151 if p.type == 'magnetic': 152 orientation_params.append(p.name) 153 magnetic_params.append(p.name) 154 fixed.append(p.name+".width") 155 attrs['orientation_params'] = tuple(orientation_params) 156 attrs['magnetic_params'] = tuple(magnetic_params) 157 attrs['fixed'] = tuple(fixed) 158 159 attrs['non_fittable'] = tuple(non_fittable) 160 161 return attrs 81 162 82 163 class SasviewModel(object): … … 84 165 Sasview wrapper for opencl/ctypes model. 85 166 """ 86 _model_info = None # type: modelinfo.ModelInfo 87 def __init__(self): 167 # Model parameters for the specific model are set in the class constructor 168 # via the _generate_model_attributes function, which subclasses 169 # SasviewModel. They are included here for typing and documentation 170 # purposes. 171 _model = None # type: KernelModel 172 _model_info = None # type: ModelInfo 173 #: load/save name for the model 174 id = None # type: str 175 #: display name for the model 176 name = None # type: str 177 #: short model description 178 description = None # type: str 179 #: default model category 180 category = None # type: str 181 182 #: names of the orientation parameters in the order they appear 183 orientation_params = None # type: Sequence[str] 184 #: names of the magnetic parameters in the order they appear 185 magnetic_params = None # type: Sequence[str] 186 #: names of the fittable parameters 187 fixed = None # type: Sequence[str] 188 # TODO: the attribute fixed is ill-named 189 190 # Axis labels 191 input_name = "Q" 192 input_unit = "A^{-1}" 193 output_name = "Intensity" 194 output_unit = "cm^{-1}" 195 196 #: default cutoff for polydispersity 197 cutoff = 1e-5 198 199 # Note: Use non-mutable values for class attributes to avoid errors 200 #: parameters that are not fitted 201 non_fittable = () # type: Sequence[str] 202 203 #: True if model should appear as a structure factor 204 is_structure_factor = False 205 #: True if model should appear as a form factor 206 is_form_factor = False 207 #: True if model has multiplicity 208 is_multiplicity_model = False 209 #: Mulitplicity information 210 multiplicity_info = None # type: MultiplicityInfoType 211 212 # Per-instance variables 213 #: parameter {name: value} mapping 214 params = None # type: Dict[str, float] 215 #: values for dispersion width, npts, nsigmas and type 216 dispersion = None # type: Dict[str, Any] 217 #: units and limits for each parameter 218 details = None # type: Mapping[str, Tuple(str, float, float)] 219 #: multiplicity used, or None if no multiplicity controls 220 multiplicity = None # type: Optional[int] 221 222 def __init__(self, multiplicity=None): 223 # type: () -> None 224 print("initializing", self.name) 225 #raise Exception("first initialization") 88 226 self._model = None 89 model_info = self._model_info 90 parameters = model_info.parameters 91 92 self.name = model_info.name 93 self.description = model_info.description 94 self.category = None 95 #self.is_multifunc = False 96 for p in parameters.kernel_parameters: 97 if p.is_control: 98 profile_axes = model_info.profile_axes 99 self.multiplicity_info = [ 100 p.limits[1], p.name, p.choices, profile_axes[0] 101 ] 102 break 103 else: 104 self.multiplicity_info = [] 105 106 ## interpret the parameters 107 ## TODO: reorganize parameter handling 108 self.details = dict() 227 228 ## _persistency_dict is used by sas.perspectives.fitting.basepage 229 ## to store dispersity reference. 230 ## TODO: _persistency_dict to persistency_dict throughout sasview 231 self._persistency_dict = {} 232 233 # TODO: refactor multiplicity info 234 # TODO: separate profile view from multiplicity 235 # The button label, x and y axis labels and scale need to be under 236 # the control of the model, not the fit page. Maximum flexibility, 237 # the fit page would supply the canvas and the profile could plot 238 # how it wants, but this assumes matplotlib. Next level is that 239 # we provide some sort of data description including title, labels 240 # and lines to plot. 241 242 # TODO: refactor multiplicity to encompass variants 243 # TODO: dispersion should be a class 244 self.multiplicity = multiplicity 109 245 self.params = collections.OrderedDict() 110 self.dispersion = dict() 111 112 self.orientation_params = [] 113 self.magnetic_params = [] 114 self.fixed = [] 115 for p in parameters.user_parameters(): 246 self.dispersion = {} 247 self.details = {} 248 config = ({self.multiplicity_info.control: multiplicity} 249 if multiplicity is not None else {}) 250 for p in self._model_info.parameters.user_parameters(config): 251 # Don't include multiplicity in the list of parameters 252 if p.name == self.multiplicity_info.control: 253 continue 116 254 self.params[p.name] = p.default 117 self.details[p. name] = [p.units] + p.limits255 self.details[p.id] = [p.units, p.limits[0], p.limits[1]] 118 256 if p.polydisperse: 257 self.details[p.id+".width"] = [ 258 "", 0.0, 1.0 if p.relative_pd else np.inf 259 ] 119 260 self.dispersion[p.name] = { 120 261 'width': 0, … … 123 264 'type': 'gaussian', 124 265 } 125 if p.type == 'orientation':126 self.orientation_params.append(p.name)127 self.orientation_params.append(p.name+".width")128 self.fixed.append(p.name+".width")129 if p.type == 'magnetic':130 self.orientation_params.append(p.name)131 self.magnetic_params.append(p.name)132 self.fixed.append(p.name+".width")133 134 self.non_fittable = []135 136 ## independent parameter name and unit [string]137 self.input_name = "Q", #model_info.get("input_name", "Q")138 self.input_unit = "A^{-1}" #model_info.get("input_unit", "A^{-1}")139 self.output_name = "Intensity" #model_info.get("output_name", "Intensity")140 self.output_unit = "cm^{-1}" #model_info.get("output_unit", "cm^{-1}")141 142 ## _persistency_dict is used by sas.perspectives.fitting.basepage143 ## to store dispersity reference.144 ## TODO: _persistency_dict to persistency_dict throughout sasview145 self._persistency_dict = {}146 147 ## New fields introduced for opencl rewrite148 self.cutoff = 1e-5149 266 150 267 def __get_state__(self): 268 # type: () -> Dict[str, Any] 151 269 state = self.__dict__.copy() 152 270 state.pop('_model') … … 157 275 158 276 def __set_state__(self, state): 277 # type: (Dict[str, Any]) -> None 159 278 self.__dict__ = state 160 279 self._model = None 161 280 162 281 def __str__(self): 282 # type: () -> str 163 283 """ 164 284 :return: string representation … … 167 287 168 288 def is_fittable(self, par_name): 289 # type: (str) -> bool 169 290 """ 170 291 Check if a given parameter is fittable or not … … 177 298 178 299 179 # pylint: disable=no-self-use180 300 def getProfile(self): 301 # type: () -> (np.ndarray, np.ndarray) 181 302 """ 182 303 Get SLD profile … … 185 306 beta is a list of the corresponding SLD values 186 307 """ 187 return None, None 308 args = [] 309 for p in self._model_info.parameters.kernel_parameters: 310 if p.id == self.multiplicity_info.control: 311 args.append(self.multiplicity) 312 elif p.length == 1: 313 args.append(self.params.get(p.id, np.NaN)) 314 else: 315 args.append([self.params.get(p.id+str(k), np.NaN) 316 for k in range(1,p.length+1)]) 317 return self._model_info.profile(*args) 188 318 189 319 def setParam(self, name, value): 320 # type: (str, float) -> None 190 321 """ 191 322 Set the value of a model parameter … … 214 345 215 346 def getParam(self, name): 347 # type: (str) -> float 216 348 """ 217 349 Set the value of a model parameter … … 237 369 238 370 def getParamList(self): 371 # type: () - > Sequence[str] 239 372 """ 240 373 Return a list of all available parameters for the model … … 246 379 247 380 def getDispParamList(self): 381 # type: () - > Sequence[str] 248 382 """ 249 383 Return a list of polydispersity parameters for the model … … 258 392 259 393 def clone(self): 394 # type: () - > "SasviewModel" 260 395 """ Return a identical copy of self """ 261 396 return deepcopy(self) 262 397 263 398 def run(self, x=0.0): 399 # type: (Union[float, (float, float), List[float]]) -> float 264 400 """ 265 401 Evaluate the model … … 281 417 282 418 def runXY(self, x=0.0): 419 # type: (Union[float, (float, float), List[float]]) -> float 283 420 """ 284 421 Evaluate the model in cartesian coordinates … … 296 433 297 434 def evalDistribution(self, qdist): 435 # type: (Union[np.ndarray, Tuple[np.ndarray, np.ndarray], List[np.ndarray]) -> np.ndarray 298 436 r""" 299 437 Evaluate a distribution of q-values. … … 339 477 % type(qdist)) 340 478 341 def calculate_Iq(self, *args): 479 def calculate_Iq(self, qx, qy=None): 480 # type: (Sequence[float], Optional[Sequence[float]]) -> np.ndarray 342 481 """ 343 482 Calculate Iq for one set of q with the current parameters. … … 350 489 if self._model is None: 351 490 self._model = core.build_model(self._model_info) 352 q_vectors = [np.asarray(q) for q in args] 491 if qy is not None: 492 q_vectors = [np.asarray(qx), np.asarray(qy)] 493 else: 494 q_vectors = [np.asarray(qx)] 353 495 kernel = self._model.make_kernel(q_vectors) 354 496 pairs = [self._get_weights(p) … … 356 498 call_details, weight, value = details.build_details(kernel, pairs) 357 499 result = kernel(call_details, weight, value, cutoff=self.cutoff) 358 kernel.q_input.release()359 500 kernel.release() 360 501 return result 361 502 362 503 def calculate_ER(self): 504 # type: () -> float 363 505 """ 364 506 Calculate the effective radius for P(q)*S(q) … … 375 517 376 518 def calculate_VR(self): 519 # type: () -> float 377 520 """ 378 521 Calculate the volf ratio for P(q)*S(q) … … 388 531 389 532 def set_dispersion(self, parameter, dispersion): 533 # type: (str, weights.Dispersion) -> Dict[str, Any] 390 534 """ 391 535 Set the dispersion object for a model parameter … … 416 560 417 561 def _dispersion_mesh(self): 562 # type: () -> List[Tuple[np.ndarray, np.ndarray]] 418 563 """ 419 564 Create a mesh grid of dispersion parameters and weights. … … 429 574 430 575 def _get_weights(self, par): 576 # type: (Parameter) -> Tuple[np.ndarray, np.ndarray] 431 577 """ 432 578 Return dispersion weights for parameter 433 579 """ 434 if par.polydisperse: 580 if par.name not in self.params: 581 if par.name == self.multiplicity_info.control: 582 return [self.multiplicity], [] 583 else: 584 return [np.NaN], [] 585 elif par.polydisperse: 435 586 dis = self.dispersion[par.name] 436 587 value, weight = weights.get_weights( … … 442 593 443 594 def test_model(): 595 # type: () -> float 444 596 """ 445 597 Test that a sasview model (cylinder) can be run. … … 451 603 452 604 def test_model_list(): 605 # type: () -> None 453 606 """ 454 607 Make sure that all models build as sasview models. -
sasmodels/weights.py
r7ae2b7f rfa5fd8d 174 174 175 175 # dispersion name -> disperser lookup table. 176 models= dict((d.type, d) for d in (176 MODELS = dict((d.type, d) for d in ( 177 177 GaussianDispersion, RectangleDispersion, 178 178 ArrayDispersion, SchulzDispersion, LogNormalDispersion … … 201 201 Returns *(value, weight)*, where *value* and *weight* are vectors. 202 202 """ 203 cls = models[disperser]203 cls = MODELS[disperser] 204 204 obj = cls(n, width, nsigmas) 205 205 v, w = obj.get_weights(value, limits[0], limits[1], relative) … … 207 207 208 208 # Hack to allow sasview dispersion objects to interoperate with sasmodels 209 dispersers = dict((v.__name__, k) for k, v in models.items())209 dispersers = dict((v.__name__, k) for k, v in MODELS.items()) 210 210 dispersers['DispersionModel'] = RectangleDispersion.type 211 211
Note: See TracChangeset
for help on using the changeset viewer.