Changeset 6e7ba14 in sasmodels for sasmodels/product.py


Ignore:
Timestamp:
Aug 20, 2018 8:52:21 AM (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:
aa44a6a
Parents:
bad3093
Message:

allow for different forms of effective_radius

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/product.py

    r6d90684 r6e7ba14  
    3535#] 
    3636 
    37 ER_ID = "radius_effective" 
    38 VF_ID = "volfraction" 
    39 BETA_DEFINITION = ("beta_mode", "", 0, [["P*S"],["P*(1+beta*(S-1))"]], "", 
    40                    "Structure factor dispersion calculation mode") 
     37RADIUS_ID = "radius_effective" 
     38VOLFRAC_ID = "volfraction" 
     39def make_extra_pars(p_info): 
     40    pars = [] 
     41    if p_info.have_Fq: 
     42        par = Parameter("structure_factor_mode", "", 0, [["P*S","P*(1+beta*(S-1))"]], "", 
     43                        "Structure factor calculation") 
     44        pars.append(par) 
     45    if p_info.effective_radius_type is not None: 
     46        par = Parameter("radius_effective_mode", "", 0, 
     47                        [["unconstrained"] + p_info.effective_radius_type], 
     48                        "", "Effective radius calculation") 
     49        pars.append(par) 
     50    return pars 
    4151 
    4252# TODO: core_shell_sphere model has suppressed the volume ratio calculation 
     
    5262    # have any magnetic parameters 
    5363    if not len(s_info.parameters.kernel_parameters) >= 2: 
    54         raise TypeError("S needs {} and {} as its first parameters".format(ER_ID, VF_ID)) 
    55     if not s_info.parameters.kernel_parameters[0].id == ER_ID: 
    56         raise TypeError("S needs {} as first parameter".format(ER_ID)) 
    57     if not s_info.parameters.kernel_parameters[1].id == VF_ID: 
    58         raise TypeError("S needs {} as second parameter".format(VF_ID)) 
     64        raise TypeError("S needs {} and {} as its first parameters".format(RADIUS_ID, VOLFRAC_ID)) 
     65    if not s_info.parameters.kernel_parameters[0].id == RADIUS_ID: 
     66        raise TypeError("S needs {} as first parameter".format(RADIUS_ID)) 
     67    if not s_info.parameters.kernel_parameters[1].id == VOLFRAC_ID: 
     68        raise TypeError("S needs {} as second parameter".format(VOLFRAC_ID)) 
    5969    if not s_info.parameters.magnetism_index == []: 
    6070        raise TypeError("S should not have SLD parameters") 
     
    6272    s_id, s_name, s_pars = s_info.id, s_info.name, s_info.parameters 
    6373 
    64     # Create list of parameters for the combined model.  Skip the first 
    65     # parameter of S, which we verified above is effective radius.  If there 
     74    # Create list of parameters for the combined model.  If there 
    6675    # are any names in P that overlap with those in S, modify the name in S 
    6776    # to distinguish it. 
    6877    p_set = set(p.id for p in p_pars.kernel_parameters) 
    6978    s_list = [(_tag_parameter(par) if par.id in p_set else par) 
    70               for par in s_pars.kernel_parameters[1:]] 
     79              for par in s_pars.kernel_parameters] 
    7180    # Check if still a collision after renaming.  This could happen if for 
    7281    # example S has volfrac and P has both volfrac and volfrac_S. 
     
    7483        raise TypeError("name collision: P has P.name and P.name_S while S has S.name") 
    7584 
     85    # make sure effective radius is not a polydisperse parameter in product 
     86    s_list[0] = copy(s_list[0]) 
     87    s_list[0].polydisperse = False 
     88 
    7689    translate_name = dict((old.id, new.id) for old, new 
    77                           in zip(s_pars.kernel_parameters[1:], s_list)) 
    78     beta = [Parameter(*BETA_DEFINITION)] if p_info.have_Fq else [] 
    79     combined_pars = p_pars.kernel_parameters + s_list + beta 
     90                          in zip(s_pars.kernel_parameters, s_list)) 
     91    combined_pars = p_pars.kernel_parameters + s_list + make_extra_pars(p_info) 
    8092    parameters = ParameterTable(combined_pars) 
    8193    parameters.max_pd = p_pars.max_pd + s_pars.max_pd 
    8294    def random(): 
    8395        combined_pars = p_info.random() 
    84         s_names = set(par.id for par in s_pars.kernel_parameters[1:]) 
     96        s_names = set(par.id for par in s_pars.kernel_parameters) 
    8597        combined_pars.update((translate_name[k], v) 
    8698                             for k, v in s_info.random().items() 
     
    225237        p_values = np.hstack(p_values).astype(self.p_kernel.dtype) 
    226238 
    227         # Call ER and VR for P since these are needed for S. 
    228         p_er, p_vr = calc_er_vr(p_info, p_details, p_values) 
    229         s_vr = (volfrac/p_vr if p_vr != 0. else volfrac) 
    230         #print("volfrac:%g p_er:%g p_vr:%g s_vr:%g"%(volfrac,p_er,p_vr,s_vr)) 
    231  
    232239        # Construct the calling parameters for S. 
    233         # The  effective radius is not in the combined parameter list, so 
    234         # the number of 'S' parameters is one less than expected.  The 
    235         # computed effective radius needs to be added into the weights 
    236         # vector, especially since it is a polydisperse parameter in the 
    237         # stand-alone structure factor models.  We will added it at the 
    238         # end so the remaining offsets don't need to change. 
    239         s_npars = s_info.parameters.npars-1 
     240        s_npars = s_info.parameters.npars 
    240241        s_length = call_details.length[p_npars:p_npars+s_npars] 
    241242        s_offset = call_details.offset[p_npars:p_npars+s_npars] 
     
    243244        s_offset = np.hstack((nweights, s_offset)) 
    244245        s_details = make_details(s_info, s_length, s_offset, nweights+1) 
    245         v, w = weights[:nweights], weights[nweights:] 
    246246        s_values = [ 
    247             # scale=1, background=0, radius_effective=p_er, volfraction=s_vr 
    248             [1., 0., p_er, s_vr], 
    249             # structure factor parameters start after scale, background and 
    250             # all the form factor parameters.  Skip the volfraction parameter 
    251             # as well, since it is computed elsewhere, and go to the end of the 
    252             # parameter list. 
    253             values[2+p_npars+1:2+p_npars+s_npars], 
    254             # no magnetism parameters to include for S 
    255             # add er into the (value, weights) pairs 
    256             v, [p_er], w, [1.0] 
     247            # scale=1, background=0, 
     248            [1., 0.], 
     249            values[2+p_npars:2+p_npars+s_npars], 
     250            weights, 
    257251        ] 
    258252        spacer = (32 - sum(len(v) for v in s_values)%32)%32 
     
    261255 
    262256        # beta mode is the first parameter after the structure factor pars 
    263         beta_index = 2+p_npars+s_npars 
    264         beta_mode = values[beta_index] 
     257        extra_offset = 2+p_npars+s_npars 
     258        if p_info.have_Fq: 
     259            beta_mode = values[extra_offset] 
     260            extra_offset += 1 
     261        else: 
     262            beta_mode = 0 
     263        if p_info.effective_radius_type is not None: 
     264            effective_radius_type = values[extra_offset] 
     265            extra_offset += 1 
     266        else: 
     267            effective_radius_type = 0 
    265268 
    266269        # Call the kernels 
    267         s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 
    268270        scale, background = values[0], values[1] 
    269271        if beta_mode: 
    270             F1, F2, volume_avg = self.p_kernel.beta(p_details, p_values, cutoff, magnetic) 
     272            F1, F2, volume_avg, effective_radius = self.p_kernel.beta( 
     273                p_details, p_values, cutoff, magnetic, effective_radius_type) 
     274            if effective_radius_type > 0: 
     275                s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 
     276            s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 
    271277            combined_scale = scale*volfrac/volume_avg 
    272278            # Define lazy results based on intermediate values. 
     
    297303            final_result = combined_scale*(F2 + (F1**2)*(s_result - 1)) + background 
    298304        else: 
    299             p_result = self.p_kernel.Iq(p_details, p_values, cutoff, magnetic) 
     305            p_result, effective_radius = self.p_kernel.Pq_Reff( 
     306                p_details, p_values, cutoff, magnetic, effective_radius_type) 
     307            if effective_radius_type > 0: 
     308                s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 
     309            s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 
    300310            # remember the parts for plotting later 
    301311            self.results = [p_result, s_result] 
Note: See TracChangeset for help on using the changeset viewer.