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
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