Ejemplo n.º 1
0
def free_one_by_one(
        recipe: MyRecipe,
        tags: tp.List[tp.Union[str, tp.Iterable[str]]]) -> tp.Generator:
    """Free the tags one by one."""
    for n, tag in enumerate(tags):
        tag_lst = [tag] if isinstance(tag, str) else tag
        recipe.free(*tag_lst)
        yield tag_lst
Ejemplo n.º 2
0
def add_scale(recipe: MyRecipe, gen: G, scale: bool = True) -> None:
    """Add the scale of the generator."""
    if not scale:
        return
    recipe.addVar(gen.scale,
                  value=0.,
                  name="{}_scale".format(gen.name),
                  tags=["{}_scale".format(gen.name), "scale",
                        gen.name]).boundRange(lb=0.)
    return
Ejemplo n.º 3
0
def add_lat(recipe: MyRecipe, gen: G, lat: tp.Union[str, None]) -> None:
    """Add the lattice parameters of the phase."""
    if not lat:
        return
    if lat == "s":
        pars = gen.phase.sgpars.latpars
    elif lat == "a":
        pars = gen.phase.getLattice()
    else:
        raise ValueError("Unknown lat: {}. Allowed: sg, all.".format(lat))
    for par in pars:
        recipe.addVar(par,
                      name="{}_{}".format(gen.name, par.name),
                      tags=["lat", gen.name,
                            "{}_lat".format(gen.name)]).boundRange(lb=0.)
    return
Ejemplo n.º 4
0
def add_delta(recipe: MyRecipe, gen: G, delta: tp.Union[str, None]) -> None:
    """Add the delta parameter of the generator."""
    if not delta:
        return
    if delta == "1":
        par = gen.delta1
    elif delta == "2":
        par = gen.delta2
    else:
        raise ValueError(
            "Unknown delta: {}. Allowed: delta1, delta2.".format(delta))
    recipe.addVar(par,
                  value=0.,
                  name="{}_{}".format(gen.name, par.name),
                  tags=["{}_delta".format(gen.name), "delta",
                        gen.name]).boundRange(lb=0.)
    return
Ejemplo n.º 5
0
def add_params(recipe: MyRecipe, con: MyContribution,
               params: tp.Union[None, str, tp.List[str]]) -> None:
    """Add contribution-level parameters in the contribution."""
    if not params:
        return
    args = {
        arg.name: arg
        for eq in con.eqfactory.equations if eq.name == "eq" for arg in eq.args
        if arg.name != con.xname
    }
    if params == "a":
        pars = args.values()
    else:
        pars = [args[p] for p in params]
    for par in pars:
        recipe.addVar(par, tag=par.name.split("_")[0])
    return
Ejemplo n.º 6
0
def add_adp(
    recipe: MyRecipe,
    gen: G,
    adp: tp.Union[str, None],
    symbols: tp.Tuple[str] = ("Biso", "B11", "B22", "B33")
) -> None:
    """Add the atomic displacement parameter of the phase."""
    if not adp:
        return
    atoms = gen.phase.getScatterers()
    if adp == "e":
        elements = set((atom.element for atom in atoms))
        dct = dict()
        for element in elements:
            dct[element] = recipe.newVar(
                "{}_{}_Biso".format(gen.name, bleach(element)),
                value=0.05,
                tags=["adp", gen.name, "{}_adp".format(gen.name)])
        for atom in atoms:
            recipe.constrain(atom.Biso, dct[atom.element])
        return
    if adp == "a":
        pars = [atom.Biso for atom in atoms]
        names = ["{}_Biso".format(bleach(atom.name)) for atom in atoms]
    elif adp == "s":
        pars = gen.phase.sgpars.adppars
        names = [
            rename_by_atom(par.name, atoms) for par in pars
            if par.name.split("_")[0] in symbols
        ]
    else:
        raise ValueError(
            "Unknown adp: {}. Allowed: element, sg, all.".format(adp))
    for par, name in zip(pars, names):
        recipe.addVar(par,
                      name="{}_{}".format(gen.name, name),
                      value=par.value if par.value != 0. else 0.05,
                      tags=["adp", gen.name,
                            "{}_adp".format(gen.name)]).boundRange(lb=0.)
    return
