Changeset fa5fd8d in sasmodels


Ignore:
Timestamp:
Apr 12, 2016 6:02:41 PM (8 years ago)
Author:
Paul Kienzle <pkienzle@…>
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
Message:

support number of shells selection in sasview wrapper for onion model

Location:
sasmodels
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/core.py

    r7ae2b7f rfa5fd8d  
    102102 
    103103def build_model(model_info, dtype=None, platform="ocl"): 
    104     # type: (modelinfo.ModelInfo, DType, str) -> KernelModel 
     104    # type: (modelinfo.ModelInfo, np.dtype, str) -> KernelModel 
    105105    """ 
    106106    Prepare the model for the default execution platform. 
     
    134134            raise ValueError('unknown mixture type %s'%composition_type) 
    135135 
     136    # If it is a python model, return it immediately 
     137    if callable(model_info.Iq): 
     138        return kernelpy.PyModel(model_info) 
     139 
    136140    ## for debugging: 
    137141    ##  1. uncomment open().write so that the source will be saved next time 
     
    144148    source = generate.make_source(model_info) 
    145149    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 
    149151    if (platform == "dll" 
    150152            or not HAVE_OPENCL 
  • sasmodels/models/onion.py

    r2afc26d rfa5fd8d  
    299299              ["sld_solvent", "1e-6/Ang^2", 6.4, [-inf, inf], "", 
    300300               "Solvent scattering length density"], 
    301               ["n", "", 1, [0, 10], "volume", 
     301              ["n_shells", "", 1, [0, 10], "volume", 
    302302               "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], "", 
    304304               "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], "", 
    306306               "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", 
    308308               "Thickness of shell k"], 
    309               ["A[n]", "", 1.0, [-inf, inf], "", 
     309              ["A[n_shells]", "", 1.0, [-inf, inf], "", 
    310310               "Decay rate of shell k"], 
    311311              ] 
     
    317317 
    318318profile_axes = ['Radius (A)', 'SLD (1e-6/A^2)'] 
    319 def profile(core_sld, core_radius, solvent_sld, n, in_sld, out_sld, thickness, A): 
     319def profile(core_sld, core_radius, solvent_sld, n_shells, 
     320            in_sld, out_sld, thickness, A): 
    320321    """ 
    321     SLD profile 
     322    Returns shape profile with x=radius, y=SLD. 
    322323    """ 
    323324 
    324     total_radius = 1.25*(sum(thickness[:n]) + core_radius + 1) 
     325    total_radius = 1.25*(sum(thickness[:n_shells]) + core_radius + 1) 
    325326    dr = total_radius/400  # 400 points for a smooth plot 
    326327 
     
    335336 
    336337    # add in the shells 
    337     for k in range(n): 
     338    for k in range(n_shells): 
    338339        # Left side of each shells 
    339340        r0 = r[-1] 
     
    362363    beta.append(solvent_sld) 
    363364 
    364     return np.asarray(r), np.asarray(beta) 
     365    return np.asarray(r), np.asarray(beta)*1e-6 
    365366 
    366367def ER(core_radius, n, thickness): 
  • sasmodels/sasview_model.py

    r7ae2b7f rfa5fd8d  
    3030from . import modelinfo 
    3131 
     32try: 
     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)]) 
     40except ImportError: 
     41    pass 
     42 
     43# TODO: separate x_axis_label from multiplicity info 
     44# The x-axis label belongs with the profile generating function 
     45MultiplicityInfo = 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 
    3251def load_standard_models(): 
     52    # type: () -> List[type] 
    3353    """ 
    3454    Load and return the list of predefined models. 
     
    4767 
    4868def load_custom_model(path): 
     69    # type: (str) -> type 
    4970    """ 
    5071    Load a custom model given the model path. 
     
    5677 
    5778def _make_standard_model(name): 
     79    # type: (str) -> type 
    5880    """ 
    5981    Load the sasview model defined by *name*. 
     
    6486    """ 
    6587    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) 
    6889    return _make_model_from_info(model_info) 
    6990 
    7091 
    7192def _make_model_from_info(model_info): 
     93    # type: (ModelInfo) -> type 
    7294    """ 
    7395    Convert *model_info* into a SasView model wrapper. 
    7496    """ 
    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__ 
    78101    ConstructedModel = type(model_info.name, (SasviewModel,), attrs) 
    79102    return ConstructedModel 
    80103 
     104def _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 
    81162 
    82163class SasviewModel(object): 
     
    84165    Sasview wrapper for opencl/ctypes model. 
    85166    """ 
    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") 
    88226        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 
    109245        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 
    116254            self.params[p.name] = p.default 
    117             self.details[p.name] = [p.units] + p.limits 
     255            self.details[p.id] = [p.units, p.limits[0], p.limits[1]] 
    118256            if p.polydisperse: 
     257                self.details[p.id+".width"] = [ 
     258                    "", 0.0, 1.0 if p.relative_pd else np.inf 
     259                ] 
    119260                self.dispersion[p.name] = { 
    120261                    'width': 0, 
     
    123264                    'type': 'gaussian', 
    124265                } 
    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.basepage 
    143         ## to store dispersity reference. 
    144         ## TODO: _persistency_dict to persistency_dict throughout sasview 
    145         self._persistency_dict = {} 
    146  
    147         ## New fields introduced for opencl rewrite 
    148         self.cutoff = 1e-5 
    149266 
    150267    def __get_state__(self): 
     268        # type: () -> Dict[str, Any] 
    151269        state = self.__dict__.copy() 
    152270        state.pop('_model') 
     
    157275 
    158276    def __set_state__(self, state): 
     277        # type: (Dict[str, Any]) -> None 
    159278        self.__dict__ = state 
    160279        self._model = None 
    161280 
    162281    def __str__(self): 
     282        # type: () -> str 
    163283        """ 
    164284        :return: string representation 
     
    167287 
    168288    def is_fittable(self, par_name): 
     289        # type: (str) -> bool 
    169290        """ 
    170291        Check if a given parameter is fittable or not 
     
    177298 
    178299 
    179     # pylint: disable=no-self-use 
    180300    def getProfile(self): 
     301        # type: () -> (np.ndarray, np.ndarray) 
    181302        """ 
    182303        Get SLD profile 
     
    185306                beta is a list of the corresponding SLD values 
    186307        """ 
    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) 
    188318 
    189319    def setParam(self, name, value): 
     320        # type: (str, float) -> None 
    190321        """ 
    191322        Set the value of a model parameter 
     
    214345 
    215346    def getParam(self, name): 
     347        # type: (str) -> float 
    216348        """ 
    217349        Set the value of a model parameter 
     
    237369 
    238370    def getParamList(self): 
     371        # type: () - > Sequence[str] 
    239372        """ 
    240373        Return a list of all available parameters for the model 
     
    246379 
    247380    def getDispParamList(self): 
     381        # type: () - > Sequence[str] 
    248382        """ 
    249383        Return a list of polydispersity parameters for the model 
     
    258392 
    259393    def clone(self): 
     394        # type: () - > "SasviewModel" 
    260395        """ Return a identical copy of self """ 
    261396        return deepcopy(self) 
    262397 
    263398    def run(self, x=0.0): 
     399        # type: (Union[float, (float, float), List[float]]) -> float 
    264400        """ 
    265401        Evaluate the model 
     
    281417 
    282418    def runXY(self, x=0.0): 
     419        # type: (Union[float, (float, float), List[float]]) -> float 
    283420        """ 
    284421        Evaluate the model in cartesian coordinates 
     
    296433 
    297434    def evalDistribution(self, qdist): 
     435        # type: (Union[np.ndarray, Tuple[np.ndarray, np.ndarray], List[np.ndarray]) -> np.ndarray 
    298436        r""" 
    299437        Evaluate a distribution of q-values. 
     
    339477                            % type(qdist)) 
    340478 
    341     def calculate_Iq(self, *args): 
     479    def calculate_Iq(self, qx, qy=None): 
     480        # type: (Sequence[float], Optional[Sequence[float]]) -> np.ndarray 
    342481        """ 
    343482        Calculate Iq for one set of q with the current parameters. 
     
    350489        if self._model is None: 
    351490            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)] 
    353495        kernel = self._model.make_kernel(q_vectors) 
    354496        pairs = [self._get_weights(p) 
     
    356498        call_details, weight, value = details.build_details(kernel, pairs) 
    357499        result = kernel(call_details, weight, value, cutoff=self.cutoff) 
    358         kernel.q_input.release() 
    359500        kernel.release() 
    360501        return result 
    361502 
    362503    def calculate_ER(self): 
     504        # type: () -> float 
    363505        """ 
    364506        Calculate the effective radius for P(q)*S(q) 
     
    375517 
    376518    def calculate_VR(self): 
     519        # type: () -> float 
    377520        """ 
    378521        Calculate the volf ratio for P(q)*S(q) 
     
    388531 
    389532    def set_dispersion(self, parameter, dispersion): 
     533        # type: (str, weights.Dispersion) -> Dict[str, Any] 
    390534        """ 
    391535        Set the dispersion object for a model parameter 
     
    416560 
    417561    def _dispersion_mesh(self): 
     562        # type: () -> List[Tuple[np.ndarray, np.ndarray]] 
    418563        """ 
    419564        Create a mesh grid of dispersion parameters and weights. 
     
    429574 
    430575    def _get_weights(self, par): 
     576        # type: (Parameter) -> Tuple[np.ndarray, np.ndarray] 
    431577        """ 
    432578        Return dispersion weights for parameter 
    433579        """ 
    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: 
    435586            dis = self.dispersion[par.name] 
    436587            value, weight = weights.get_weights( 
     
    442593 
    443594def test_model(): 
     595    # type: () -> float 
    444596    """ 
    445597    Test that a sasview model (cylinder) can be run. 
     
    451603 
    452604def test_model_list(): 
     605    # type: () -> None 
    453606    """ 
    454607    Make sure that all models build as sasview models. 
  • sasmodels/weights.py

    r7ae2b7f rfa5fd8d  
    174174 
    175175# dispersion name -> disperser lookup table. 
    176 models = dict((d.type, d) for d in ( 
     176MODELS = dict((d.type, d) for d in ( 
    177177    GaussianDispersion, RectangleDispersion, 
    178178    ArrayDispersion, SchulzDispersion, LogNormalDispersion 
     
    201201    Returns *(value, weight)*, where *value* and *weight* are vectors. 
    202202    """ 
    203     cls = models[disperser] 
     203    cls = MODELS[disperser] 
    204204    obj = cls(n, width, nsigmas) 
    205205    v, w = obj.get_weights(value, limits[0], limits[1], relative) 
     
    207207 
    208208# Hack to allow sasview dispersion objects to interoperate with sasmodels 
    209 dispersers = dict((v.__name__, k) for k, v in models.items()) 
     209dispersers = dict((v.__name__, k) for k, v in MODELS.items()) 
    210210dispersers['DispersionModel'] = RectangleDispersion.type 
    211211 
Note: See TracChangeset for help on using the changeset viewer.