Changeset 5399809 in sasmodels


Ignore:
Timestamp:
Aug 21, 2018 1:32:40 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:
2a12351b
Parents:
c57ee9e
Message:

fix R_eff support infrastructure so more tests pass

Location:
sasmodels
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/core.py

    r71b751d r5399809  
    363363    model = load_model("cylinder@hardsphere*sphere") 
    364364    actual = [p.name for p in model.info.parameters.kernel_parameters] 
    365     target = ("sld sld_solvent radius length theta phi volfraction" 
    366               " beta_mode A_sld A_sld_solvent A_radius").split() 
     365    target = ("sld sld_solvent radius length theta phi" 
     366              " radius_effective volfraction structure_factor_mode" 
     367              " A_sld A_sld_solvent A_radius").split() 
    367368    assert target == actual, "%s != %s"%(target, actual) 
    368369 
  • sasmodels/generate.py

    r6e7ba14 r5399809  
    802802                              for p in partable.kernel_parameters)) 
    803803    # Define the function calls 
     804    call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(mode, v) 0.0" 
    804805    if partable.form_volume_parameters: 
    805806        refs = _call_pars("_v.", partable.form_volume_parameters) 
    806807        call_volume = "#define CALL_VOLUME(_v) form_volume(%s)"%(",".join(refs)) 
    807         call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(mode, _v) effective_radius(mode, %s)"%(",".join(refs)) 
     808        if model_info.effective_radius_type: 
     809            call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(mode, _v) effective_radius(mode, %s)"%(",".join(refs)) 
    808810    else: 
    809811        # Model doesn't have volume.  We could make the kernel run a little 
     
    811813        # the ifdef's reduce readability more than is worthwhile. 
    812814        call_volume = "#define CALL_VOLUME(v) 1.0" 
    813         call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(mode, v) 0.0" 
    814815    source.append(call_volume) 
    815816    source.append(call_effective_radius) 
  • sasmodels/kernel.py

    r6e7ba14 r5399809  
    4444        # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 
    4545        Pq, Reff = self.Pq_Reff(call_details, values, cutoff, magnetic, effective_radius_type=0) 
    46         scale = values[0] 
    47         background = values[1] 
    48         return scale*Pq + background 
     46        return Pq 
    4947    __call__ = Iq 
    5048 
     
    5351        self._call_kernel(call_details, values, cutoff, magnetic, effective_radius_type) 
    5452        #print("returned",self.q_input.q, self.result) 
    55         nout = 2 if self.info.have_Fq else 1 
     53        nout = 2 if self.info.have_Fq and self.dim == '1d' else 1 
    5654        total_weight = self.result[nout*self.q_input.nq + 0] 
    5755        if total_weight == 0.: 
     
    6361        #           = scale*(sum(w*F^2)/sum w)/(sum (w*V)/sum w) + background 
    6462        #           = scale/sum (w*V) * sum(w*F^2) + background 
     63        F2 = self.result[0:nout*self.q_input.nq:nout] 
    6564        scale = values[0]/(weighted_volume if weighted_volume != 0.0 else 1.0) 
    6665        background = values[1] 
     66        Pq = scale*F2 + background 
    6767        #print("scale",scale,background) 
    68         return self.result[0:nout*self.q_input.nq:nout], effective_radius 
     68        return Pq, effective_radius 
    6969 
    7070    def beta(self, call_details, values, cutoff, magnetic, effective_radius_type): 
  • sasmodels/kernelcl.py

    r6e7ba14 r5399809  
    481481        # at this point, so instead using 32, which is good on the set of 
    482482        # architectures tested so far. 
     483        extra_q = 3  # total weight, weighted volume and weighted radius 
    483484        if self.is_2d: 
    484             # Note: 16 rather than 15 because result is 1 longer than input. 
    485             width = ((self.nq+16)//16)*16 
     485            width = ((self.nq+15+extra_q)//16)*16 
    486486            self.q = np.empty((width, 2), dtype=dtype) 
    487487            self.q[:self.nq, 0] = q_vectors[0] 
    488488            self.q[:self.nq, 1] = q_vectors[1] 
    489489        else: 
    490             # Note: 32 rather than 31 because result is 1 longer than input. 
    491             width = ((self.nq+32)//32)*32 
     490            width = ((self.nq+31+extra_q)//32)*32 
    492491            self.q = np.empty(width, dtype=dtype) 
    493492            self.q[:self.nq] = q_vectors[0] 
     
    539538        self.dim = '2d' if q_input.is_2d else '1d' 
    540539        # leave room for f1/f2 results in case we need to compute beta for 1d models 
    541         num_returns = 1 if self.dim == '2d' else 2  # 
    542         # plus 1 for the normalization value, plus another for R_eff 
    543         self.result = np.empty((q_input.nq+2)*num_returns, dtype) 
     540        nout = 2 if self.info.have_Fq and self.dim == '1d' else 1 
     541        # plus 3 weight, volume, radius 
     542        self.result = np.empty(q_input.nq*nout + 3, self.dtype) 
    544543 
    545544        # Inputs and outputs for each kernel call 
     
    549548 
    550549        self.result_b = cl.Buffer(self.queue.context, mf.READ_WRITE, 
    551                                   q_input.global_size[0] * num_returns * dtype.itemsize) 
     550                                  q_input.global_size[0] * nout * dtype.itemsize) 
    552551        self.q_input = q_input # allocated by GpuInput above 
    553552 
  • sasmodels/kernelpy.py

    r6e7ba14 r5399809  
    182182        radius = ((lambda: 0.0) if effective_radius_type == 0 
    183183                  else (lambda: self._radius(effective_radius_type))) 
    184         res = _loops(self._parameter_vector, self._form, self._volume, radius, 
    185                      self.q_input.nq, call_details, values, cutoff) 
    186         return res 
     184        self.result = _loops( 
     185            self._parameter_vector, self._form, self._volume, radius, 
     186            self.q_input.nq, call_details, values, cutoff) 
    187187 
    188188    def release(self): 
     
    213213    #                                                              # 
    214214    ################################################################ 
     215 
     216    # WARNING: Trickery ahead 
     217    # The parameters[] vector is embedded in the closures for form(), 
     218    # form_volume() and form_radius().  We set the initial vector from 
     219    # the values for the model parameters. As we loop through the polydispesity 
     220    # mesh, we update the components with the polydispersity values before 
     221    # calling the respective functions. 
    215222    n_pars = len(parameters) 
    216223    parameters[:] = values[2:n_pars+2] 
     224 
    217225    if call_details.num_active == 0: 
    218         pd_norm = float(form_volume()) 
    219         scale = values[0]/(pd_norm if pd_norm != 0.0 else 1.0) 
    220         background = values[1] 
    221         return scale*form() + background 
    222  
    223     pd_value = values[2+n_pars:2+n_pars + call_details.num_weights] 
    224     pd_weight = values[2+n_pars + call_details.num_weights:] 
    225  
    226     weight_norm = 0.0 
    227     weighted_volume = 0.0 
    228     weighted_radius = 0.0 
    229     partial_weight = np.NaN 
    230     weight = np.NaN 
    231  
    232     p0_par = call_details.pd_par[0] 
    233     p0_length = call_details.pd_length[0] 
    234     p0_index = p0_length 
    235     p0_offset = call_details.pd_offset[0] 
    236  
    237     pd_par = call_details.pd_par[:call_details.num_active] 
    238     pd_offset = call_details.pd_offset[:call_details.num_active] 
    239     pd_stride = call_details.pd_stride[:call_details.num_active] 
    240     pd_length = call_details.pd_length[:call_details.num_active] 
    241  
    242     total = np.zeros(nq, 'd') 
    243     for loop_index in range(call_details.num_eval): 
    244         # update polydispersity parameter values 
    245         if p0_index == p0_length: 
    246             pd_index = (loop_index//pd_stride)%pd_length 
    247             parameters[pd_par] = pd_value[pd_offset+pd_index] 
    248             partial_weight = np.prod(pd_weight[pd_offset+pd_index][1:]) 
    249             p0_index = loop_index%p0_length 
    250  
    251         weight = partial_weight * pd_weight[p0_offset + p0_index] 
    252         parameters[p0_par] = pd_value[p0_offset + p0_index] 
    253         p0_index += 1 
    254         if weight > cutoff: 
    255             # Call the scattering function 
    256             # Assume that NaNs are only generated if the parameters are bad; 
    257             # exclude all q for that NaN.  Even better would be to have an 
    258             # INVALID expression like the C models, but that is too expensive. 
    259             Iq = np.asarray(form(), 'd') 
    260             if np.isnan(Iq).any(): 
    261                 continue 
    262  
    263             # update value and norm 
    264             total += weight * Iq 
    265             weight_norm += weight 
    266             weighted_volume += weight * form_volume() 
    267             weighted_radius += weight * form_radius() 
     226        total = form() 
     227        weight_norm = 1.0 
     228        weighted_volume = form_volume() 
     229        weighted_radius = form_radius() 
     230 
     231    else: 
     232        pd_value = values[2+n_pars:2+n_pars + call_details.num_weights] 
     233        pd_weight = values[2+n_pars + call_details.num_weights:] 
     234 
     235        weight_norm = 0.0 
     236        weighted_volume = 0.0 
     237        weighted_radius = 0.0 
     238        partial_weight = np.NaN 
     239        weight = np.NaN 
     240 
     241        p0_par = call_details.pd_par[0] 
     242        p0_length = call_details.pd_length[0] 
     243        p0_index = p0_length 
     244        p0_offset = call_details.pd_offset[0] 
     245 
     246        pd_par = call_details.pd_par[:call_details.num_active] 
     247        pd_offset = call_details.pd_offset[:call_details.num_active] 
     248        pd_stride = call_details.pd_stride[:call_details.num_active] 
     249        pd_length = call_details.pd_length[:call_details.num_active] 
     250 
     251        total = np.zeros(nq, 'd') 
     252        for loop_index in range(call_details.num_eval): 
     253            # update polydispersity parameter values 
     254            if p0_index == p0_length: 
     255                pd_index = (loop_index//pd_stride)%pd_length 
     256                parameters[pd_par] = pd_value[pd_offset+pd_index] 
     257                partial_weight = np.prod(pd_weight[pd_offset+pd_index][1:]) 
     258                p0_index = loop_index%p0_length 
     259 
     260            weight = partial_weight * pd_weight[p0_offset + p0_index] 
     261            parameters[p0_par] = pd_value[p0_offset + p0_index] 
     262            p0_index += 1 
     263            if weight > cutoff: 
     264                # Call the scattering function 
     265                # Assume that NaNs are only generated if the parameters are bad; 
     266                # exclude all q for that NaN.  Even better would be to have an 
     267                # INVALID expression like the C models, but that is expensive. 
     268                Iq = np.asarray(form(), 'd') 
     269                if np.isnan(Iq).any(): 
     270                    continue 
     271 
     272                # update value and norm 
     273                total += weight * Iq 
     274                weight_norm += weight 
     275                weighted_volume += weight * form_volume() 
     276                weighted_radius += weight * form_radius() 
    268277 
    269278    result = np.hstack((total, weight_norm, weighted_volume, weighted_radius)) 
  • sasmodels/modelinfo.py

    r6e7ba14 r5399809  
    794794    info.source = getattr(kernel_module, 'source', []) 
    795795    info.c_code = getattr(kernel_module, 'c_code', None) 
     796    info.effective_radius = getattr(kernel_module, 'effective_radius', None) 
    796797    info.ER = None  # CRUFT 
    797798    info.VR = None  # CRUFT 
  • sasmodels/product.py

    rc57ee9e r5399809  
    301301                p_details, p_values, cutoff, magnetic, effective_radius_type) 
    302302            if effective_radius_type > 0: 
     303                # Plug R_eff from p into S model (initial value and pd value) 
    303304                s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 
    304305            s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 
     
    312313                p_details, p_values, cutoff, magnetic, effective_radius_type) 
    313314            if effective_radius_type > 0: 
     315                # Plug R_eff from p into S model (initial value and pd value) 
    314316                s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 
    315317            s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 
Note: See TracChangeset for help on using the changeset viewer.