Changeset 108e70e in sasmodels for sasmodels/modelinfo.py


Ignore:
Timestamp:
Dec 14, 2017 1:08:45 PM (6 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
ef85a09
Parents:
df69efa
Message:

use Iqac/Iqabc? for the new orientation interface but Iqxy for the old

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/modelinfo.py

    r2d81cfe r108e70e  
    3737 
    3838# assumptions about common parameters exist throughout the code, such as: 
    39 # (1) kernel functions Iq, Iqxy, form_volume, ... don't see them 
     39# (1) kernel functions Iq, Iqxy, Iqac, Iqabc, form_volume, ... don't see them 
    4040# (2) kernel drivers assume scale is par[0] and background is par[1] 
    4141# (3) mixture models drop the background on components and replace the scale 
     
    256256 
    257257    *type* indicates how the parameter will be used.  "volume" parameters 
    258     will be used in all functions.  "orientation" parameters will be used 
    259     in *Iqxy* and *Imagnetic*.  "magnetic* parameters will be used in 
    260     *Imagnetic* only.  If *type* is the empty string, the parameter will 
     258    will be used in all functions.  "orientation" parameters are not passed, 
     259    but will be used to convert from *qx*, *qy* to *qa*, *qb*, *qc* in calls to 
     260    *Iqxy* and *Imagnetic*.  If *type* is the empty string, the parameter will 
    261261    be used in all of *Iq*, *Iqxy* and *Imagnetic*.  "sld" parameters 
    262262    can automatically be promoted to magnetic parameters, each of which 
     
    386386      with vector parameter p sent as p[]. 
    387387 
    388     * [removed] *iqxy_parameters* is the list of parameters to the Iqxy(qx, qy, ...) 
    389       function, with vector parameter p sent as p[]. 
    390  
    391388    * *form_volume_parameters* is the list of parameters to the form_volume(...) 
    392389      function, with vector parameter p sent as p[]. 
     
    443440        self.iq_parameters = [p for p in self.kernel_parameters 
    444441                              if p.type not in ('orientation', 'magnetic')] 
    445         # note: orientation no longer sent to Iqxy, so its the same as 
    446         #self.iqxy_parameters = [p for p in self.kernel_parameters 
    447         #                        if p.type != 'magnetic'] 
     442        self.orientation_parameters = [p for p in self.kernel_parameters 
     443                                       if p.type == 'orientation'] 
    448444        self.form_volume_parameters = [p for p in self.kernel_parameters 
    449445                                       if p.type == 'volume'] 
     
    490486                if p.type != 'orientation': 
    491487                    raise TypeError("psi must be an orientation parameter") 
     488            elif p.type == 'orientation': 
     489                raise TypeError("only theta, phi and psi can be orientation parameters") 
    492490        if theta >= 0 and phi >= 0: 
     491            last_par = len(self.kernel_parameters) - 1 
    493492            if phi != theta+1: 
    494493                raise TypeError("phi must follow theta") 
    495494            if psi >= 0 and psi != phi+1: 
    496495                raise TypeError("psi must follow phi") 
     496            #if (psi >= 0 and psi != last_par) or (psi < 0 and phi != last_par): 
     497            #    raise TypeError("orientation parameters must appear at the " 
     498            #                    "end of the parameter table") 
    497499        elif theta >= 0 or phi >= 0 or psi >= 0: 
    498500            raise TypeError("oriented shapes must have both theta and phi and maybe psi") 
     
    715717 
    716718 
     719#: Set of variables defined in the model that might contain C code 
     720C_SYMBOLS = ['Imagnetic', 'Iq', 'Iqxy', 'Iqac', 'Iqabc', 'form_volume', 'c_code'] 
     721 
    717722def _find_source_lines(model_info, kernel_module): 
    718723    # type: (ModelInfo, ModuleType) -> None 
     
    720725    Identify the location of the C source inside the model definition file. 
    721726 
    722     This code runs through the source of the kernel module looking for 
    723     lines that start with 'Iq', 'Iqxy' or 'form_volume'.  Clearly there are 
    724     all sorts of reasons why this might not work (e.g., code commented out 
    725     in a triple-quoted line block, code built using string concatenation, 
    726     or code defined in the branch of an 'if' block), but it should work 
    727     properly in the 95% case, and getting the incorrect line number will 
    728     be harmless. 
    729     """ 
    730     # Check if we need line numbers at all 
    731     if callable(model_info.Iq): 
    732         return None 
    733  
    734     if (model_info.Iq is None 
    735             and model_info.Iqxy is None 
    736             and model_info.Imagnetic is None 
    737             and model_info.form_volume is None): 
     727    This code runs through the source of the kernel module looking for lines 
     728    that contain C code (because it is a c function definition).  Clearly 
     729    there are all sorts of reasons why this might not work (e.g., code 
     730    commented out in a triple-quoted line block, code built using string 
     731    concatenation, code defined in the branch of an 'if' block, code imported 
     732    from another file), but it should work properly in the 95% case, and for 
     733    the remainder, getting the incorrect line number will merely be 
     734    inconvenient. 
     735    """ 
     736    # Only need line numbers if we are creating a C module and the C symbols 
     737    # are defined. 
     738    if (callable(model_info.Iq) 
     739            or not any(hasattr(model_info, s) for s in C_SYMBOLS)): 
    738740        return 
    739741 
    740     # find the defintion lines for the different code blocks 
     742    # load the module source if we can 
    741743    try: 
    742744        source = inspect.getsource(kernel_module) 
    743745    except IOError: 
    744746        return 
    745     for k, v in enumerate(source.split('\n')): 
    746         if v.startswith('Imagnetic'): 
    747             model_info._Imagnetic_line = k+1 
    748         elif v.startswith('Iqxy'): 
    749             model_info._Iqxy_line = k+1 
    750         elif v.startswith('Iq'): 
    751             model_info._Iq_line = k+1 
    752         elif v.startswith('form_volume'): 
    753             model_info._form_volume_line = k+1 
    754  
     747 
     748    # look for symbol at the start of the line 
     749    for lineno, line in enumerate(source.split('\n')): 
     750        for name in C_SYMBOLS: 
     751            if line.startswith(name): 
     752                # Add 1 since some compilers complain about "#line 0" 
     753                model_info.lineno[name] = lineno + 1 
     754                break 
    755755 
    756756def make_model_info(kernel_module): 
     
    761761    Fill in default values for parts of the module that are not provided. 
    762762 
    763     Note: vectorized Iq and Iqxy functions will be created for python 
     763    Note: vectorized Iq and Iqac/Iqabc functions will be created for python 
    764764    models when the model is first called, not when the model is loaded. 
    765765    """ 
     
    790790    info.profile_axes = getattr(kernel_module, 'profile_axes', ['x', 'y']) 
    791791    info.source = getattr(kernel_module, 'source', []) 
     792    info.c_code = getattr(kernel_module, 'c_code', None) 
    792793    # TODO: check the structure of the tests 
    793794    info.tests = getattr(kernel_module, 'tests', []) 
     
    797798    info.Iq = getattr(kernel_module, 'Iq', None) # type: ignore 
    798799    info.Iqxy = getattr(kernel_module, 'Iqxy', None) # type: ignore 
     800    info.Iqac = getattr(kernel_module, 'Iqac', None) # type: ignore 
     801    info.Iqabc = getattr(kernel_module, 'Iqabc', None) # type: ignore 
    799802    info.Imagnetic = getattr(kernel_module, 'Imagnetic', None) # type: ignore 
    800803    info.profile = getattr(kernel_module, 'profile', None) # type: ignore 
     
    811814    info.hidden = getattr(kernel_module, 'hidden', None) # type: ignore 
    812815 
     816    if callable(info.Iq) and parameters.has_2d: 
     817        raise ValueError("oriented python models not supported") 
     818 
     819    info.lineno = {} 
    813820    _find_source_lines(info, kernel_module) 
    814821 
     
    824831 
    825832    The structure should be mostly static, other than the delayed definition 
    826     of *Iq* and *Iqxy* if they need to be defined. 
     833    of *Iq*, *Iqac* and *Iqabc* if they need to be defined. 
    827834    """ 
    828835    #: Full path to the file defining the kernel, if any. 
     
    906913    structure_factor = None # type: bool 
    907914    #: List of C source files used to define the model.  The source files 
    908     #: should define the *Iq* function, and possibly *Iqxy*, though a default 
    909     #: *Iqxy = Iq(sqrt(qx**2+qy**2)* will be created if no *Iqxy* is provided. 
    910     #: Files containing the most basic functions must appear first in the list, 
    911     #: followed by the files that use those functions.  Form factors are 
    912     #: indicated by providing a :attr:`ER` function. 
     915    #: should define the *Iq* function, and possibly *Iqac* or *Iqabc* if the 
     916    #: model defines orientation parameters. Files containing the most basic 
     917    #: functions must appear first in the list, followed by the files that 
     918    #: use those functions.  Form factors are indicated by providing 
     919    #: an :attr:`ER` function. 
    913920    source = None           # type: List[str] 
    914921    #: The set of tests that must pass.  The format of the tests is described 
     
    935942    #: See :attr:`ER` for details on the parameters. 
    936943    VR = None               # type: Optional[Callable[[np.ndarray], Tuple[np.ndarray, np.ndarray]]] 
     944    #: Arbitrary C code containing supporting functions, etc., to be inserted 
     945    #: after everything in source.  This can include Iq and Iqxy functions with 
     946    #: the full function signature, including all parameters. 
     947    c_code = None 
    937948    #: Returns the form volume for python-based models.  Form volume is needed 
    938949    #: for volume normalization in the polydispersity integral.  If no 
     
    955966    #: include the decimal point. See :mod:`generate` for more details. 
    956967    Iq = None               # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
    957     #: Returns *I(qx, qy, a, b, ...)*.  The interface follows :attr:`Iq`. 
    958     Iqxy = None             # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
     968    #: Returns *I(qab, qc, a, b, ...)*.  The interface follows :attr:`Iq`. 
     969    Iqac = None             # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
     970    #: Returns *I(qa, qb, qc, a, b, ...)*.  The interface follows :attr:`Iq`. 
     971    Iqabc = None            # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
    959972    #: Returns *I(qx, qy, a, b, ...)*.  The interface follows :attr:`Iq`. 
    960973    Imagnetic = None        # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
     
    972985    #: Returns a random parameter set for the model 
    973986    random = None           # type: Optional[Callable[[], Dict[str, float]]] 
    974  
    975     # line numbers within the python file for bits of C source, if defined 
    976     # NB: some compilers fail with a "#line 0" directive, so default to 1. 
    977     _Imagnetic_line = 1 
    978     _Iqxy_line = 1 
    979     _Iq_line = 1 
    980     _form_volume_line = 1 
    981  
     987    #: Line numbers for symbols defining C code 
     988    lineno = None           # type: Dict[str, int] 
    982989 
    983990    def __init__(self): 
Note: See TracChangeset for help on using the changeset viewer.