Changes in / [153f8f6:aa8c6e0] in sasmodels


Ignore:
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • doc/guide/plugin.rst

    r81751c2 r81751c2  
    744744    erf, erfc, tgamma, lgamma:  **do not use** 
    745745        Special functions that should be part of the standard, but are missing 
    746         or inaccurate on some platforms. Use sas_erf, sas_erfc and sas_gamma 
    747         instead (see below). Note: lgamma(x) has not yet been tested. 
     746        or inaccurate on some platforms. Use sas_erf, sas_erfc, sas_gamma 
     747        and sas_lgamma instead (see below). 
    748748 
    749749Some non-standard constants and functions are also provided: 
     
    812812        Gamma function sas_gamma\ $(x) = \Gamma(x)$. 
    813813 
    814         The standard math function, tgamma(x) is unstable for $x < 1$ 
     814        The standard math function, tgamma(x), is unstable for $x < 1$ 
    815815        on some platforms. 
    816816 
    817817        :code:`source = ["lib/sas_gamma.c", ...]` 
    818818        (`sas_gamma.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_gamma.c>`_) 
     819 
     820    sas_gammaln(x): 
     821        log gamma function sas_gammaln\ $(x) = \log \Gamma(|x|)$. 
     822 
     823        The standard math function, lgamma(x), is incorrect for single 
     824        precision on some platforms. 
     825 
     826        :code:`source = ["lib/sas_gammainc.c", ...]` 
     827        (`sas_gammainc.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_gammainc.c>`_) 
     828 
     829    sas_gammainc(a, x), sas_gammaincc(a, x): 
     830        Incomplete gamma function 
     831        sas_gammainc\ $(a, x) = \int_0^x t^{a-1}e^{-t}\,dt / \Gamma(a)$ 
     832        and complementary incomplete gamma function 
     833        sas_gammaincc\ $(a, x) = \int_x^\infty t^{a-1}e^{-t}\,dt / \Gamma(a)$ 
     834 
     835        :code:`source = ["lib/sas_gammainc.c", ...]` 
     836        (`sas_gammainc.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_gammainc.c>`_) 
    819837 
    820838    sas_erf(x), sas_erfc(x): 
     
    854872        If $n$ = 0 or 1, it uses sas_J0($x$) or sas_J1($x$), respectively. 
    855873 
     874        Warning: JN(n,x) can be very inaccurate (0.1%) for x not in [0.1, 100]. 
     875 
    856876        The standard math function jn(n, x) is not available on all platforms. 
    857877 
     
    862882        Sine integral Si\ $(x) = \int_0^x \tfrac{\sin t}{t}\,dt$. 
    863883 
     884        Warning: Si(x) can be very inaccurate (0.1%) for x in [0.1, 100]. 
     885 
    864886        This function uses Taylor series for small and large arguments: 
    865887 
    866         For large arguments, 
     888        For large arguments use the following Taylor series, 
    867889 
    868890        .. math:: 
     
    872894             - \frac{\sin(x)}{x}\left(\frac{1}{x} - \frac{3!}{x^3} + \frac{5!}{x^5} - \frac{7!}{x^7}\right) 
    873895 
    874         For small arguments, 
     896        For small arguments , 
    875897 
    876898        .. math:: 
  • explore/precision.py

    ree60aa7 rfba9ca0  
    9595            neg:    [-100,100] 
    9696 
     97        For arbitrary range use "start:stop:steps:scale" where scale is 
     98        one of log, lin, or linear. 
     99 
    97100        *diff* is "relative", "absolute" or "none" 
    98101 
     
    102105        linear = not xrange.startswith("log") 
    103106        if xrange == "zoom": 
    104             lin_min, lin_max, lin_steps = 1000, 1010, 2000 
     107            start, stop, steps = 1000, 1010, 2000 
    105108        elif xrange == "neg": 
    106             lin_min, lin_max, lin_steps = -100.1, 100.1, 2000 
     109            start, stop, steps = -100.1, 100.1, 2000 
    107110        elif xrange == "linear": 
    108             lin_min, lin_max, lin_steps = 1, 1000, 2000 
    109             lin_min, lin_max, lin_steps = 0.001, 2, 2000 
     111            start, stop, steps = 1, 1000, 2000 
     112            start, stop, steps = 0.001, 2, 2000 
    110113        elif xrange == "log": 
    111             log_min, log_max, log_steps = -3, 5, 400 
     114            start, stop, steps = -3, 5, 400 
    112115        elif xrange == "logq": 
    113             log_min, log_max, log_steps = -4, 1, 400 
     116            start, stop, steps = -4, 1, 400 
     117        elif ':' in xrange: 
     118            parts = xrange.split(':') 
     119            linear = parts[3] != "log" if len(parts) == 4 else True 
     120            steps = int(parts[2]) if len(parts) > 2 else 400 
     121            start = float(parts[0]) 
     122            stop = float(parts[1]) 
     123 
    114124        else: 
    115125            raise ValueError("unknown range "+xrange) 
     
    121131            # value to x in the given precision. 
    122132            if linear: 
    123                 lin_min = max(lin_min, self.limits[0]) 
    124                 lin_max = min(lin_max, self.limits[1]) 
    125                 qrf = np.linspace(lin_min, lin_max, lin_steps, dtype='single') 
    126                 #qrf = np.linspace(lin_min, lin_max, lin_steps, dtype='double') 
     133                start = max(start, self.limits[0]) 
     134                stop = min(stop, self.limits[1]) 
     135                qrf = np.linspace(start, stop, steps, dtype='single') 
     136                #qrf = np.linspace(start, stop, steps, dtype='double') 
    127137                qr = [mp.mpf(float(v)) for v in qrf] 
    128                 #qr = mp.linspace(lin_min, lin_max, lin_steps) 
     138                #qr = mp.linspace(start, stop, steps) 
    129139            else: 
    130                 log_min = np.log10(max(10**log_min, self.limits[0])) 
    131                 log_max = np.log10(min(10**log_max, self.limits[1])) 
    132                 qrf = np.logspace(log_min, log_max, log_steps, dtype='single') 
    133                 #qrf = np.logspace(log_min, log_max, log_steps, dtype='double') 
     140                start = np.log10(max(10**start, self.limits[0])) 
     141                stop = np.log10(min(10**stop, self.limits[1])) 
     142                qrf = np.logspace(start, stop, steps, dtype='single') 
     143                #qrf = np.logspace(start, stop, steps, dtype='double') 
    134144                qr = [mp.mpf(float(v)) for v in qrf] 
    135                 #qr = [10**v for v in mp.linspace(log_min, log_max, log_steps)] 
     145                #qr = [10**v for v in mp.linspace(start, stop, steps)] 
    136146 
    137147        target = self.call_mpmath(qr, bits=500) 
     
    176186    """ 
    177187    if diff == "relative": 
    178         err = np.array([abs((t-a)/t) for t, a in zip(target, actual)], 'd') 
     188        err = np.array([(abs((t-a)/t) if t != 0 else a) for t, a in zip(target, actual)], 'd') 
    179189        #err = np.clip(err, 0, 1) 
    180190        pylab.loglog(x, err, '-', label=label) 
     
    197207    return model_info 
    198208 
     209# Hack to allow second parameter A in two parameter functions 
     210A = 1 
     211def parse_extra_pars(): 
     212    global A 
     213 
     214    A_str = str(A) 
     215    pop = [] 
     216    for k, v in enumerate(sys.argv[1:]): 
     217        if v.startswith("A="): 
     218            A_str = v[2:] 
     219            pop.append(k+1) 
     220    if pop: 
     221        sys.argv = [v for k, v in enumerate(sys.argv) if k not in pop] 
     222        A = float(A_str) 
     223 
     224parse_extra_pars() 
     225 
    199226 
    200227# =============== FUNCTION DEFINITIONS ================ 
     
    297324    ocl_function=make_ocl("return sas_gamma(q);", "sas_gamma", ["lib/sas_gamma.c"]), 
    298325    limits=(-3.1, 10), 
     326) 
     327add_function( 
     328    name="gammaln(x)", 
     329    mp_function=mp.loggamma, 
     330    np_function=scipy.special.gammaln, 
     331    ocl_function=make_ocl("return sas_gammaln(q);", "sas_gammaln", ["lib/sas_gammainc.c"]), 
     332    #ocl_function=make_ocl("return lgamma(q);", "sas_gammaln"), 
     333) 
     334add_function( 
     335    name="gammainc(x)", 
     336    mp_function=lambda x, a=A: mp.gammainc(a, a=0, b=x)/mp.gamma(a), 
     337    np_function=lambda x, a=A: scipy.special.gammainc(a, x), 
     338    ocl_function=make_ocl("return sas_gammainc(%.15g,q);"%A, "sas_gammainc", ["lib/sas_gammainc.c"]), 
     339) 
     340add_function( 
     341    name="gammaincc(x)", 
     342    mp_function=lambda x, a=A: mp.gammainc(a, a=x, b=mp.inf)/mp.gamma(a), 
     343    np_function=lambda x, a=A: scipy.special.gammaincc(a, x), 
     344    ocl_function=make_ocl("return sas_gammaincc(%.15g,q);"%A, "sas_gammaincc", ["lib/sas_gammainc.c"]), 
    299345) 
    300346add_function( 
     
    465511lanczos_gamma = """\ 
    466512    const double coeff[] = { 
    467             76.18009172947146,     -86.50532032941677, 
    468             24.01409824083091,     -1.231739572450155, 
     513            76.18009172947146, -86.50532032941677, 
     514            24.01409824083091, -1.231739572450155, 
    469515            0.1208650973866179e-2,-0.5395239384953e-5 
    470516            }; 
     
    477523""" 
    478524add_function( 
    479     name="log gamma(x)", 
     525    name="loggamma(x)", 
    480526    mp_function=mp.loggamma, 
    481527    np_function=scipy.special.gammaln, 
     
    601647 
    602648ALL_FUNCTIONS = set(FUNCTIONS.keys()) 
    603 ALL_FUNCTIONS.discard("loggamma")  # OCL version not ready yet 
     649ALL_FUNCTIONS.discard("loggamma")  # use cephes-based gammaln instead 
    604650ALL_FUNCTIONS.discard("3j1/x:taylor") 
    605651ALL_FUNCTIONS.discard("3j1/x:trig") 
     
    617663    -r indicates that the relative error should be plotted (default), 
    618664    -x<range> indicates the steps in x, where <range> is one of the following 
    619       log indicates log stepping in [10^-3, 10^5] (default) 
    620       logq indicates log stepping in [10^-4, 10^1] 
    621       linear indicates linear stepping in [1, 1000] 
    622       zoom indicates linear stepping in [1000, 1010] 
    623       neg indicates linear stepping in [-100.1, 100.1] 
    624 and name is "all" or one of: 
     665        log indicates log stepping in [10^-3, 10^5] (default) 
     666        logq indicates log stepping in [10^-4, 10^1] 
     667        linear indicates linear stepping in [1, 1000] 
     668        zoom indicates linear stepping in [1000, 1010] 
     669        neg indicates linear stepping in [-100.1, 100.1] 
     670        start:stop:n[:stepping] indicates an n-step plot in [start, stop] 
     671            or [10^start, 10^stop] if stepping is "log" (default n=400) 
     672Some functions (notably gammainc/gammaincc) have an additional parameter A 
     673which can be set from the command line as A=value.  Default is A=1. 
     674 
     675Name is one of: 
    625676    """+names) 
    626677    sys.exit(1) 
  • sasmodels/kernelpy.py

    re44432d re44432d  
    4242        self.info = model_info 
    4343        self.dtype = np.dtype('d') 
     44        logger.info("make python model " + self.info.name) 
    4445 
    4546    def make_kernel(self, q_vectors): 
  • sasmodels/model_test.py

    r81751c2 r81751c2  
    4747import sys 
    4848import unittest 
     49import traceback 
    4950 
    5051try: 
     
    7677# pylint: enable=unused-import 
    7778 
    78  
    7979def make_suite(loaders, models): 
    8080    # type: (List[str], List[str]) -> unittest.TestSuite 
     
    8787    *models* is the list of models to test, or *["all"]* to test all models. 
    8888    """ 
    89     ModelTestCase = _hide_model_case_from_nose() 
    9089    suite = unittest.TestSuite() 
    9190 
     
    9695        skip = [] 
    9796    for model_name in models: 
    98         if model_name in skip: 
    99             continue 
    100         model_info = load_model_info(model_name) 
    101  
    102         #print('------') 
    103         #print('found tests in', model_name) 
    104         #print('------') 
    105  
    106         # if ispy then use the dll loader to call pykernel 
    107         # don't try to call cl kernel since it will not be 
    108         # available in some environmentes. 
    109         is_py = callable(model_info.Iq) 
    110  
    111         # Some OpenCL drivers seem to be flaky, and are not producing the 
    112         # expected result.  Since we don't have known test values yet for 
    113         # all of our models, we are instead going to compare the results 
    114         # for the 'smoke test' (that is, evaluation at q=0.1 for the default 
    115         # parameters just to see that the model runs to completion) between 
    116         # the OpenCL and the DLL.  To do this, we define a 'stash' which is 
    117         # shared between OpenCL and DLL tests.  This is just a list.  If the 
    118         # list is empty (which it will be when DLL runs, if the DLL runs 
    119         # first), then the results are appended to the list.  If the list 
    120         # is not empty (which it will be when OpenCL runs second), the results 
    121         # are compared to the results stored in the first element of the list. 
    122         # This is a horrible stateful hack which only makes sense because the 
    123         # test suite is thrown away after being run once. 
    124         stash = [] 
    125  
    126         if is_py:  # kernel implemented in python 
    127             test_name = "%s-python"%model_name 
    128             test_method_name = "test_%s_python" % model_info.id 
     97        if model_name not in skip: 
     98            model_info = load_model_info(model_name) 
     99            _add_model_to_suite(loaders, suite, model_info) 
     100 
     101    return suite 
     102 
     103def _add_model_to_suite(loaders, suite, model_info): 
     104    ModelTestCase = _hide_model_case_from_nose() 
     105 
     106    #print('------') 
     107    #print('found tests in', model_name) 
     108    #print('------') 
     109 
     110    # if ispy then use the dll loader to call pykernel 
     111    # don't try to call cl kernel since it will not be 
     112    # available in some environmentes. 
     113    is_py = callable(model_info.Iq) 
     114 
     115    # Some OpenCL drivers seem to be flaky, and are not producing the 
     116    # expected result.  Since we don't have known test values yet for 
     117    # all of our models, we are instead going to compare the results 
     118    # for the 'smoke test' (that is, evaluation at q=0.1 for the default 
     119    # parameters just to see that the model runs to completion) between 
     120    # the OpenCL and the DLL.  To do this, we define a 'stash' which is 
     121    # shared between OpenCL and DLL tests.  This is just a list.  If the 
     122    # list is empty (which it will be when DLL runs, if the DLL runs 
     123    # first), then the results are appended to the list.  If the list 
     124    # is not empty (which it will be when OpenCL runs second), the results 
     125    # are compared to the results stored in the first element of the list. 
     126    # This is a horrible stateful hack which only makes sense because the 
     127    # test suite is thrown away after being run once. 
     128    stash = [] 
     129 
     130    if is_py:  # kernel implemented in python 
     131        test_name = "%s-python"%model_info.name 
     132        test_method_name = "test_%s_python" % model_info.id 
     133        test = ModelTestCase(test_name, model_info, 
     134                                test_method_name, 
     135                                platform="dll",  # so that 
     136                                dtype="double", 
     137                                stash=stash) 
     138        suite.addTest(test) 
     139    else:   # kernel implemented in C 
     140 
     141        # test using dll if desired 
     142        if 'dll' in loaders or not use_opencl(): 
     143            test_name = "%s-dll"%model_info.name 
     144            test_method_name = "test_%s_dll" % model_info.id 
    129145            test = ModelTestCase(test_name, model_info, 
    130                                  test_method_name, 
    131                                  platform="dll",  # so that 
    132                                  dtype="double", 
    133                                  stash=stash) 
     146                                    test_method_name, 
     147                                    platform="dll", 
     148                                    dtype="double", 
     149                                    stash=stash) 
    134150            suite.addTest(test) 
    135         else:   # kernel implemented in C 
    136  
    137             # test using dll if desired 
    138             if 'dll' in loaders: 
    139                 test_name = "%s-dll"%model_name 
    140                 test_method_name = "test_%s_dll" % model_info.id 
    141                 test = ModelTestCase(test_name, model_info, 
    142                                      test_method_name, 
    143                                      platform="dll", 
    144                                      dtype="double", 
    145                                      stash=stash) 
    146                 suite.addTest(test) 
    147  
    148             # test using opencl if desired and available 
    149             if 'opencl' in loaders and use_opencl(): 
    150                 test_name = "%s-opencl"%model_name 
    151                 test_method_name = "test_%s_opencl" % model_info.id 
    152                 # Using dtype=None so that the models that are only 
    153                 # correct for double precision are not tested using 
    154                 # single precision.  The choice is determined by the 
    155                 # presence of *single=False* in the model file. 
    156                 test = ModelTestCase(test_name, model_info, 
    157                                      test_method_name, 
    158                                      platform="ocl", dtype=None, 
    159                                      stash=stash) 
    160                 #print("defining", test_name) 
    161                 suite.addTest(test) 
    162  
    163             # test using cuda if desired and available 
    164             if 'cuda' in loaders and use_cuda(): 
    165                 test_name = "%s-cuda"%model_name 
    166                 test_method_name = "test_%s_cuda" % model_info.id 
    167                 # Using dtype=None so that the models that are only 
    168                 # correct for double precision are not tested using 
    169                 # single precision.  The choice is determined by the 
    170                 # presence of *single=False* in the model file. 
    171                 test = ModelTestCase(test_name, model_info, 
    172                                      test_method_name, 
    173                                      platform="cuda", dtype=None, 
    174                                      stash=stash) 
    175                 #print("defining", test_name) 
    176                 suite.addTest(test) 
    177  
    178     return suite 
     151 
     152        # test using opencl if desired and available 
     153        if 'opencl' in loaders and use_opencl(): 
     154            test_name = "%s-opencl"%model_info.name 
     155            test_method_name = "test_%s_opencl" % model_info.id 
     156            # Using dtype=None so that the models that are only 
     157            # correct for double precision are not tested using 
     158            # single precision.  The choice is determined by the 
     159            # presence of *single=False* in the model file. 
     160            test = ModelTestCase(test_name, model_info, 
     161                                    test_method_name, 
     162                                    platform="ocl", dtype=None, 
     163                                    stash=stash) 
     164            #print("defining", test_name) 
     165            suite.addTest(test) 
     166 
     167        # test using cuda if desired and available 
     168        if 'cuda' in loaders and use_cuda(): 
     169            test_name = "%s-cuda"%model_name 
     170            test_method_name = "test_%s_cuda" % model_info.id 
     171            # Using dtype=None so that the models that are only 
     172            # correct for double precision are not tested using 
     173            # single precision.  The choice is determined by the 
     174            # presence of *single=False* in the model file. 
     175            test = ModelTestCase(test_name, model_info, 
     176                                    test_method_name, 
     177                                    platform="cuda", dtype=None, 
     178                                    stash=stash) 
     179            #print("defining", test_name) 
     180            suite.addTest(test) 
     181 
    179182 
    180183def _hide_model_case_from_nose(): 
     
    403406    return abs(target-actual)/shift < 1.5*10**-digits 
    404407 
    405 def run_one(model): 
    406     # type: (str) -> str 
    407     """ 
    408     Run the tests for a single model, printing the results to stdout. 
    409  
    410     *model* can by a python file, which is handy for checking user defined 
    411     plugin models. 
     408# CRUFT: old interface; should be deprecated and removed 
     409def run_one(model_name): 
     410    # msg = "use check_model(model_info) rather than run_one(model_name)" 
     411    # warnings.warn(msg, category=DeprecationWarning, stacklevel=2) 
     412    try: 
     413        model_info = load_model_info(model_name) 
     414    except Exception: 
     415        output = traceback.format_exc() 
     416        return output 
     417 
     418    success, output = check_model(model_info) 
     419    return output 
     420 
     421def check_model(model_info): 
     422    # type: (ModelInfo) -> str 
     423    """ 
     424    Run the tests for a single model, capturing the output. 
     425 
     426    Returns success status and the output string. 
    412427    """ 
    413428    # Note that running main() directly did not work from within the 
     
    423438 
    424439    # Build a test suite containing just the model 
    425     loader = 'opencl' if use_opencl() else 'cuda' if use_cuda() else 'dll' 
    426     models = [model] 
    427     try: 
    428         suite = make_suite([loader], models) 
    429     except Exception: 
    430         import traceback 
    431         stream.writeln(traceback.format_exc()) 
    432         return 
     440    loaders = ['opencl' if use_opencl() else 'cuda' if use_cuda() else 'dll'] 
     441    suite = unittest.TestSuite() 
     442    _add_model_to_suite(loaders, suite, model_info) 
    433443 
    434444    # Warn if there are no user defined tests. 
     
    445455    for test in suite: 
    446456        if not test.info.tests: 
    447             stream.writeln("Note: %s has no user defined tests."%model) 
     457            stream.writeln("Note: %s has no user defined tests."%model_info.name) 
    448458        break 
    449459    else: 
     
    461471    output = stream.getvalue() 
    462472    stream.close() 
    463     return output 
     473    return result.wasSuccessful(), output 
    464474 
    465475 
  • sasmodels/sasview_model.py

    r39a06c9 r39a06c9  
    819819            return value, [value], [1.0] 
    820820 
     821    @classmethod 
     822    def runTests(cls): 
     823        """ 
     824        Run any tests built into the model and captures the test output. 
     825 
     826        Returns success flag and output 
     827        """ 
     828        from .model_test import check_model 
     829        return check_model(cls._model_info) 
     830 
    821831def test_cylinder(): 
    822832    # type: () -> float 
  • sasmodels/special.py

    rdf69efa rfba9ca0  
    113113        The standard math function, tgamma(x) is unstable for $x < 1$ 
    114114        on some platforms. 
     115 
     116    sas_gammaln(x): 
     117        log gamma function sas_gammaln\ $(x) = \log \Gamma(|x|)$. 
     118 
     119        The standard math function, lgamma(x), is incorrect for single 
     120        precision on some platforms. 
     121 
     122    sas_gammainc(a, x), sas_gammaincc(a, x): 
     123        Incomplete gamma function 
     124        sas_gammainc\ $(a, x) = \int_0^x t^{a-1}e^{-t}\,dt / \Gamma(a)$ 
     125        and complementary incomplete gamma function 
     126        sas_gammaincc\ $(a, x) = \int_x^\infty t^{a-1}e^{-t}\,dt / \Gamma(a)$ 
    115127 
    116128    sas_erf(x), sas_erfc(x): 
     
    207219from numpy import pi, nan, inf 
    208220from scipy.special import gamma as sas_gamma 
     221from scipy.special import gammaln as sas_gammaln 
     222from scipy.special import gammainc as sas_gammainc 
     223from scipy.special import gammaincc as sas_gammaincc 
    209224from scipy.special import erf as sas_erf 
    210225from scipy.special import erfc as sas_erfc 
Note: See TracChangeset for help on using the changeset viewer.