Changeset a6f9577 in sasmodels


Ignore:
Timestamp:
Mar 21, 2016 5:40:25 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:
9f4409a
Parents:
39cc3be
Message:

restore support for simple polydispersity (incomplete)

Location:
sasmodels
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/generate.py

    r7ff3cf3 ra6f9577  
    593593      width (e.g., radius +/- 10%) rather than absolute distribution 
    594594      width (e.g., theta +/- 6 degrees). 
     595    * *theta_par* is the index of the polar angle polydispersion parameter 
     596      or -1 if no such parameter exists 
    595597    """ 
    596598    par_set = {} 
     
    600602    par_set['pd'] = [p.name for p in pars if p.type in ('volume', 'orientation')] 
    601603    par_set['pd_relative'] = [p.name for p in pars if p.type == 'volume'] 
     604    if 'theta' in par_set['2d']: 
     605        # find id of theta in parameter set (or whatever variable is 
     606        # used for spherical normalization during polydispersity... 
     607        par_set['theta_par'] = [k for k,p in enumerate(pars) if p.name=='theta'][0] 
     608    else: 
     609        par_set['theta_par'] = -1 
    602610    return par_set 
    603611 
     
    649657        model_info['demo'] = dict((p.name, p.default) for p in pars) 
    650658    model_info['has_2d'] = par_type['orientation'] or par_type['magnetic'] 
     659    # Don't use more polydisperse parameters than are available in the model 
     660    # Note: we can do polydispersity on arbitrary parameters, so it is not 
     661    # clear that this is a good idea; it does however make the poly_details 
     662    # code easier to write, so we will leave it in for now. 
     663    model_info['max_pd'] = min(len(par_type['pd']), MAX_PD) 
    651664 
    652665def mono_details(model_info): 
     
    659672    details[0*max_pd:1*max_pd] = range(max_pd)       # pd_par: arbitrary order; use first 
    660673    details[1*max_pd:2*max_pd] = [1]*max_pd          # pd_length: only one element 
    661     details[2*max_pd:3*max_pd] = range(2, max_pd+2)  # pd_offset: skip scale and background 
     674    details[2*max_pd:3*max_pd] = range(max_pd)       # pd_offset: consecutive 1.0 weights 
    662675    details[3*max_pd:4*max_pd] = [1]*max_pd          # pd_stride: vectors of length 1 
    663676    details[4*max_pd:5*max_pd] = [0]*max_pd          # pd_isvol: doens't matter if no norm 
    664     details[p+0*npars:p+1*npars] = range(2, npars+2) # par_offset 
     677    details[p+0*npars:p+1*npars] = range(2, npars+2) # par_offset: skip scale and background 
    665678    details[p+1*npars:p+2*npars] = [0]*npars         # no coordination 
    666679    #details[p+npars] = 1 # par_coord[0] is coordinated with the first par? 
    667680    details[p+2*npars:p+3*npars] = 0 # fast coord with 0 
    668681    details[c]   = 1     # fast_coord_count: one fast index 
    669     details[c+1] = -1  # theta_var: None 
    670     details[c+2] = 0   # fast_theta: False 
     682    details[c+1] = -1    # theta_par: None 
    671683    return details 
    672684 
    673 def poly_details(model_info, weights, constraints=None): 
    674     if constraints is not None: 
    675         # Need to find the independently varying pars and sort them 
    676         # Need to build a coordination list for the dependent variables 
    677         # Need to generate a constraints function which takes values 
    678         # and weights, returning par blocks 
    679         raise ValueError("Can't handle constraints yet") 
    680  
     685def poly_details(model_info, weights): 
     686    pars = model_info['parameters'][2:]  # skip scale and background 
    681687    max_pd = model_info['max_pd'] 
    682     npars = len(model_info['parameters']) - 2 
     688    npars = len(pars) # scale and background already removed 
    683689    p = 5*max_pd 
    684     c = p + 3*npars 
     690    constants_offset = p + 3*npars 
    685691 
    686692    # Decreasing list of polydispersity lengths 
    687693    # Note: the reversing view, x[::-1], does not require a copy 
    688     idx = np.argsort([len(w) for w in weights])[::-1] 
    689     details = np.zeros(c + 3, 'int32') 
    690     details[0*max_pd:1*max_pd] = idx[:max_pd]        # pd_par: arbitrary order; use first 
    691     details[1*max_pd:2*max_pd] = [1]*max_pd          # pd_length: only one element 
    692     details[2*max_pd:3*max_pd] = range(2, max_pd+2)  # pd_offset: skip scale and background 
    693     details[3*max_pd:4*max_pd] = [1]*max_pd          # pd_stride: vectors of length 1 
    694     details[4*max_pd:5*max_pd] = [0]*max_pd          # pd_isvol: doens't matter if no norm 
    695     details[p+0*npars:p+1*npars] = range(2, npars+2) # par_offset 
    696     details[p+1*npars:p+2*npars] = [0]*npars         # no coordination 
    697     #details[p+npars] = 1 # par_coord[0] is coordinated with the first par? 
    698     details[p+2*npars:p+3*npars] = 0 # fast coord with 0 
    699     details[c]   = 1     # fast_coord_count: one fast index 
    700     details[c+1] = -1  # theta_var: None 
    701     details[c+2] = 0   # fast_theta: False 
     694    pd_length = np.array([len(w) for w in weights]) 
     695    pd_offset = np.cumsum(np.hstack((0, pd_length))) 
     696    pd_isvol = np.array([p.type=='volume' for p in pars]) 
     697    idx = np.argsort(pd_length)[::-1][:max_pd] 
     698    pd_stride = np.cumprod(np.hstack((1, np.maximum(pd_length[idx][:-1],1)))) 
     699    par_offsets = np.cumsum(np.hstack((2, np.maximum(pd_length, 1))))[:-1] 
     700    theta_par = model_info['theta_par'] 
     701    if theta_par >= 0 and pd_length[theta_par] <= 1: 
     702        theta_par = -1 
     703 
     704    details = np.empty(constants_offset + 3, 'int32') 
     705    details[0*max_pd:1*max_pd] = idx             # pd_par 
     706    details[1*max_pd:2*max_pd] = pd_length[idx] 
     707    details[2*max_pd:3*max_pd] = pd_offset[idx] 
     708    details[3*max_pd:4*max_pd] = pd_stride 
     709    details[4*max_pd:5*max_pd] = pd_isvol[idx] 
     710    details[p+0*npars:p+1*npars] = par_offsets 
     711    details[p+1*npars:p+2*npars] = 0  # no coordination for most 
     712    details[p+2*npars:p+3*npars] = 0  # no fast coord with 0 
     713    coord_offset = p+1*pars 
     714    for k,parameter_num in enumerate(idx): 
     715        details[coord_offset+parameter_num] = 2**k 
     716    details[constants_offset]   = 1   # fast_coord_count: one fast index 
     717    details[constants_offset+1] = theta_par 
    702718    return details 
    703719 
    704  
    705  
    706     raise ValueError("polydispersity not supported") 
     720def constrained_poly_details(model_info, weights, constraints): 
     721    # Need to find the independently varying pars and sort them 
     722    # Need to build a coordination list for the dependent variables 
     723    # Need to generate a constraints function which takes values 
     724    # and weights, returning par blocks 
     725    raise NotImplementedError("Can't handle constraints yet") 
    707726 
    708727 
     
    777796        name = " ".join(w.capitalize() for w in kernel_id.split('_')) 
    778797    model_info = dict( 
    779         max_pd=MAX_PD, 
    780798        id=kernel_id,  # string used to load the kernel 
    781799        filename=abspath(kernel_module.__file__), 
  • sasmodels/kernel_iq.c

    r39cc3be ra6f9577  
    1818 
    1919typedef struct { 
    20     int32_t pd_par[MAX_PD];     // index of the nth polydispersity variable 
     20    int32_t pd_par[MAX_PD];     // id of the nth polydispersity variable 
    2121    int32_t pd_length[MAX_PD];  // length of the nth polydispersity weight vector 
    2222    int32_t pd_offset[MAX_PD];  // offset of pd weights in the par & weight vector 
     
    2525    int32_t par_offset[NPARS];  // offset of par values in the par & weight vector 
    2626    int32_t par_coord[NPARS];   // polydispersity coordination bitvector 
    27     int32_t fast_coord_index[NPARS]; // index of the fast coordination parameters 
     27    int32_t fast_coord_pars[NPARS]; // ids of the fast coordination parameters 
    2828    int32_t fast_coord_count;   // number of parameters coordinated with pd 1 
    2929    int32_t theta_var;          // id of spherical correction variable 
    30     int32_t fast_theta;         // true if spherical correction depends on pd 1 
    3130} ProblemDetails; 
    3231 
     
    5554  double *pvec = (double *)(&local_pars);  // Alias named parameters with a vector 
    5655 
    57   local int offset[NPARS-2]; 
     56  local int offset[NPARS];  // NPARS excludes scale/background 
    5857 
    5958#if 1 // defined(USE_SHORTCUT_OPTIMIZATION) 
     
    155154        spherical_correction = fabs(cos(M_PI_180*pvec[problem->theta_var])); 
    156155      } 
    157       if (!problem->fast_theta) { 
     156      if (problem->theta_var == problem->pd_par[0]) { 
    158157        weight *= spherical_correction; 
    159158      } 
     
    167166      if (problem->pd_isvol[0]) vol_weight *= wi; 
    168167      for (int k=0; k < problem->fast_coord_count; k++) { 
    169         pvec[problem->fast_coord_index[k]] 
    170             = pars[offset[problem->fast_coord_index[k]]++]; 
    171       } 
    172       if (problem->fast_theta) { 
     168        pvec[problem->fast_coord_pars[k]] 
     169            = pars[offset[problem->fast_coord_pars[k]]++]; 
     170      } 
     171      if (problem->theta_var ==problem->pd_par[0]) { 
    173172        weight *= fabs(cos(M_PI_180*pvec[problem->theta_var])); 
    174173      } 
  • sasmodels/kernelcl.py

    r4f9d3fd ra6f9577  
    448448        self._need_release = [self.loops_b, self.res_b, self.q_input] 
    449449 
    450     def __call__(self, fixed_pars, pd_pars, cutoff=1e-5): 
     450    def __call__(self, details, weights, values, cutoff): 
    451451        real = (np.float32 if self.q_input.dtype == generate.F32 
    452452                else np.float64 if self.q_input.dtype == generate.F64 
Note: See TracChangeset for help on using the changeset viewer.