Changeset 117c02a in sasmodels for sasmodels/product.py


Ignore:
Timestamp:
Sep 3, 2018 5:20:35 AM (6 years ago)
Author:
Torin Cooper-Bennun <torin.cooper-bennun@…>
Branches:
master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
c0131d44
Parents:
bad3093
Message:

cherry-picking lazy results implementation from beta_approx_lazy_results, beta_approx_new_R_eff branches

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/product.py

    r6d90684 r117c02a  
    1313from __future__ import print_function, division 
    1414 
     15from collections import OrderedDict 
     16 
    1517from copy import copy 
    1618import numpy as np  # type: ignore 
     
    2224# pylint: disable=unused-import 
    2325try: 
    24     from typing import Tuple 
     26    from typing import Tuple, Callable 
    2527except ImportError: 
    2628    pass 
     
    3739ER_ID = "radius_effective" 
    3840VF_ID = "volfraction" 
    39 BETA_DEFINITION = ("beta_mode", "", 0, [["P*S"],["P*(1+beta*(S-1))"]], "", 
     41BETA_DEFINITION = ("beta_mode", ["P*S", "P*(1+beta*(S-1))"], 0, (None, None), "", 
    4042                   "Structure factor dispersion calculation mode") 
     43def make_extra_pars(p_info): 
     44    pars = [] 
     45    if p_info.have_Fq: 
     46        par = Parameter("structure_factor_mode", ["P*S","P*(1+beta*(S-1))"], 0, (None, None), "", 
     47                        "Structure factor calculation") 
     48        pars.append(par) 
     49    return pars 
    4150 
    4251# TODO: core_shell_sphere model has suppressed the volume ratio calculation 
     
    7685    translate_name = dict((old.id, new.id) for old, new 
    7786                          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 
     87    combined_pars = p_pars.kernel_parameters + s_list + make_extra_pars(p_info) 
    8088    parameters = ParameterTable(combined_pars) 
    8189    parameters.max_pd = p_pars.max_pd + s_pars.max_pd 
     
    145153    return par 
    146154 
     155def _intermediates(P, S): 
     156    # type: (np.ndarray, np.ndarray) -> OrderedDict[str, np.ndarray] 
     157    """ 
     158    Returns intermediate results for standard product (P(Q)*S(Q)) 
     159    """ 
     160    return OrderedDict(( 
     161        ("P(Q)", P), 
     162        ("S(Q)", S), 
     163    )) 
     164 
     165def _intermediates_beta(F1, F2, S, scale, bg): 
     166    # type: (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray) -> OrderedDict[str, np.ndarray] 
     167    """ 
     168    Returns intermediate results for beta approximation-enabled product 
     169    """ 
     170    # TODO: 1. include calculated Q vector 
     171    # TODO: 2. consider implications if there are intermediate results in P(Q) 
     172    return OrderedDict(( 
     173        ("P(Q)", scale*F2), 
     174        ("S(Q)", S), 
     175        ("beta(Q)", F1**2 / F2), 
     176        ("S_eff(Q)", 1 + (F1**2 / F2)*(S-1)), 
     177        # ("I(Q)", scale*(F2 + (F1**2)*(S-1)) + bg), 
     178    )) 
     179 
    147180class ProductModel(KernelModel): 
    148181    def __init__(self, model_info, P, S): 
     
    270303            F1, F2, volume_avg = self.p_kernel.beta(p_details, p_values, cutoff, magnetic) 
    271304            combined_scale = scale*volfrac/volume_avg 
    272             # Define lazy results based on intermediate values. 
    273             # The return value for the calculation should be an ordered 
    274             # dictionary containing any result the user might want to see 
    275             # at the end of the calculation, including scalars, strings, 
    276             # and plottable data.  Don't want to build this structure during 
    277             # fits, only when displaying the final result (or a one-off 
    278             # computation which asks for it). 
    279             # Do not use the current hack of storing the intermediate values 
    280             # in self.results since that leads to awkward threading issues. 
    281             # Instead return the function along with the bundle of inputs. 
    282             # P and Q may themselves have intermediate results they want to 
    283             # include, such as A and B if P = A + B.  Might use this mechanism 
    284             # to return the computed effective radius as well. 
    285             #def lazy_results(Q, S, F1, F2, scale): 
    286             #    """ 
    287             #    beta = F1**2 / F2  # what about divide by zero errors? 
    288             #    return { 
    289             #        'P' : Data1D(Q, scale*F2), 
    290             #        'beta': Data1D(Q, beta), 
    291             #        'S' : Data1D(Q, S), 
    292             #        'Seff': Data1D(Q, 1 + beta*(S-1)), 
    293             #        'I' : Data1D(Q, scale*(F2 + (F1**2)*(S-1)) + background), 
    294             #    } 
    295             #lazy_pars = s_result, F1, F2, combined_scale 
    296             self.results = [F2*volfrac/volume_avg, s_result] 
     305 
     306            self.results = lambda: _intermediates_beta(F1, F2, s_result, volfrac/volume_avg, background) 
    297307            final_result = combined_scale*(F2 + (F1**2)*(s_result - 1)) + background 
     308 
    298309        else: 
    299310            p_result = self.p_kernel.Iq(p_details, p_values, cutoff, magnetic) 
    300             # remember the parts for plotting later 
    301             self.results = [p_result, s_result] 
     311 
     312            self.results = lambda: _intermediates(p_result, s_result) 
    302313            final_result = scale*(p_result*s_result) + background 
    303314 
Note: See TracChangeset for help on using the changeset viewer.