Ejemplo n.º 7
0
def optimize(recipe: MyRecipe,
             tags: tp.List[tp.Union[str, tp.Iterable[str]]],
             validate: bool = True,
             verbose: int = 0,
             **kwargs):
    """First fix all variables and then free the variables one by one and fit the recipe.

    Parameters
    ----------
    recipe
        The recipe to fit.

    tags
        The tags of variables to free. It can be single tag or a tuple of tags.

    validate
        Whether to validate the existences of the tags and variable names before the optimization.

    verbose
        How verbose the fit should be.

    kwargs
        The kwargs of the 'fit'.
    """
    if verbose > 0:
        print(f"Start {recipe.name} with all parameters fixed.")
    if validate:
        recipe.fix("all")
        list(free_one_by_one(recipe, tags))
    n = len(tags)
    count = 1
    recipe.fix("all")
    for tag_lst in free_one_by_one(recipe, tags):
        if verbose > 0:
            print("Round {} / {}: Free {} ...".format(count, n,
                                                      ", ".join(tag_lst)))
        fit(recipe, verbose=verbose, **kwargs)
        count += 1
    return
Ejemplo n.º 8
0
def add_xyz(recipe: MyRecipe, gen: G, xyz: tp.Union[str, None]) -> None:
    """Add the coordinates of the atoms in the phase."""
    if not xyz:
        return
    atoms = gen.phase.getScatterers()
    if xyz == "s":
        pars = gen.phase.sgpars.xyzpars
        names = [rename_by_atom(par.name, atoms) for par in pars]
    elif xyz == "a":
        pars, names = list(), list()
        for atom in atoms:
            pars.append(atom.x)
            names.append("{}_x".format(atom.name))
            pars.append(atom.y)
            names.append("{}_y".format(atom.name))
            pars.append(atom.z)
            names.append("{}_z".format(atom.name))
    else:
        raise ValueError("Unknown xyz: {}. Allowed: s, a.".format(xyz))
    for par, name in zip(pars, names):
        recipe.addVar(par,
                      name="{}_{}".format(gen.name, name),
                      tags=["xyz", gen.name, "{}_xyz".format(gen.name)])
    return
Ejemplo n.º 9
0
def create(name: str,
           data: MyParser,
           arange: tp.Tuple[float, float, float],
           equation: str,
           functions: tp.Dict[str, tp.Callable],
           structures: tp.Dict[str, S],
           ncpu: int = None) -> MyRecipe:
    """Create a single-contribution recipe without any variables inside.

    Parameters
    ----------
    name :
        The name of the contribution.

    data :
        The parser that contains the information of the

    arange :
        The rmin, rmax, rstep (inclusive).

    equation :
        The equation of the contribution.

    functions :
        The keys are function names in the equation and the values are function objects.

    structures :
        The keys are structure name in the equation and the values are structure object.

    ncpu :
        The number of cpu used in parallel computing. If None, no parallel. Default None.

    Returns
    -------
    recipe :
        A single-contribution recipe without any variables inside.
    """
    con = create_con(name, data, arange, equation, functions, structures, ncpu)
    recipe = MyRecipe()
    recipe.addContribution(con)
    recipe.clearFitHooks()
    return recipe
Ejemplo n.º 10
0
def get_value_dct(recipe: MyRecipe) -> tp.Dict[str, float]:
    """Get the values in the recipe in a dictionary."""
    return dict(zip(recipe.getNames(), recipe.getValues()))
Ejemplo n.º 11
0
def get_bound_dct(recipe: MyRecipe) -> tp.Dict[str, tp.List[float]]:
    """Get the bounds in the recipe in a dictionary."""
    return dict(zip(recipe.getNames(), recipe.getBounds()))