예제 #1
0
def process_model(path):
    # type: (str) -> None
    """
    Generate doc file and image file for the given model definition file.
    """

    # Load the model file
    model_name = os.path.basename(path)[:-3]
    model_info = core.load_model_info(model_name)

    # Plotting ranges and options
    opts = {
        'xscale'    : 'log',
        'yscale'    : 'log' if not model_info.structure_factor else 'linear',
        'zscale'    : 'log' if not model_info.structure_factor else 'linear',
        'q_min'     : 0.001,
        'q_max'     : 1.0,
        'nq'        : 1000,
        'nq2d'      : 1000,
        'vmin'      : 1e-3,  # floor for the 2D data results
        'qx_max'    : 0.5,
        #'colormap'  : 'gist_ncar',
        'colormap'  : 'nipy_spectral',
        #'colormap'  : 'jet',
    }

    # Generate the RST file and the figure.  Order doesn't matter.
    gen_docs(model_info)
    make_figure(model_info, opts)
예제 #2
0
def process_model(path):
    # type: (str) -> None
    """
    Generate doc file and image file for the given model definition file.
    """

    # Load the model file
    model_name = os.path.basename(path)[:-3]
    model_info = core.load_model_info(model_name)

    # Plotting ranges and options
    opts = {
        'xscale': 'log',
        'yscale': 'log' if not model_info.structure_factor else 'linear',
        'zscale': 'log' if not model_info.structure_factor else 'linear',
        'q_min': 0.001,
        'q_max': 1.0,
        'nq': 1000,
        'nq2d': 1000,
        'vmin': 1e-3,  # floor for the 2D data results
        'qx_max': 0.5,
        #'colormap'  : 'gist_ncar',
        'colormap': 'nipy_spectral',
        #'colormap'  : 'jet',
    }

    # Generate the RST file and the figure.  Order doesn't matter.
    gen_docs(model_info)
    make_figure(model_info, opts)
예제 #3
0
def build_model(model_name, q, **pars):
    from sasmodels.core import load_model_info, build_model as build_sasmodel
    from sasmodels.data import empty_data1D
    from sasmodels.direct_model import DirectModel
    model_info = load_model_info(model_name)
    model = build_sasmodel(model_info, dtype='double!')
    data = empty_data1D(q)
    calculator = DirectModel(data, model, cutoff=0)
    calculator.pars = pars.copy()
    calculator.pars.setdefault('background', 0)
    return calculator
예제 #4
0
def process_model(py_file, force=False):
    # type: (str) -> None
    """
    Generate doc file and image file for the given model definition file.

    Does nothing if the corresponding rst file is newer than *py_file*.
    Also checks the timestamp on the *genmodel.py* program (*__file__*),
    since we want to rerun the generator on all files if we change this
    code.

    If *force* then generate the rst file regardless of time stamps.
    """
    rst_file = joinpath(TARGET_DIR, basename(py_file).replace('.py', '.rst'))
    if not (force or newer(py_file, rst_file) or newer(__file__, rst_file)):
        #print("skipping", rst_file)
        return rst_file

    # Load the model file
    model_info = core.load_model_info(py_file)
    if model_info.basefile is None:
        model_info.basefile = py_file

    # Plotting ranges and options
    PLOT_OPTS = {
        'xscale': 'log',
        'yscale': 'log' if not model_info.structure_factor else 'linear',
        'zscale': 'log' if not model_info.structure_factor else 'linear',
        'q_min': 0.001,
        'q_max': 1.0,
        'nq': 1000,
        'nq2d': 1000,
        'vmin': 1e-3,  # floor for the 2D data results
        'qx_max': 0.5,
        #'colormap'  : 'gist_ncar',
        'colormap': 'nipy_spectral',
        #'colormap'  : 'jet',
    }

    # Generate the RST file and the figure.  Order doesn't matter.
    print("generating", rst_file)
    gen_docs(model_info, rst_file)
    if force:
        make_figure(model_info, PLOT_OPTS)
    else:
        make_figure_cached(model_info, PLOT_OPTS)
    return rst_file
