Exemplo n.º 1
0
def generate_parameters(phase_models, datasets, ref_state, excess_model):
    """Generate parameters from given phase models and datasets

    Parameters
    ----------
    phase_models : dict
        Dictionary of components and phases to fit.
    datasets : PickleableTinyDB
        database of single- and multi-phase to fit.
    ref_state : str
        String of the reference data to use, e.g. 'SGTE91' or 'SR2016'
    excess_model : str
        String of the type of excess model to fit to, e.g. 'linear'

    Returns
    -------
    pycalphad.Database

    """
    logging.info('Generating parameters.')
    dbf = Database()
    dbf.elements = set(phase_models['components'])
    for el in dbf.elements:
        if Species is not None:  # TODO: drop this on release of pycalphad 0.7
            dbf.species.add(Species(el, {el: 1}, 0))
    # Write reference state to Database
    refdata = getattr(espei.refdata, ref_state)
    stabledata = getattr(espei.refdata, ref_state + 'Stable')
    for key, element in refdata.items():
        if isinstance(element, sympy.Piecewise):
            newargs = element.args + ((0, True), )
            refdata[key] = sympy.Piecewise(*newargs)
    for key, element in stabledata.items():
        if isinstance(element, sympy.Piecewise):
            newargs = element.args + ((0, True), )
            stabledata[key] = sympy.Piecewise(*newargs)
    comp_refs = {
        c.upper(): stabledata[c.upper()]
        for c in dbf.elements if c.upper() != 'VA'
    }
    comp_refs['VA'] = 0
    # note that the `c.upper()*2)[:2]` returns 'AL' for c.upper()=='AL' and 'VV' for c.upper()=='V'
    dbf.symbols.update(
        {'GHSER' + (c.upper() * 2)[:2]: data
         for c, data in comp_refs.items()})
    for phase_name, phase_obj in sorted(phase_models['phases'].items(),
                                        key=operator.itemgetter(0)):
        # Perform parameter selection and single-phase fitting based on input
        # TODO: Need to pass particular models to include: magnetic, order-disorder, etc.
        symmetry = phase_obj.get('equivalent_sublattices', None)
        aliases = phase_obj.get('aliases', None)
        # TODO: More advanced phase data searching
        site_ratios = phase_obj['sublattice_site_ratios']
        subl_model = phase_obj['sublattice_model']
        dbf.add_phase(phase_name, dict(), site_ratios)
        dbf.add_phase_constituents(phase_name, subl_model)
        dbf.add_structure_entry(phase_name, phase_name)
        phase_fit(dbf,
                  phase_name,
                  symmetry,
                  subl_model,
                  site_ratios,
                  datasets,
                  refdata,
                  aliases=aliases)
    logging.info('Finished generating parameters.')
    return dbf
Exemplo n.º 2
0
def generate_parameters(phase_models,
                        datasets,
                        ref_state,
                        excess_model,
                        ridge_alpha=None,
                        aicc_penalty_factor=None,
                        dbf=None):
    """Generate parameters from given phase models and datasets

    Parameters
    ----------
    phase_models : dict
        Dictionary of components and phases to fit.
    datasets : PickleableTinyDB
        database of single- and multi-phase to fit.
    ref_state : str
        String of the reference data to use, e.g. 'SGTE91' or 'SR2016'
    excess_model : str
        String of the type of excess model to fit to, e.g. 'linear'
    ridge_alpha : float
        Value of the $alpha$ hyperparameter used in ridge regression. Defaults
        to None, which falls back to ordinary least squares regression.
        For now, the parameter is applied to all features.
    aicc_penalty_factor : dict
        Map of phase name to feature to a multiplication factor for the AICc's parameter penalty.
    dbf : Database
        Initial pycalphad Database that can have parameters that would not be fit by ESPEI

    Returns
    -------
    pycalphad.Database

    """
    logging.info('Generating parameters.')
    logging.log(
        TRACE,
        f'Found the following user reference states: {espei.refdata.INSERTED_USER_REFERENCE_STATES}'
    )
    phases = sorted(map(lambda x: x.upper(), phase_models['phases'].keys()))
    dbf = dbf or Database()
    dbf.elements.update(set(phase_models['components']))
    for el in dbf.elements:
        dbf.species.add(Species(el, {el: 1}, 0))
        # Add the SER reference data
        dbf.refstates[el] = espei.refdata.ser_dict[el]
        # update the refdata for this element with the reference phase
        if el not in espei.refdata.pure_element_phases.keys():
            # Probably VA, /- or something else
            continue
        refdata_phase = espei.refdata.pure_element_phases[el]
        if refdata_phase in phases:
            dbf.refstates[el]['phase'] = refdata_phase
        else:
            # Check all the aliases and set the one that matches
            for phase_name, phase_obj in phase_models['phases'].items():
                for alias in phase_obj.get('aliases', []):
                    if alias == refdata_phase:
                        dbf.refstates[el]['phase'] = phase_name
    # Write reference state to Database
    refdata = getattr(espei.refdata, ref_state)
    stabledata = getattr(espei.refdata, ref_state + 'Stable')
    for key, element in refdata.items():
        if isinstance(element, sympy.Piecewise):
            newargs = element.args + ((0, True), )
            refdata[key] = sympy.Piecewise(*newargs)
    for key, element in stabledata.items():
        if isinstance(element, sympy.Piecewise):
            newargs = element.args + ((0, True), )
            stabledata[key] = sympy.Piecewise(*newargs)
    comp_refs = {
        c.upper(): stabledata[c.upper()]
        for c in dbf.elements if c.upper() != 'VA'
    }
    comp_refs['VA'] = 0
    # note that the `c.upper()*2)[:2]` returns 'AL' for c.upper()=='AL' and 'VV' for c.upper()=='V'
    dbf.symbols.update(
        {'GHSER' + (c.upper() * 2)[:2]: data
         for c, data in comp_refs.items()})
    for phase_name, phase_obj in sorted(phase_models['phases'].items(),
                                        key=operator.itemgetter(0)):
        # Perform parameter selection and single-phase fitting based on input
        # TODO: Need to pass particular models to include: magnetic, order-disorder, etc.
        symmetry = phase_obj.get('equivalent_sublattices', None)
        aliases = phase_obj.get('aliases', None)
        # TODO: More advanced phase data searching
        site_ratios = phase_obj['sublattice_site_ratios']
        subl_model = phase_obj['sublattice_model']
        if phase_name not in dbf.phases.keys():
            dbf.add_phase(phase_name, dict(), site_ratios)
            dbf.add_phase_constituents(phase_name, subl_model)
            dbf.add_structure_entry(phase_name, phase_name)
        phase_fit(dbf,
                  phase_name,
                  symmetry,
                  subl_model,
                  site_ratios,
                  datasets,
                  refdata,
                  ridge_alpha,
                  aicc_penalty=aicc_penalty_factor,
                  aliases=aliases)
    logging.info('Finished generating parameters.')
    return dbf