Changeset bb39b4a in sasmodels


Ignore:
Timestamp:
Aug 6, 2017 11:36:58 AM (7 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
97d89af
Parents:
232bb12
Message:

make the sascomp command line more regular

Location:
sasmodels
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/compare.py

    r232bb12 rbb39b4a  
    5656 
    5757USAGE = """ 
    58 usage: compare.py model N1 N2 [options...] [key=val] 
    59  
    60 Compare the speed and value for a model between the SasView original and the 
    61 sasmodels rewrite. 
     58usage: sascomp model [options...] [key=val] 
     59 
     60Generate and compare SAS models.  If a single model is specified it shows 
     61a plot of that model.  Different models can be compared, or the same model 
     62with different parameters.  The same model with the same parameters can 
     63be compared with different calculation engines to see the effects of precision 
     64on the resultant values. 
    6265 
    6366model or model1,model2 are the names of the models to compare (see below). 
    64 N1 is the number of times to run sasmodels (default=1). 
    65 N2 is the number times to run sasview (default=1). 
    6667 
    6768Options (* for default): 
    6869 
    69     -plot*/-noplot plots or suppress the plot of the model 
     70    === data generation === 
     71    -data="path" uses q, dq from the data file 
     72    -noise=0 sets the measurement error dI/I 
     73    -res=0 sets the resolution width dQ/Q if calculating with resolution 
    7074    -lowq*/-midq/-highq/-exq use q values up to 0.05, 0.2, 1.0, 10.0 
    7175    -nq=128 sets the number of Q points in the data set 
     76    -1d*/-2d computes 1d or 2d data 
    7277    -zero indicates that q=0 should be included 
    73     -1d*/-2d computes 1d or 2d data 
     78 
     79    === model parameters === 
    7480    -preset*/-random[=seed] preset or random parameters 
     81    -sets=n generates n random datasets, with the seed given by -random=seed 
     82    -pars/-nopars* prints the parameter set or not 
     83    -default/-demo* use demo vs default parameters 
     84 
     85    === calculation options === 
    7586    -mono*/-poly force monodisperse or allow polydisperse demo parameters 
     87    -cutoff=1e-5* cutoff value for including a point in polydispersity 
    7688    -magnetic/-nonmagnetic* suppress magnetism 
    77     -cutoff=1e-5* cutoff value for including a point in polydispersity 
    78     -pars/-nopars* prints the parameter set or not 
    79     -abs/-rel* plot relative or absolute error 
    80     -linear/-log*/-q4 intensity scaling 
    81     -hist/-nohist* plot histogram of relative error 
    82     -res=0 sets the resolution width dQ/Q if calculating with resolution 
    8389    -accuracy=Low accuracy of the resolution calculation Low, Mid, High, Xhigh 
    84     -edit starts the parameter explorer 
    85     -default/-demo* use demo vs default parameters 
    86     -help/-html shows the model docs instead of running the model 
    87     -title="note" adds note to the plot title, after the model name 
    88     -data="path" uses q, dq from the data file 
    89  
    90 Any two calculation engines can be selected for comparison: 
    91  
     90 
     91    === precision options === 
     92    -calc=default uses the default calcution precision 
    9293    -single/-double/-half/-fast sets an OpenCL calculation engine 
    9394    -single!/-double!/-quad! sets an OpenMP calculation engine 
    9495    -sasview sets the sasview calculation engine 
    9596 
    96 The default is -single -double.  Note that the interpretation of quad 
    97 precision depends on architecture, and may vary from 64-bit to 128-bit, 
    98 with 80-bit floats being common (1e-19 precision). 
     97    === plotting === 
     98    -plot*/-noplot plots or suppress the plot of the model 
     99    -linear/-log*/-q4 intensity scaling on plots 
     100    -hist/-nohist* plot histogram of relative error 
     101    -abs/-rel* plot relative or absolute error 
     102    -title="note" adds note to the plot title, after the model name 
     103 
     104    === output options === 
     105    -edit starts the parameter explorer 
     106    -help/-html shows the model docs instead of running the model 
     107 
     108The interpretation of quad precision depends on architecture, and may 
     109vary from 64-bit to 128-bit, with 80-bit floats being common (1e-19 precision). 
     110On unix and mac you may need single quotes around the DLL computation 
     111engines, such as -calc='single!,double!' since !, is treated as a history 
     112expansion request in the shell. 
    99113 
    100114Key=value pairs allow you to set specific values for the model parameters. 
    101 Key=value1,value2 to compare different values of the same parameter. 
    102 value can be an expression including other parameters 
     115Key=value1,value2 to compare different values of the same parameter. The 
     116value can be an expression including other parameters. 
     117 
     118Items later on the command line override those that appear earlier. 
     119 
     120Examples: 
     121 
     122    # compare single and double precision calculation for a barbell 
     123    sascomp barbell -calc=single,double 
     124 
     125    # generate 10 random lorentz models, with seed=27 
     126    sascomp lorentz -sets=10 -seed=27 
     127 
     128    # compare ellipsoid with R = R_polar = R_equatorial to sphere of radius R 
     129    sascomp sphere,ellipsoid radius_polar=radius radius_equatorial=radius 
     130 
     131    # model timing test requires multiple evals to perform the estimate 
     132    sascomp pringle -calc=single,double -timing=100,100 -noplot 
    103133""" 
    104134 
     
    111141------------------- 
    112142 
    113 """ 
    114            + USAGE) 
     143""" + USAGE) 
    115144 
    116145kerneldll.ALLOW_SINGLE_PRECISION_DLLS = True 
     
    775804    # type: (Dict[str, Any]) -> Dict[str, Any] 
    776805 
    777     n_base, n_comp = opts['count'] 
    778     pars, pars2 = opts['pars'] 
     806    base, comp = opts['engines'] 
     807    base_n, comp_n = opts['count'] 
     808    base_pars, comp_pars = opts['pars'] 
    779809    data = opts['data'] 
    780810 
    781     # silence the linter 
    782     base = opts['engines'][0] if n_base else None 
    783     comp = opts['engines'][1] if n_comp else None 
     811    comparison = comp is not None 
    784812 
    785813    base_time = comp_time = None 
     
    787815 
    788816    # Base calculation 
    789     if n_base > 0: 
     817    try: 
     818        base_raw, base_time = time_calculation(base, base_pars, base_n) 
     819        base_value = np.ma.masked_invalid(base_raw) 
     820        if verbose: 
     821            print("%s t=%.2f ms, intensity=%.0f" 
     822                  % (base.engine, base_time, base_value.sum())) 
     823        _show_invalid(data, base_value) 
     824    except ImportError: 
     825        traceback.print_exc() 
     826 
     827    # Comparison calculation 
     828    if comparison: 
    790829        try: 
    791             base_raw, base_time = time_calculation(base, pars, n_base) 
    792             base_value = np.ma.masked_invalid(base_raw) 
    793             if verbose: 
    794                 print("%s t=%.2f ms, intensity=%.0f" 
    795                       % (base.engine, base_time, base_value.sum())) 
    796             _show_invalid(data, base_value) 
    797         except ImportError: 
    798             traceback.print_exc() 
    799             n_base = 0 
    800  
    801     # Comparison calculation 
    802     if n_comp > 0: 
    803         try: 
    804             comp_raw, comp_time = time_calculation(comp, pars2, n_comp) 
     830            comp_raw, comp_time = time_calculation(comp, comp_pars, comp_n) 
    805831            comp_value = np.ma.masked_invalid(comp_raw) 
    806832            if verbose: 
     
    810836        except ImportError: 
    811837            traceback.print_exc() 
    812             n_comp = 0 
    813838 
    814839    # Compare, but only if computing both forms 
    815     if n_base > 0 and n_comp > 0: 
     840    if comparison: 
    816841        resid = (base_value - comp_value) 
    817842        relerr = resid/np.where(comp_value != 0., abs(comp_value), 1.0) 
     
    856881 
    857882    have_base, have_comp = (base_value is not None), (comp_value is not None) 
    858     base = opts['engines'][0] if have_base else None 
    859     comp = opts['engines'][1] if have_comp else None 
     883    base, comp = opts['engines'] 
    860884    data = opts['data'] 
    861885    use_data = (opts['datafile'] is not None) and (have_base ^ have_comp) 
     
    874898 
    875899    if have_base: 
    876         if have_comp: plt.subplot(131) 
     900        if have_comp: 
     901            plt.subplot(131) 
    877902        plot_theory(data, base_value, view=view, use_data=use_data, limits=limits) 
    878903        plt.title("%s t=%.2f ms"%(base.engine, base_time)) 
    879904        #cbar_title = "log I" 
    880905    if have_comp: 
    881         if have_base: plt.subplot(132) 
     906        if have_base: 
     907            plt.subplot(132) 
    882908        if not opts['is2d'] and have_base: 
    883909            plot_theory(data, base_value, view=view, use_data=use_data, limits=limits) 
     
    894920            sorted = np.sort(err.flatten()) 
    895921            cutoff = sorted[int(sorted.size*0.95)] 
    896             err[err>cutoff] = cutoff 
     922            err[err > cutoff] = cutoff 
    897923        #err,errstr = base/comp,"ratio" 
    898924        plot_theory(data, None, resid=err, view=errview, use_data=use_data) 
     
    923949# =========================================================================== 
    924950# 
    925 NAME_OPTIONS = set([ 
     951 
     952# Set of command line options. 
     953# Normal options such as -plot/-noplot are specified as 'name'. 
     954# For options such as -nq=500 which require a value use 'name='. 
     955# 
     956OPTIONS = [ 
     957    # Plotting 
    926958    'plot', 'noplot', 
    927     'half', 'fast', 'single', 'double', 
    928     'single!', 'double!', 'quad!', 'sasview', 
    929     'lowq', 'midq', 'highq', 'exq', 'zero', 
     959    'linear', 'log', 'q4', 
     960    'rel', 'abs', 
     961    'hist', 'nohist', 
     962    'title=', 
     963 
     964    # Data generation 
     965    'data=', 'noise=', 'res=', 
     966    'nq=', 'lowq', 'midq', 'highq', 'exq', 'zero', 
    930967    '2d', '1d', 
    931     'preset', 'random', 
    932     'poly', 'mono', 
     968 
     969    # Parameter set 
     970    'preset', 'random', 'random=', 'sets=', 
     971    'demo', 'default',  # TODO: remove demo/default 
     972    'nopars', 'pars', 
     973 
     974    # Calculation options 
     975    'poly', 'mono', 'cutoff=', 
    933976    'magnetic', 'nonmagnetic', 
    934     'nopars', 'pars', 
    935     'rel', 'abs', 
    936     'linear', 'log', 'q4', 
    937     'hist', 'nohist', 
    938     'edit', 'html', 'help', 
    939     'demo', 'default', 
    940     ]) 
    941 VALUE_OPTIONS = [ 
    942     # Note: random is both a name option and a value option 
    943     'cutoff', 'random', 'nq', 'res', 'accuracy', 'title', 'data', 'sets' 
     977    'accuracy=', 
     978 
     979    # Precision options 
     980    'calc=', 
     981    'half', 'fast', 'single', 'double', 'single!', 'double!', 'quad!', 
     982    'sasview',  # TODO: remove sasview 3.x support 
     983    'timing=', 
     984 
     985    # Output options 
     986    'help', 'html', 'edit', 
    944987    ] 
     988 
     989NAME_OPTIONS = set(k for k in OPTIONS if not k.endswith('=')) 
     990VALUE_OPTIONS = [k[:-1] for k in OPTIONS if k.endswith('=')] 
     991 
    945992 
    946993def columnize(items, indent="", width=79): 
     
    10021049# not sure about brackets [] {} 
    10031050# maybe one of the following @ ? ^ ! , 
    1004 MODEL_SPLIT = ',' 
     1051PAR_SPLIT = ',' 
    10051052def parse_opts(argv): 
    10061053    # type: (List[str]) -> Dict[str, Any] 
     
    10211068        print(columnize(MODELS, indent="  ")) 
    10221069        return None 
    1023     if len(positional_args) > 3: 
    1024         print("expected parameters: model N1 N2") 
    10251070 
    10261071    invalid = [o[1:] for o in flags 
     
    10311076        return None 
    10321077 
    1033     name = positional_args[0] 
    1034     n1 = int(positional_args[1]) if len(positional_args) > 1 else 1 
    1035     n2 = int(positional_args[2]) if len(positional_args) > 2 else 1 
     1078    name = positional_args[-1] 
    10361079 
    10371080    # pylint: disable=bad-whitespace 
     
    10441087        'nq'        : 128, 
    10451088        'res'       : 0.0, 
     1089        'noise'     : 0.0, 
    10461090        'accuracy'  : 'Low', 
    1047         'cutoff'    : 0.0, 
     1091        'cutoff'    : '0.0', 
    10481092        'seed'      : -1,  # default to preset 
    10491093        'mono'      : True, 
     
    10601104        'datafile'  : None, 
    10611105        'sets'      : 1, 
     1106        'engine'    : 'default', 
     1107        'evals'     : '1', 
    10621108    } 
    1063     engines = [] 
    10641109    for arg in flags: 
    10651110        if arg == '-noplot':    opts['plot'] = False 
     
    10771122        elif arg.startswith('-nq='):       opts['nq'] = int(arg[4:]) 
    10781123        elif arg.startswith('-res='):      opts['res'] = float(arg[5:]) 
     1124        elif arg.startswith('-noise='):    opts['noise'] = float(arg[7:]) 
    10791125        elif arg.startswith('-sets='):     opts['sets'] = int(arg[6:]) 
    10801126        elif arg.startswith('-accuracy='): opts['accuracy'] = arg[10:] 
    1081         elif arg.startswith('-cutoff='):   opts['cutoff'] = float(arg[8:]) 
     1127        elif arg.startswith('-cutoff='):   opts['cutoff'] = arg[8:] 
    10821128        elif arg.startswith('-random='):   opts['seed'] = int(arg[8:]) 
    10831129        elif arg.startswith('-title='):    opts['title'] = arg[7:] 
    10841130        elif arg.startswith('-data='):     opts['datafile'] = arg[6:] 
     1131        elif arg.startswith('-calc='):     opts['engine'] = arg[6:] 
     1132        elif arg.startswith('-neval='):    opts['evals'] = arg[7:] 
    10851133        elif arg == '-random':  opts['seed'] = np.random.randint(1000000) 
    10861134        elif arg == '-preset':  opts['seed'] = -1 
     
    10951143        elif arg == '-rel':     opts['rel_err'] = True 
    10961144        elif arg == '-abs':     opts['rel_err'] = False 
    1097         elif arg == '-half':    engines.append(arg[1:]) 
    1098         elif arg == '-fast':    engines.append(arg[1:]) 
    1099         elif arg == '-single':  engines.append(arg[1:]) 
    1100         elif arg == '-double':  engines.append(arg[1:]) 
    1101         elif arg == '-single!': engines.append(arg[1:]) 
    1102         elif arg == '-double!': engines.append(arg[1:]) 
    1103         elif arg == '-quad!':   engines.append(arg[1:]) 
    1104         elif arg == '-sasview': engines.append(arg[1:]) 
     1145        elif arg == '-half':    opts['engine'] = 'half' 
     1146        elif arg == '-fast':    opts['engine'] = 'fast' 
     1147        elif arg == '-single':  opts['engine'] = 'single' 
     1148        elif arg == '-double':  opts['engine'] = 'double' 
     1149        elif arg == '-single!': opts['engine'] = 'single!' 
     1150        elif arg == '-double!': opts['engine'] = 'double!' 
     1151        elif arg == '-quad!':   opts['engine'] = 'quad!' 
     1152        elif arg == '-sasview': opts['engine'] = 'sasview' 
    11051153        elif arg == '-edit':    opts['explore'] = True 
    11061154        elif arg == '-demo':    opts['use_demo'] = True 
     
    11141162        opts['seed'] = np.random.randint(1000000) 
    11151163 
    1116     if MODEL_SPLIT in name: 
    1117         name, name2 = name.split(MODEL_SPLIT, 2) 
    1118     else: 
    1119         name2 = name 
    1120     try: 
    1121         model_info = core.load_model_info(name) 
    1122         model_info2 = core.load_model_info(name2) if name2 != name else model_info 
    1123     except ImportError as exc: 
    1124         print(str(exc)) 
    1125         print("Could not find model; use one of:\n    " + models) 
    1126         return None 
    1127  
    1128     # TODO: check if presets are different when deciding if models are same 
    1129     same_model = name == name2 
    1130     if len(engines) == 0: 
    1131         if same_model: 
    1132             engines.extend(['single', 'double']) 
    1133         else: 
    1134             engines.extend(['single', 'single']) 
    1135     elif len(engines) == 1: 
    1136         if not same_model: 
    1137             engines.append(engines[0]) 
    1138         elif engines[0] == 'double': 
    1139             engines.append('single') 
    1140         else: 
    1141             engines.append('double') 
    1142     elif len(engines) > 2: 
    1143         del engines[2:] 
    1144  
    11451164    # Create the computational engines 
    11461165    if opts['datafile'] is not None: 
     
    11481167    else: 
    11491168        data, _ = make_data(opts) 
    1150     if n1: 
    1151         base = make_engine(model_info, data, engines[0], opts['cutoff']) 
     1169 
     1170    comparison = any(PAR_SPLIT in v for v in values) 
     1171    if PAR_SPLIT in name: 
     1172        names = name.split(PAR_SPLIT, 2) 
     1173        comparison = True 
    11521174    else: 
    1153         base = None 
    1154     if n2: 
    1155         comp = make_engine(model_info2, data, engines[1], opts['cutoff']) 
     1175        names = [name]*2 
     1176    try: 
     1177        model_info = [core.load_model_info(k) for k in names] 
     1178    except ImportError as exc: 
     1179        print(str(exc)) 
     1180        print("Could not find model; use one of:\n    " + models) 
     1181        return None 
     1182 
     1183    if PAR_SPLIT in opts['engine']: 
     1184        engine_types = opts['engine'].split(PAR_SPLIT, 2) 
     1185        comparison = True 
     1186    else: 
     1187        engine_types = [opts['engine']]*2 
     1188 
     1189    if PAR_SPLIT in opts['evals']: 
     1190        evals = [int(k) for k in opts['evals'].split(PAR_SPLIT, 2)] 
     1191        comparison = True 
     1192    else: 
     1193        evals = [int(opts['evals'])]*2 
     1194 
     1195    if PAR_SPLIT in opts['cutoff']: 
     1196        cutoff = [float(k) for k in opts['cutoff'].split(PAR_SPLIT, 2)] 
     1197        comparison = True 
     1198    else: 
     1199        cutoff = [float(opts['cutoff'])]*2 
     1200 
     1201    base = make_engine(model_info[0], data, engine_types[0], cutoff[0]) 
     1202    if comparison: 
     1203        comp = make_engine(model_info[1], data, engine_types[1], cutoff[1]) 
    11561204    else: 
    11571205        comp = None 
     
    11611209    opts.update({ 
    11621210        'data'      : data, 
    1163         'name'      : [name, name2], 
    1164         'def'       : [model_info, model_info2], 
    1165         'count'     : [n1, n2], 
     1211        'name'      : names, 
     1212        'def'       : model_info, 
     1213        'count'     : evals, 
    11661214        'engines'   : [base, comp], 
    11671215        'values'    : values, 
     
    12101258            print("%r invalid; parameters are: %s"%(k, ", ".join(sorted(s)))) 
    12111259            return None 
    1212         v1, v2 = v.split(MODEL_SPLIT, 2) if MODEL_SPLIT in v else (v,v) 
     1260        v1, v2 = v.split(PAR_SPLIT, 2) if PAR_SPLIT in v else (v,v) 
    12131261        if v1 and k in pars: 
    12141262            presets[k] = float(v1) if isnumber(v1) else v1 
  • sasmodels/core.py

    r650c6d2 rbb39b4a  
    253253 
    254254    # Convert dtype string to numpy dtype. 
    255     if dtype is None: 
     255    if dtype is None or dtype == "default": 
    256256        numpy_dtype = (generate.F32 if platform == "ocl" and model_info.single 
    257257                       else generate.F64) 
  • sasmodels/models/ellipsoid.py

    r31df0c9 rbb39b4a  
    111111*Structure Analysis by Small-Angle X-Ray and Neutron Scattering*, 
    112112Plenum Press, New York, 1987. 
     113 
     114A. Isihara. J. Chem. Phys. 18(1950) 1446-1449 
    113115 
    114116Authorship and Verification 
     
    162164def ER(radius_polar, radius_equatorial): 
    163165    import numpy as np 
    164 # see equation (26) in A.Isihara, J.Chem.Phys. 18(1950)1446-1449 
     166    # see equation (26) in A.Isihara, J.Chem.Phys. 18(1950)1446-1449 
    165167    ee = np.empty_like(radius_polar) 
    166168    idx = radius_polar > radius_equatorial 
Note: See TracChangeset for help on using the changeset viewer.