예제 #5
0
def _eval_demo_1d(resolution, title):
    import sys
    from sasmodels import core
    from sasmodels import direct_model
    name = sys.argv[1] if len(sys.argv) > 1 else 'cylinder'

    if name == 'cylinder':
        pars = {'length': 210, 'radius': 500, 'background': 0}
    elif name == 'teubner_strey':
        pars = {'a2': 0.003, 'c1': -1e4, 'c2': 1e10, 'background': 0.312643}
    elif name == 'sphere' or name == 'spherepy':
        pars = TEST_PARS_SLIT_SPHERE
    elif name == 'ellipsoid':
        pars = {
            'scale': 0.05,
            'background': 0,
            'r_polar': 500,
            'r_equatorial': 15000,
            'sld': 6,
            'sld_solvent': 1,
        }
    else:
        pars = {}
    model_info = core.load_model_info(name)
    model = core.build_model(model_info)

    kernel = model.make_kernel([resolution.q_calc])
    theory = direct_model.call_kernel(kernel, pars)
    Iq = resolution.apply(theory)

    if isinstance(resolution, Slit1D):
        width, height = resolution.qx_width, resolution.qy_width
        Iq_romb = romberg_slit_1d(resolution.q, width, height, model, pars)
    else:
        dq = resolution.q_width
        Iq_romb = romberg_pinhole_1d(resolution.q, dq, model, pars)

    import matplotlib.pyplot as plt  # type: ignore
    plt.loglog(resolution.q_calc, theory, label='unsmeared')
    plt.loglog(resolution.q, Iq, label='smeared', hold=True)
    plt.loglog(resolution.q, Iq_romb, label='romberg smeared', hold=True)
    plt.legend()
    plt.title(title)
    plt.xlabel("Q (1/Ang)")
    plt.ylabel("I(Q) (1/cm)")
예제 #6
0
def _eval_demo_1d(resolution, title):
    import sys
    from sasmodels import core
    name = sys.argv[1] if len(sys.argv) > 1 else 'cylinder'

    if name == 'cylinder':
        pars = {'length':210, 'radius':500, 'background': 0}
    elif name == 'teubner_strey':
        pars = {'a2':0.003, 'c1':-1e4, 'c2':1e10, 'background':0.312643}
    elif name == 'sphere' or name == 'spherepy':
        pars = TEST_PARS_SLIT_SPHERE
    elif name == 'ellipsoid':
        pars = {
            'scale':0.05, 'background': 0,
            'r_polar':500, 'r_equatorial':15000,
            'sld':6, 'sld_solvent': 1,
            }
    else:
        pars = {}
    model_info = core.load_model_info(name)
    model = core.build_model(model_info)

    kernel = model.make_kernel([resolution.q_calc])
    theory = core.call_kernel(kernel, pars)
    Iq = resolution.apply(theory)

    if isinstance(resolution, Slit1D):
        width, height = resolution.dqx, resolution.dqy
        Iq_romb = romberg_slit_1d(resolution.q, width, height, model, pars)
    else:
        dq = resolution.q_width
        Iq_romb = romberg_pinhole_1d(resolution.q, dq, model, pars)

    import matplotlib.pyplot as plt
    plt.loglog(resolution.q_calc, theory, label='unsmeared')
    plt.loglog(resolution.q, Iq, label='smeared', hold=True)
    plt.loglog(resolution.q, Iq_romb, label='romberg smeared', hold=True)
    plt.legend()
    plt.title(title)
    plt.xlabel("Q (1/Ang)")
    plt.ylabel("I(Q) (1/cm)")
