Changeset 9eb3632 in sasmodels for sasmodels/details.py


Ignore:
Timestamp:
Jul 23, 2016 12:54:17 AM (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:
7b7da6b
Parents:
6a0d6aa
Message:

restructure kernels using fixed PD loops

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/details.py

    r32e3c9b r9eb3632  
    22 
    33import numpy as np  # type: ignore 
     4from numpy import pi, cos, sin 
     5 
     6try: 
     7    np.meshgrid([]) 
     8    meshgrid = np.meshgrid 
     9except ValueError: 
     10    # CRUFT: np.meshgrid requires multiple vectors 
     11    def meshgrid(*args): 
     12        if len(args) > 1: 
     13            return np.meshgrid(*args) 
     14        else: 
     15            return [np.asarray(v) for v in args] 
    416 
    517try: 
     
    8092        print("pd_stride", self.pd_stride) 
    8193 
     94 
    8295def mono_details(model_info): 
    8396    call_details = CallDetails(model_info) 
    8497    call_details.pd_prod = 1 
     98    call_details.pd_sum = model_info.parameters.nvalues 
     99    call_details.pd_par[:] = np.arange(0, model_info.parameters.max_pd) 
     100    call_details.pd_length[:] = 1 
     101    call_details.pd_offset[:] = np.arange(0, model_info.parameters.max_pd) 
     102    call_details.pd_stride[:] = 1 
    85103    return call_details 
     104 
    86105 
    87106def poly_details(model_info, weights): 
     
    90109 
    91110    # Decreasing list of polydispersity lengths 
    92     pd_length = np.array([len(w) for w in weights]) 
     111    #print([p.id for p in model_info.parameters.call_parameters]) 
     112    pd_length = np.array([len(w) for w in weights[2:2+model_info.parameters.npars]]) 
    93113    num_active = np.sum(pd_length>1) 
    94     if num_active > model_info.parameters.max_pd: 
     114    max_pd = model_info.parameters.max_pd 
     115    if num_active > max_pd: 
    95116        raise ValueError("Too many polydisperse parameters") 
    96117 
     
    100121    #print("off:",pd_offset) 
    101122    # Note: the reversing view, x[::-1], does not require a copy 
    102     idx = np.argsort(pd_length)[::-1][:num_active] 
    103     par_length = np.array([len(w) for w in weights]) 
    104     pd_stride = np.cumprod(np.hstack((1, par_length[idx]))) 
     123    idx = np.argsort(pd_length)[::-1][:max_pd] 
     124    pd_stride = np.cumprod(np.hstack((1, pd_length[idx]))) 
    105125 
    106126    call_details = CallDetails(model_info) 
    107     call_details.pd_par[:num_active] = idx - 2  # skip background & scale 
    108     call_details.pd_length[:num_active] = pd_length[idx] 
    109     call_details.pd_offset[:num_active] = pd_offset[idx] 
    110     call_details.pd_stride[:num_active] = pd_stride[:-1] 
     127    call_details.pd_par[:max_pd] = idx 
     128    call_details.pd_length[:max_pd] = pd_length[idx] 
     129    call_details.pd_offset[:max_pd] = pd_offset[idx] 
     130    call_details.pd_stride[:max_pd] = pd_stride[:-1] 
    111131    call_details.pd_prod = pd_stride[-1] 
    112     call_details.pd_sum = np.sum(par_length) 
     132    call_details.pd_sum = sum(len(w) for w in weights) 
    113133    call_details.num_active = num_active 
    114134    #call_details.show() 
    115135    return call_details 
     136 
     137 
     138def dispersion_mesh(model_info, pars): 
     139    """ 
     140    Create a mesh grid of dispersion parameters and weights. 
     141 
     142    Returns [p1,p2,...],w where pj is a vector of values for parameter j 
     143    and w is a vector containing the products for weights for each 
     144    parameter set in the vector. 
     145    """ 
     146    value, weight = zip(*pars) 
     147    weight = [w if w else [1.] for w in weight] 
     148    weight = np.vstack([v.flatten() for v in meshgrid(*weight)]) 
     149    weight = np.prod(weight, axis=0) 
     150    value = [v.flatten() for v in meshgrid(*value)] 
     151    lengths = [par.length for par in model_info.parameters.kernel_parameters 
     152               if par.type == 'volume'] 
     153    if any(n > 1 for n in lengths): 
     154        pars = [] 
     155        offset = 0 
     156        for n in lengths: 
     157            pars.append(np.vstack(value[offset:offset+n]) if n > 1 else value[offset]) 
     158            offset += n 
     159        value = pars 
     160    return value, weight 
     161 
     162 
     163 
     164def build_details(kernel, pairs): 
     165    # type: (Kernel, Tuple[List[np.ndarray], List[np.ndarray]]) -> Tuple[CallDetails, np.ndarray, bool] 
     166    """ 
     167    Converts (value, weight) pairs into parameters for the kernel call. 
     168 
     169    Returns a CallDetails object indicating the polydispersity, a data object 
     170    containing the different values, and the magnetic flag indicating whether 
     171    any magnetic magnitudes are non-zero. Magnetic vectors (M0, phi, theta) are 
     172    converted to rectangular coordinates (mx, my, mz). 
     173    """ 
     174    values, weights = zip(*pairs) 
     175    scalars = [v[0] for v in values] 
     176    if all(len(w)==1 for w in weights): 
     177        call_details = mono_details(kernel.info) 
     178        data = np.array(scalars+scalars+[1]*len(scalars), dtype=kernel.dtype) 
     179    else: 
     180        call_details = poly_details(kernel.info, weights) 
     181        data = np.hstack(scalars+list(values)+list(weights)).astype(kernel.dtype) 
     182    is_magnetic = convert_magnetism(kernel.info.parameters, data) 
     183    #call_details.show() 
     184    return call_details, data, is_magnetic 
     185 
     186def convert_magnetism(parameters, values): 
     187    """ 
     188    Convert magnetism in value table from polar to rectangular coordinates. 
     189 
     190    Returns True if any magnetism is present. 
     191    """ 
     192    mag = values[parameters.nvalues-3*parameters.nmagnetic:parameters.nvalues] 
     193    mag = mag.reshape(-1, 3) 
     194    M0 = mag[:,0] 
     195    if np.any(M0): 
     196        theta, phi = mag[:,1]*pi/180., mag[:,2]*pi/180. 
     197        cos_theta = cos(theta) 
     198        mx = M0*cos_theta*cos(phi) 
     199        my = M0*sin(theta) 
     200        mz = -M0*cos_theta*sin(phi) 
     201        mag[:,0], mag[:,1], mag[:,2] = mx, my, mz 
     202        return True 
     203    else: 
     204        return False 
Note: See TracChangeset for help on using the changeset viewer.