Changeset 04045f4 in sasmodels for sasmodels/modelinfo.py


Ignore:
Timestamp:
Apr 12, 2016 6:02:40 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:
793beb3
Parents:
fa5fd8d
Message:

support for rpa style variant models

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/modelinfo.py

    r7ae2b7f r04045f4  
    77module into the model info block as seen by the rest of the sasmodels library. 
    88""" 
     9from __future__ import print_function 
     10 
    911from copy import copy 
    1012from os.path import abspath, basename, splitext 
     
    1618# Optional typing 
    1719try: 
    18     from typing import Tuple, List, Union, Dict, Optional, Any, Callable 
     20    from typing import Tuple, List, Union, Dict, Optional, Any, Callable, Sequence, Set 
    1921except ImportError: 
    2022    pass 
     
    2224    from .details import CallDetails 
    2325    Limits = Tuple[float, float] 
    24     #LimitsOrChoice = Union[Limits, Tuple[str]] 
     26    LimitsOrChoice = Union[Limits, Tuple[Sequence[str]]] 
    2527    ParameterDef = Tuple[str, str, float, Limits, str, str] 
    2628    ParameterSetUser = Dict[str, Union[float, List[float]]] 
     
    6870 
    6971def parse_parameter(name, units='', default=np.NaN, 
    70                     limits=(-np.inf, np.inf), ptype='', description=''): 
    71     # type: (str, str, float, Limits, str, str) -> Parameter 
     72                    user_limits=None, ptype='', description=''): 
     73    # type: (str, str, float, LimitsOrChoice, str, str) -> Parameter 
    7274    """ 
    7375    Parse an individual parameter from the parameter definition block. 
     
    8183    if not isstr(units): 
    8284        raise ValueError("expected units to be a string for %s"%name) 
    83     # if limits is a list of strings, then this is a choice list 
    84     # field, and limits are 1 to length of string list 
     85 
     86    # Process limits as [float, float] or [[str, str, ...]] 
    8587    choices = []  # type: List[str] 
    86     if isinstance(limits, list) and all(isstr(k) for k in limits): 
    87         choices = limits 
    88         limits = (0., len(choices)-1.) 
    89  
    90     # TODO: maybe allow limits of None for (-inf, inf) 
    91     try: 
    92         low, high = limits 
    93         if not isinstance(low, (int, float)): 
    94             raise TypeError("low is not numeric") 
    95         if not isinstance(high, (int, float)): 
    96             raise TypeError("high is not numeric") 
    97         if low >= high: 
    98             raise ValueError("require low < high") 
    99     except Exception: 
    100         raise ValueError("invalid limits %s for %s"%(limits, name)) 
    101  
     88    if user_limits is None: 
     89        limits = (-np.inf, np.inf) 
     90    elif not isinstance(user_limits, (tuple, list)): 
     91        raise ValueError("invalid limits for %s"%name) 
     92    else: 
     93        # if limits is [[str,...]], then this is a choice list field, 
     94        # and limits are 1 to length of string list 
     95        if isinstance(user_limits[0], (tuple, list)): 
     96            choices = user_limits[0] 
     97            limits = (0., len(choices)-1.) 
     98            if not all(isstr(k) for k in choices): 
     99                raise ValueError("choices must be strings for %s"%name) 
     100        else: 
     101            try: 
     102                low, high = user_limits 
     103                limits = (float(low), float(high)) 
     104            except Exception: 
     105                raise ValueError("invalid limits for %s"%name) 
     106            else: 
     107                if low >= high: 
     108                    raise ValueError("require lower limit < upper limit") 
     109 
     110    # Process default value as float, making sure it is in range 
    102111    if not isinstance(default, (int, float)): 
    103112        raise ValueError("expected default %r to be a number for %s" 
    104113                         % (default, name)) 
    105     if default < low or default > high: 
     114    if default < limits[0] or default > limits[1]: 
    106115        raise ValueError("default value %r not in range for %s" 
    107116                         % (default, name)) 
    108117 
     118    # Check for valid parameter type 
    109119    if ptype not in ("volume", "orientation", "sld", "magnetic", ""): 
    110120        raise ValueError("unexpected type %r for %s" % (ptype, name)) 
    111121 
     122    # Check for valid parameter description 
    112123    if not isstr(description): 
    113124        raise ValueError("expected description to be a string") 
    114  
    115125 
    116126    # Parameter id for name[n] does not include [n] 
     
    122132    else: 
    123133        pid, ref = name, None 
    124  
    125134 
    126135    # automatically identify sld types 
     
    474483                    raise ValueError("expected limits on %s to be within [0, 20]" 
    475484                                     % ref.name) 
    476                 # TODO: may want to make a copy of the parameter before updating 
    477                 # this introduces other potential problems, since the same 
    478                 # parameter may be referenced elsewhere 
    479                 p.length = high 
     485                p.length = int(high) 
    480486 
    481487    def _get_defaults(self): 
     
    544550        early, and rerender the table when it is changed. 
    545551        """ 
     552        # control parameters go first 
    546553        control = [p for p in self.kernel_parameters if p.is_control] 
    547554 
    548555        # Gather entries such as name[n] into groups of the same n 
    549         dependent = dict((p.id, []) for p in control)  # type: Dict[str, List[Parameter]] 
     556        dependent = {} # type: Dict[str, List[Parameter]] 
     557        dependent.update((p.id, []) for p in control) 
    550558        for p in self.kernel_parameters: 
    551559            if p.length_control is not None: 
     
    635643    info.single = getattr(kernel_module, 'single', True) 
    636644    info.structure_factor = getattr(kernel_module, 'structure_factor', False) 
    637     info.profile_axes = getattr(kernel_module, 'profile_axes', ['x','y']) 
     645    info.profile_axes = getattr(kernel_module, 'profile_axes', ['x', 'y']) 
    638646    info.variant_info = getattr(kernel_module, 'variant_info', None) 
    639647    info.source = getattr(kernel_module, 'source', []) 
     
    647655    info.profile = getattr(kernel_module, 'profile', None) # type: ignore 
    648656    info.sesans = getattr(kernel_module, 'sesans', None) # type: ignore 
     657    info.control = getattr(kernel_module, 'control', None) 
     658    info.hidden = getattr(kernel_module, 'hidden', None) # type: ignore 
    649659 
    650660    # Precalculate the monodisperse parameter details 
     
    691701      *model_info* blocks for the composition objects.  This allows us to 
    692702      build complete product and mixture models from just the info. 
     703    * *control* is the name of the control parameter if there is one. 
     704    * *hidden* returns the list of hidden parameters given the value of the 
     705      control parameter 
    693706 
    694707    The structure should be mostly static, other than the delayed definition 
     
    703716    demo = None             # type: Dict[str, float] 
    704717    composition = None      # type: Optional[Tuple[str, List[ModelInfo]]] 
     718    control = None          # type: str 
    705719    docs = None             # type: str 
    706720    category = None         # type: Optional[str] 
     
    718732    profile = None          # type: Optional[Callable[[np.ndarray], None]] 
    719733    sesans = None           # type: Optional[Callable[[np.ndarray], np.ndarray]] 
     734    hidden = None           # type: Optional[Callable[int], Set[str]] 
    720735    mono_details = None     # type: CallDetails 
    721736 
     
    724739        pass 
    725740 
    726  
     741    def get_hidden_parameters(self, control): 
     742        if self.hidden is not None: 
     743            hidden = self.hidden(control) 
     744        else: 
     745            controls = [p for p in self.parameters.kernel_parameters] 
     746            if len(controls) != 1: 
     747                raise ValueError("more than one control parameter") 
     748            hidden = set(p.id+str(k) 
     749                         for p in self.parameters.kernel_parameters 
     750                         for k in range(control+1, p.length+1) 
     751                         if p.length > 1) 
     752        return hidden 
Note: See TracChangeset for help on using the changeset viewer.