예제 #7
0
def build_model(model_name, n=150, qmax=0.5, **pars):
    """
    Build a calculator for the given shape.

    *model_name* is any sasmodels model.  *n* and *qmax* define an n x n mesh
    on which to evaluate the model.  The remaining parameters are stored in
    the returned calculator as *calculator.pars*.  They are used by
    :func:`draw_scattering` to set the non-orientation parameters in the
    calculation.

    Returns a *calculator* function which takes a dictionary or parameters and
    produces Iqxy.  The Iqxy value needs to be reshaped to an n x n matrix
    for plotting.  See the :class:`sasmodels.direct_model.DirectModel` class
    for details.
    """
    from sasmodels.core import load_model_info, build_model
    from sasmodels.data import empty_data2D
    from sasmodels.direct_model import DirectModel

    model_info = load_model_info(model_name)
    model = build_model(model_info)  #, dtype='double!')
    q = np.linspace(-qmax, qmax, n)
    data = empty_data2D(q, q)
    calculator = DirectModel(data, model)

    # stuff the values for non-orientation parameters into the calculator
    calculator.pars = pars.copy()
    calculator.pars.setdefault('backgound', 1e-3)

    # fix the data limits so that we can see if the pattern fades
    # under rotation or angular dispersion
    Iqxy = calculator(theta=0, phi=0, psi=0, **calculator.pars)
    Iqxy = np.log(Iqxy)
    vmin, vmax = clipped_range(Iqxy, 0.95, mode='top')
    calculator.limits = vmin, vmax + 1

    return calculator
예제 #8
0
파일: gentoc.py 프로젝트: willend/sasmodels
def generate_toc(model_files):
    # type: (List[str]) -> None
    if not model_files:
        print("gentoc needs a list of model files", file=sys.stderr)

    # find all categories
    category = {}  # type: Dict[str, List[str]]
    for item in model_files:
        # assume model is in sasmodels/models/name.py, and ignore the full path
        model_name = basename(item)[:-3]
        if model_name.startswith('_'): continue
        model_info = load_model_info(model_name)
        if model_info.category is None:
            print("Missing category for", item, file=sys.stderr)
        else:
            category.setdefault(model_info.category, []).append(model_name)

    # Check category names
    for k, v in category.items():
        if len(v) == 1:
            print("Category %s contains only %s" % (k, v[0]), file=sys.stderr)

    # Generate category files for the table of contents.
    # Initially we had "shape functions" as an additional TOC level, but we
    # have revised it so that the individual shape categories now go at
    # the top level.  Judicious rearrangement of comments will make the
    # "shape functions" level reappear.
    # We are forcing shape-independent, structure-factor and custom-models
    # to come at the end of the TOC.  All other categories will come in
    # alphabetical order before them.

    if not exists(MODEL_TOC_PATH): mkdir(MODEL_TOC_PATH)
    model_toc = _make_category('index', 'Models', 'Model Functions')
    #shape_toc = _make_category(
    #    'shape',  'Shapes', 'Shape Functions', model_toc)
    free_toc = _make_category('shape-independent', 'Shape-independent',
                              'Shape-Independent Functions')
    struct_toc = _make_category('structure-factor', 'Structure-factor',
                                'Structure Factors')
    custom_toc = _make_category('custom-models', 'Custom-models',
                                'Custom Models')

    # remember to top level categories
    cat_files = {
        #'shape':shape_toc,
        'shape': model_toc,
        'shape-independent': free_toc,
        'structure-factor': struct_toc,
        'custom': custom_toc,
    }

    # Process the model lists
    for k, v in sorted(category.items()):
        if ':' in k:
            cat, subcat = k.split(':')
            _maybe_make_category(cat, v, cat_files, model_toc)
            cat_file = cat_files[cat]
            label = "-".join((cat, subcat))
            filename = label
            title = subcat.capitalize() + " Functions"
            sub_toc = _make_category(filename, label, title, cat_file)
            for model in sorted(v):
                _add_model(sub_toc, model)
            sub_toc.close()
        else:
            _maybe_make_category(k, v, cat_files, model_toc)
            cat_file = cat_files[k]
            for model in sorted(v):
                _add_model(cat_file, model)

    #_add_subcategory('shape', model_toc)
    _add_subcategory('shape-independent', model_toc)
    _add_subcategory('structure-factor', model_toc)
    _add_subcategory('custom-models', model_toc)

    # Close the top-level category files
    #model_toc.close()
    for f in cat_files.values():
        f.close()
