Changeset 4bfd277 in sasmodels


Ignore:
Timestamp:
Apr 8, 2016 10:11:16 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:
2afc26d
Parents:
d2fc9a4
Message:

support ER/VR calls with vector parameters

Location:
sasmodels
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/details.py

    rd2fc9a4 r4bfd277  
    144144            return [np.asarray(v) for v in args] 
    145145 
    146 def dispersion_mesh(pars): 
     146def dispersion_mesh(model_info, pars): 
    147147    """ 
    148148    Create a mesh grid of dispersion parameters and weights. 
     
    154154    value, weight = zip(*pars) 
    155155    weight = [w if w else [1.] for w in weight] 
    156     value = [v.flatten() for v in meshgrid(*value)] 
    157156    weight = np.vstack([v.flatten() for v in meshgrid(*weight)]) 
    158157    weight = np.prod(weight, axis=0) 
     158    value = [v.flatten() for v in meshgrid(*value)] 
     159    lengths = [par.length for par in model_info.parameters.kernel_parameters 
     160               if par.type == 'volume'] 
     161    if any(n > 1 for n in lengths): 
     162        pars = [] 
     163        offset = 0 
     164        for n in lengths: 
     165            pars.append(np.vstack(value[offset:offset+n]) if n > 1 else value[offset]) 
     166            offset += n 
     167        value = pars 
    159168    return value, weight 
    160169 
  • sasmodels/kernelpy.py

    r6d6508e r4bfd277  
    1010from numpy import pi, cos 
    1111 
     12from . import details 
    1213from .generate import F64 
    1314 
     
    145146 
    146147    def __call__(self, call_details, weights, values, cutoff): 
    147         # type: (.generate.CallDetails, np.ndarray, np.ndarray, float) -> np.ndarray 
     148        assert isinstance(call_details, details.CallDetails) 
    148149        res = _loops(self._parameter_vector, self._form, self._volume, 
    149150                     self.q_input.nq, call_details, weights, values, cutoff) 
     
    160161           form_volume, # type: Callable[[], float] 
    161162           nq,          # type: int 
    162            call_details,# type: .generate.CallDetails 
     163           call_details,# type: details.CallDetails 
    163164           weights,     # type: np.ndarray 
    164165           values,      # type: np.ndarray 
     
    205206                this_offset = call_details.par_offset[par] 
    206207                block_size = 1 
    207                 for bit in xrange(32): 
     208                for bit in range(len(pd_offset)): 
    208209                    if coord&1: 
    209210                        this_offset += block_size * pd_index[bit] 
     
    245246 
    246247 
     248def _create_default_functions(model_info): 
     249    """ 
     250    Autogenerate missing functions, such as Iqxy from Iq. 
     251 
     252    This only works for Iqxy when Iq is written in python. :func:`make_source` 
     253    performs a similar role for Iq written in C.  This also vectorizes 
     254    any functions that are not already marked as vectorized. 
     255    """ 
     256    _create_vector_Iq(model_info) 
     257    _create_vector_Iqxy(model_info)  # call create_vector_Iq() first 
     258 
    247259 
    248260def _create_vector_Iq(model_info): 
     
    252264    Iq = model_info.Iq 
    253265    if callable(Iq) and not getattr(Iq, 'vectorized', False): 
     266        #print("vectorizing Iq") 
    254267        def vector_Iq(q, *args): 
    255268            """ 
     
    265278    """ 
    266279    Iq, Iqxy = model_info.Iq, model_info.Iqxy 
    267     if callable(Iqxy) and not getattr(Iqxy, 'vectorized', False): 
    268         def vector_Iqxy(qx, qy, *args): 
    269             """ 
    270             Vectorized 2D kernel. 
    271             """ 
    272             return np.array([Iqxy(qxi, qyi, *args) for qxi, qyi in zip(qx, qy)]) 
    273         vector_Iqxy.vectorized = True 
    274         model_info.Iqxy = vector_Iqxy 
     280    if callable(Iqxy): 
     281        if not getattr(Iqxy, 'vectorized', False): 
     282            #print("vectorizing Iqxy") 
     283            def vector_Iqxy(qx, qy, *args): 
     284                """ 
     285                Vectorized 2D kernel. 
     286                """ 
     287                return np.array([Iqxy(qxi, qyi, *args) for qxi, qyi in zip(qx, qy)]) 
     288            vector_Iqxy.vectorized = True 
     289            model_info.Iqxy = vector_Iqxy 
    275290    elif callable(Iq): 
     291        #print("defaulting Iqxy") 
    276292        # Iq is vectorized because create_vector_Iq was already called. 
    277293        def default_Iqxy(qx, qy, *args): 
     
    283299        model_info.Iqxy = default_Iqxy 
    284300 
    285 def _create_default_functions(model_info): 
    286     """ 
    287     Autogenerate missing functions, such as Iqxy from Iq. 
    288  
    289     This only works for Iqxy when Iq is written in python. :func:`make_source` 
    290     performs a similar role for Iq written in C.  This also vectorizes 
    291     any functions that are not already marked as vectorized. 
    292     """ 
    293     _create_vector_Iq(model_info) 
    294     _create_vector_Iqxy(model_info)  # call create_vector_Iq() first 
    295  
  • sasmodels/model_test.py

    r6d6508e r4bfd277  
    5656from .direct_model import call_kernel, get_weights 
    5757from .exception import annotate_exception 
    58  
    59  
    60 def call_ER(model_info, values): 
     58from .modelinfo import expand_pars 
     59 
     60def call_ER(model_info, pars): 
    6161    """ 
    6262    Call the model ER function using *values*. *model_info* is either 
     
    6767        return 1.0 
    6868    else: 
    69         vol_pars = [get_weights(parameter, values) 
    70                     for parameter in model_info.parameters.call_parameters 
    71                     if parameter.type == 'volume'] 
    72         value, weight = dispersion_mesh(vol_pars) 
     69        value, weight = _vol_pars(model_info, pars) 
    7370        individual_radii = model_info.ER(*value) 
    7471        return np.sum(weight*individual_radii) / np.sum(weight) 
    7572 
    76 def call_VR(model_info, values): 
     73def call_VR(model_info, pars): 
    7774    """ 
    7875    Call the model VR function using *pars*. 
     
    8380        return 1.0 
    8481    else: 
    85         vol_pars = [get_weights(parameter, values) 
    86                     for parameter in model_info.parameters.call_parameters 
    87                     if parameter.type == 'volume'] 
    88         value, weight = dispersion_mesh(vol_pars) 
     82        value, weight = _vol_pars(model_info, pars) 
    8983        whole, part = model_info.VR(*value) 
    9084        return np.sum(weight*part)/np.sum(weight*whole) 
     85 
     86def _vol_pars(model_info, pars): 
     87    vol_pars = [get_weights(p, pars) 
     88                for p in model_info.parameters.call_parameters 
     89                if p.type == 'volume'] 
     90    value, weight = dispersion_mesh(model_info, vol_pars) 
     91    return value, weight 
    9192 
    9293 
     
    175176            self.dtype = dtype 
    176177 
    177             setattr(self, test_method_name, self._runTest) 
     178            setattr(self, test_method_name, self.run_all) 
    178179            unittest.TestCase.__init__(self, test_method_name) 
    179180 
    180         def _runTest(self): 
     181        def run_all(self): 
    181182            smoke_tests = [ 
    182183                [{}, 0.1, None], 
     
    191192                                    platform=self.platform) 
    192193                for test in smoke_tests + tests: 
    193                     self._run_one_test(model, test) 
     194                    self.run_one(model, test) 
    194195 
    195196                if not tests and self.platform == "dll": 
     
    205206                raise 
    206207 
    207         def _run_one_test(self, model, test): 
     208        def run_one(self, model, test): 
    208209            pars, x, y = test 
     210            pars = expand_pars(self.info.parameters, pars) 
    209211 
    210212            if not isinstance(y, list): 
     
    229231                actual = call_kernel(kernel, pars) 
    230232 
    231             self.assertGreater(len(actual), 0) 
     233            self.assertTrue(len(actual) > 0) 
    232234            self.assertEqual(len(y), len(actual)) 
    233235 
     
    311313    tests = make_suite(['opencl', 'dll'], ['all']) 
    312314    for test_i in tests: 
    313         yield test_i._runTest 
     315        yield test_i.run_all 
    314316 
    315317 
  • sasmodels/modelinfo.py

    r6d6508e r4bfd277  
    117117 
    118118 
    119 def make_demo_pars(partable, demo): 
     119def expand_pars(partable, pars): 
    120120    """ 
    121121    Create demo parameter set from key-value pairs. 
    122122 
    123     *demo* are the key-value pairs to use for the demo parameters.  Any 
    124     parameters not specified in *demo* are set from the *partable* defaults. 
    125  
    126     If *demo* references vector fields, such as thickness[n], then support 
     123    *pars* are the key-value pairs to use for the parameters.  Any 
     124    parameters not specified in *pars* are set from the *partable* defaults. 
     125 
     126    If *pars* references vector fields, such as thickness[n], then support 
    127127    different ways of assigning the demo values, including assigning a 
    128128    specific value (e.g., thickness3=50.0), assigning a new value to all 
    129129    (e.g., thickness=50.0) or assigning values using list notation. 
    130130    """ 
    131     if demo is None: 
     131    if pars is None: 
    132132        result = partable.defaults 
    133133    else: 
    134         pars = dict((p.id, p) for p in partable.kernel_parameters) 
     134        lookup = dict((p.id, p) for p in partable.kernel_parameters) 
    135135        result = partable.defaults.copy() 
    136         vectors = dict((name,value) for name,value in demo.items() 
    137                        if name in pars and pars[name].length > 1) 
     136        vectors = dict((name,value) for name,value in pars.items() 
     137                       if name in lookup and lookup[name].length > 1) 
    138138        if vectors: 
    139             scalars = dict((name, value) for name, value in demo.items() 
    140                            if name not in pars or pars[name].length == 1) 
     139            scalars = dict((name, value) for name, value in pars.items() 
     140                           if name not in lookup or lookup[name].length == 1) 
    141141            for name, value in vectors.items(): 
    142142                if np.isscalar(value): 
    143143                    # support for the form 
    144                     #    demo(thickness=0, thickness2=50) 
    145                     for k in range(1, pars[name].length+1): 
     144                    #    dict(thickness=0, thickness2=50) 
     145                    for k in range(1, lookup[name].length+1): 
    146146                        key = name+str(k) 
    147147                        if key not in scalars: 
     
    149149                else: 
    150150                    # supoprt for the form 
    151                     #    demo(thickness=[20,10,3]) 
     151                    #    dict(thickness=[20,10,3]) 
    152152                    for (k,v) in enumerate(value): 
    153153                        scalars[name+str(k)] = v 
    154154            result.update(scalars) 
    155155        else: 
    156             result.update(demo) 
     156            result.update(pars) 
    157157 
    158158    return result 
     
    537537    #print("make parameter table", kernel_module.parameters) 
    538538    parameters = make_parameter_table(kernel_module.parameters) 
    539     demo = make_demo_pars(parameters, getattr(kernel_module, 'demo', None)) 
     539    demo = expand_pars(parameters, getattr(kernel_module, 'demo', None)) 
    540540    filename = abspath(kernel_module.__file__) 
    541541    kernel_id = splitext(basename(filename))[0] 
  • sasmodels/sasview_model.py

    r6d6508e r4bfd277  
    8383    Sasview wrapper for opencl/ctypes model. 
    8484    """ 
    85     _model_info = {} 
     85    _model_info = None # type: modelinfo.ModelInfo 
    8686    def __init__(self): 
    8787        self._model = None 
     
    353353        pairs = [self._get_weights(p) 
    354354                 for p in self._model_info.parameters.call_parameters] 
    355         call_details, weights, values = details.build_details(kernel, pairs) 
    356         result = kernel(call_details, weights, values, cutoff=self.cutoff) 
     355        call_details, weight, value = details.build_details(kernel, pairs) 
     356        result = kernel(call_details, weight, value, cutoff=self.cutoff) 
    357357        kernel.q_input.release() 
    358358        kernel.release() 
     
    365365        :return: the value of the effective radius 
    366366        """ 
    367         if model_info.ER is None: 
     367        if self._model_info.ER is None: 
    368368            return 1.0 
    369369        else: 
    370             values, weights = self._dispersion_mesh() 
    371             fv = model_info.ER(*values) 
     370            value, weight = self._dispersion_mesh() 
     371            fv = self._model_info.ER(*value) 
    372372            #print(values[0].shape, weights.shape, fv.shape) 
    373             return np.sum(weights * fv) / np.sum(weights) 
     373            return np.sum(weight * fv) / np.sum(weight) 
    374374 
    375375    def calculate_VR(self): 
     
    379379        :return: the value of the volf ratio 
    380380        """ 
    381         if model_info.VR is None: 
     381        if self._model_info.VR is None: 
    382382            return 1.0 
    383383        else: 
    384             values, weights = self._dispersion_mesh() 
    385             whole, part = model_info.VR(*values) 
    386             return np.sum(weights * part) / np.sum(weights * whole) 
     384            value, weight = self._dispersion_mesh() 
     385            whole, part = self._model_info.VR(*value) 
     386            return np.sum(weight * part) / np.sum(weight * whole) 
    387387 
    388388    def set_dispersion(self, parameter, dispersion): 
     
    422422        parameter set in the vector. 
    423423        """ 
    424         pars = self._model_info.partype['volume'] 
    425         return details.dispersion_mesh([self._get_weights(p) for p in pars]) 
     424        pars = [self._get_weights(p) 
     425                for p in self._model_info.parameters.call_parameters 
     426                if p.type == 'volume'] 
     427        return details.dispersion_mesh(self._model_info, pars) 
    426428 
    427429    def _get_weights(self, par): 
Note: See TracChangeset for help on using the changeset viewer.