예제 #9
0
import sys, os, math, re
import numpy as np
import matplotlib.pyplot as plt
import pylab
sys.path.insert(0, os.path.abspath('..'))
from sasmodels import generate, core
from sasmodels.direct_model import DirectModel
from sasmodels.data import empty_data1D, empty_data2D

# Convert ../sasmodels/models/name.py to name
model_name = os.path.basename(sys.argv[1])[:-3]
model_info = core.load_model_info(model_name)
model = core.build_model(model_info)

# Load the doc string from the module definition file and store it in rst
docstr = generate.make_doc(model_info)

# Calculate 1D curve for default parameters
pars = dict((p.name, p.default) for p in model_info['parameters'])

# Plotting ranges and options
opts = {
    'xscale': 'log',
    'yscale': 'log' if not model_info['structure_factor'] else 'linear',
    'zscale': 'log' if not model_info['structure_factor'] else 'linear',
    'q_min': 0.001,
    'q_max': 1.0,
    'nq': 1000,
    'nq2d': 1000,
    'vmin': 1e-3,  # floor for the 2D data results
    'qx_max': 0.5,
예제 #10
0
def generate_toc(model_files):
    # type: (List[str]) -> None
    if not model_files:
        print("gentoc needs a list of model files", file=sys.stderr)

    # find all categories
    category = {} # type: Dict[str, List[str]]
    for item in model_files:
        # assume model is in sasmodels/models/name.py, and ignore the full path
        model_name = basename(item)[:-3]
        if model_name.startswith('_'): continue
        model_info = load_model_info(model_name)
        if model_info.category is None:
            print("Missing category for", item, file=sys.stderr)
        else:
            category.setdefault(model_info.category,[]).append(model_name)

    # Check category names
    for k,v in category.items():
        if len(v) == 1:
            print("Category %s contains only %s"%(k,v[0]), file=sys.stderr)

    # Generate category files for the table of contents.
    # Initially we had "shape functions" as an additional TOC level, but we
    # have revised it so that the individual shape categories now go at
    # the top level.  Judicious rearrangement of comments will make the
    # "shape functions" level reappear.
    # We are forcing shape-independent, structure-factor and custom-models
    # to come at the end of the TOC.  All other categories will come in
    # alphabetical order before them.

    if not exists(MODEL_TOC_PATH): mkdir(MODEL_TOC_PATH)
    model_toc = _make_category(
        'index',  'Models', 'Model Functions')
    #shape_toc = _make_category(
    #    'shape',  'Shapes', 'Shape Functions', model_toc)
    free_toc = _make_category(
        'shape-independent',  'Shape-independent',
        'Shape-Independent Functions')
    struct_toc = _make_category(
        'structure-factor',  'Structure-factor', 'Structure Factors')
    custom_toc = _make_category(
        'custom-models',  'Custom-models', 'Custom Models')

    # remember to top level categories
    cat_files = {
        #'shape':shape_toc,
        'shape':model_toc,
        'shape-independent':free_toc,
        'structure-factor': struct_toc,
        'custom': custom_toc,
        }

    # Process the model lists
    for k,v in sorted(category.items()):
        if ':' in k:
            cat,subcat = k.split(':')
            _maybe_make_category(cat, v, cat_files, model_toc)
            cat_file = cat_files[cat]
            label = "-".join((cat,subcat))
            filename = label
            title = subcat.capitalize()+" Functions"
            sub_toc = _make_category(filename, label, title, cat_file)
            for model in sorted(v):
                _add_model(sub_toc, model)
            sub_toc.close()
        else:
            _maybe_make_category(k, v, cat_files, model_toc)
            cat_file = cat_files[k]
            for model in sorted(v):
                _add_model(cat_file, model)

    #_add_subcategory('shape', model_toc)
    _add_subcategory('shape-independent', model_toc)
    _add_subcategory('structure-factor', model_toc)
    _add_subcategory('custom-models', model_toc)

    # Close the top-level category files
    #model_toc.close()
    for f in cat_files.values(): f.close()
예제 #11
0
def gen_data(model_name,
             data,
             count=1,
             noise=2,
             mono=True,
             magnetic=False,
             cutoff=1e-5,
             maxdim=np.inf,
             precision='double'):
    r"""
    Generates the data for the given model and parameters.

    *model_name* is the name of the model.

    *data* is the data object giving $q, \Delta q$ calculation points.

    *N* is the number of comparisons to make.

    *cutoff* is the polydispersity weight cutoff to make the calculation
    a little bit faster.

    *maxdim* is maximum value for any shape dimension.

    *precision* is the name of the calculation engine to use.

    Returns iterator *(seed, pars, data), ...* where *pars* is
    *{par: value, ...}* and *data* is *(q, dq, iq, diq)*.
    """
    is2d = False
    assert data.x.size > 0
    model_info = sascore.load_model_info(model_name)
    calculator = sascomp.make_engine(model_info, data, precision, cutoff)
    default_pars = sascomp.get_pars(model_info)
    assert calculator._data.x.size > 0
    x, dx = calculator._data.x, calculator._data.dx

    # A not very clean macro for evaluating the models, wich uses name and
    # seed from the current scope even though they haven't been defined yet.
    def simulate(pars):
        """
        Generate a random dataset for *fn* evaluated at *pars*.
        Returns *(x, dx, y, dy)*, o.

        Note that this replaces the data object within *fn*.
        """
        # TODO: support 2D data, which does not use x, dx, y, dy
        try:
            assert calculator._data.x.size > 0
            calculator.simulate_data(noise=noise, **pars)
            assert calculator._data.x.size > 0
            data = calculator._data
            # TODO: Do we need to copy? [Yes if data.y is reused.]
            result = (x, dx, data.y.copy(), data.dy.copy())
        except Exception:
            traceback.print_exc()
            print(f"Error when generating {model_name} for {seed}")
            result = (x, dx, np.NaN * x, np.NaN * x)
            #raise
        return result

    def pretty(pars):
        """
        Pretty the parameter set for displaying on one line
        """
        parlist = sascomp.parlist(model_info, pars, is2d)
        parlist = parlist.replace(os.linesep, '  ')
        parlist = parlist.replace(': ', '=')
        return parlist

    t0 = -np.inf
    interval = 5
    for k in range(count):
        seed = np.random.randint(int(1e6))
        t1 = time.perf_counter()
        if t1 > t0 + interval:
            print(f"generating {model_name} {k+1} of {count}")
            t0 = t1

        # Generate parameters
        with sascomp.push_seed(seed):
            pars = sascomp.randomize_pars(model_info, default_pars, maxdim)
        sascomp.constrain_pars(model_info, pars)
        if mono:
            pars = sascomp.suppress_pd(pars)
        if not magnetic:
            pars = sascomp.suppress_magnetism(pars)
        pars.update({'scale': 1, 'background': 1e-5})
        #print(f"{model_name} {seed} {pretty(pars)}")

        # Evaluate model
        data = simulate(pars)  # q, dq, iq, diq

        # Skip data sets with NaN or negative numbers.
        # Note: some datasets will have fewer entries than others.
        if np.isnan(data[2]).any():
            print(f">>> NaN in {model_name} {seed} {pretty(pars)}")
            continue
        if (data[2] <= 0.).any():
            print(f">>> Negative values in {model_name} {seed} {pretty(pars)}")
            continue

        yield seed, pars, data

    # TODO: can free the calculator now
    print(f"Complete {model_name}")