ESPEI¶
Installation¶
Anaconda¶
Installing ESPEI from PyPI (by pip install espei
) is not supported.
Please install ESPEI using Anaconda package manager.
If you do not have Anaconda installed, we recommend you download and install Miniconda3.
Optionally, you may also be want to install JupyterLab at the same time.
conda install -c conda-forge espei jupyterlab
Development versions¶
To make changes to the ESPEI source code, the development version must be installed. If you’ll need to make changes to pycalphad simultaneously, follow the instructions to install the development version of pycalphad first.
We recommend that users interested in developing packages work in a
Conda virtual environment.
The steps below will create an environment called espei-dev
, which can be
entered using conda activate espei-dev
.
The environment name is arbitrary - you can use whatever name you prefer.
If you already have an environment, use conda env update ...
instead of
conda env create ...
when following the steps below.
ESPEI uses Git and GitHub for version control. Windows users: if you do not have a working version of Git, download it here first.
To install the latest development version of ESPEI, use Anaconda to install the
required dependencies using the environment-dev.yml
file found in ESPEI’s
repository, then install ESPEI as editable using pip
.:
git clone https://github.com/phasesresearchlab/espei.git
cd espei
conda env create -n espei-dev --file environment-dev.yml
conda activate espei-dev
pip install --no-deps -e .
Optionally, you may also be want to install JupyterLab.
Each environment needs its own copy of JupyterLab, so you will need to install
it even if it is already installed in your base
environment.
You can install it to your espei-dev
environment by running
conda install -n espei-dev jupyterlab
Every time you open a new terminal window, you start in the base
environment. You can activate your espei-dev
environment by running
conda activate espei-dev
and return to your base
environment by running
conda deactivate espei-dev
With the development version installed and your environment activated, you can run the automated tests by running
pytest
If the test suite passes, you are ready to start using the development version or making changes yourself! See the guide for contributing to ESPEI to learn more. If any tests fail, please report the failure to the ESPEI issue tracker on GitHub.
To upgrade your development version to the latest version, run git pull
from the top level ESPEI directory (the directory containing the setup.py
file).
Quickstart¶
ESPEI has two different fitting modes: parameter generation and Bayesian parameter estimation, which uses Markov Chain Monte Carlo (MCMC). You can run either of these modes or both of them sequentially.
To run either of the modes, you need to have a phase models file that describes the phases in the system using the standard CALPHAD approach within the compound energy formalism.
You also need to describe the data that ESPEI should fit to.
You will need single-phase and multi-phase data for a full run.
Fit settings and all datasets are stored as JSON files and described in detail at the Making ESPEI datasets page.
All of your input datasets should be validated by running espei --check-datasets my-input-datasets
, where my-input-datasets
is a folder of all your JSON files.
The main output result is going to be a database (defaults to out.tdb
), an array of the steps in the MCMC trace (defaults to trace.npy
), and the an array of the log-probabilities for each iteration and chain (defaults to lnprob.npy
).
Parameter Generation only¶
If you have only non-equilibrium thermochemical data, e.g. heat capacity, entropy and enthalpy data and mixing data from first-principles calculations, you may want to see the starting point for your MCMC calculation.
Create an input file called espei-in.yaml
.
system:
phase_models: my-phases.json
datasets: my-input-datasets
generate_parameters:
excess_model: linear
ref_state: SGTE91
Then ESPEI can be run by running
espei --input espei-in.yaml
Bayesian Parameter Estimation (MCMC) only¶
If you have a database already and want to do a Bayesian parameter estimation, you can specify a starting TDB file (named my-tdb.tdb
) with
system:
phase_models: my-phases.json
datasets: my-input-data
mcmc:
iterations: 1000
input_db: my-tdb.tdb
The TDB file you input must have all of the degrees of freedom you want as FUNCTIONs with names beginning with VV
.
Restart from previous run-phase only¶
If you’ve run an MCMC fitting already in ESPEI and have a trace file called my-previous-trace.npy
, then you can resume the calculation with the following input file
system:
phase_models: my-phases.json
datasets: my-input-data
mcmc:
iterations: 1000
input_db: my-tdb.tdb
restart_trace: my-previous-trace.npy
Full run¶
A minimal full run of ESPEI is done by the following
system:
phase_models: my-phases.json
datasets: my-input-data
generate_parameters:
excess_model: linear
ref_state: SGTE91
mcmc:
iterations: 1000
Input Customization¶
ESPEI lets you control many aspects of your calculations with the input files shown above. See ESPEI YAML input files for a full description of all possible inputs.
FAQ¶
Q: There is an error in my JSON files¶
A: Common mistakes are using single quotes instead of the double quotes required by JSON files. Another common source of errors is misaligned open/closing brackets.
Many mistakes are found with ESPEI’s check-datasets
utility.
Run espei check-datasets my-input-datasets
on your directory my-input-datasets
.
Q: How do I analyze my results?¶
A: By default, ESPEI will create trace.npy
and lnprob.npy
for the MCMC chain at the specified save interval and according to the save interval (defaults to ever iteration).
These are created from arrays via numpy.save()
and can thus be loaded with numpy.load()
.
Note that the arrays are preallocated with zeros.
These filenames and settings can be changed using in the input file.
You can then use these chains and corresponding log-probabilities to make corner plots, calculate autocorrelations, find optimal parameters for databases, etc..
Some examples are shown in the Recipes page.
Finally, you can use espei.plot
functions such as
espei.plot.dataplot()
in concert with pycalphad to plot phase diagrams
with your input equilibria data. The espei.plot.plot_endmember()
and
espei.plot.plot_interaction()
functions can be
used to compare single-phase data (e.g. formation and mixing data) with the
properties calculated from your database.
Q: Can I run ESPEI on a supercomputer supporting MPI?¶
A: Yes! ESPEI has MPI support. See the Advanced Schedulers page for more details.
Q: How is the log probability reported by ESPEI calculated?¶
MCMC simulation requires determining the probability of the data given a set of parameters, \(p(D|\theta)\). In MCMC, the log probability is often used to avoid floating point errors that arise from multiplying many small floating point numbers. For each type of data the error, often interpreted as the absolute difference between the expected and calculated value, is determined. For the types of data and how the error is calculated, refer to the ESPEI paper 1.
The error is assumed to be normally distributed around the experimental data point that the prediction of a set of parameters is being compared against.
The log probability of each data type is calculated by the log probability density function of the error in this normal distribution with a mean of zero and the standard deviation as given by the data type and the adjustable weights (see data_weights
in ESPEI YAML input files).
The total log probability is the sum of all log probabilities.
Note that any probability density function always returns a positive value between 0 and 1, so the log probability density function should return negative numbers and the log probability reported by ESPEI should be negative.
Q: Why is the version of ESPEI ‘0+unknown’?¶
A: A version number of '0+unknown'
indicates that you do not have git installed.
This can occur on Windows where git is not in the PATH (and the Python interpreter cannot see it).
You can install git using conda install git
on Windows.
Q: I have a large database, can I use ESPEI to optimize parameters in only a subsystem?¶
A: Yes, if you have a multicomponent CALPHAD database, but want to optimize or determine the uncertainty for a constituent unary, binary or ternary subsystem that you have data for, you can do that without any extra effort.
You may be interested in the symbols input parameter to specify which parameter subset to optimize.
Note that if you optimize parameters in a subsystem (e.g. Cu-Mg) that is used in a higher order description (e.g. Al-Cu-Mg), you may need to reoptimize the parameters for the higher order system as well.
References¶
- 1
Bocklund, R. Otis, A. Egorov, A. Obaied, I. Roslyakova, Z.-K. Liu, ESPEI for efficient thermodynamic database development, modification, and uncertainty quantification: application to Cu–Mg, MRS Commun. (2019) 1–10. doi:10.1557/mrc.2019.59.
ESPEI, or Extensible Self-optimizing Phase Equilibria Infrastructure, is a tool for thermodynamic database development within the CALPHAD method. It uses pycalphad for calculating Gibbs free energies of thermodynamic models.
What is ESPEI?¶
ESPEI parameterizes CALPHAD models with enthalpy, entropy, and heat capacity data using the corrected Akiake Information Criterion (AICc). This parameter generation step augments the CALPHAD modeler by providing tools for data-driven model selection, rather than relying on a modeler’s intuition alone.
ESPEI optimizes CALPHAD model parameters to thermochemical and phase boundary data and quantifies the uncertainty of the model parameters using Markov Chain Monte Carlo (MCMC). This is similar to the PARROT module of Thermo-Calc, but goes beyond by adjusting all parameters simultaneously and evaluating parameter uncertainty.
Details on the implementation of ESPEI can be found in the publication: B. Bocklund et al., MRS Communications 9(2) (2019) 1–10. doi:10.1557/mrc.2019.59.
What ESPEI can do?¶
ESPEI can be used to generate model parameters for CALPHAD models of the Gibbs energy that follow the temperature-dependent polynomial by Dinsdale (CALPHAD 15(4) 1991 317-425) within the compound energy formalism (CEF) for endmembers and Redlich-Kister-Mugganu excess mixing parameters in unary, binary and ternary systems.
All thermodynamic quantities are computed by pycalphad. The MCMC-based Bayesian parameter estimation can optimize data for any model that is supported by pycalphad, including models beyond the endmember Gibbs energies Redlich-Kister-Mugganiu excess terms, such as parameters in the ionic liquid model, magnetic, or two-state models. Performing Bayesian parameter estimation for arbitrary multicomponent thermodynamic data is supported.
Goals¶
Offer a free and open-source tool for users to develop multicomponent databases with quantified uncertainty
Enable development of CALPHAD-type models for Gibbs energy, thermodynamic or kinetic properties
Provide a platform to build and apply novel model selection, optimization, and uncertainty quantification methods
The implementation for ESPEI involves first performing parameter generation by calculating parameters in thermodynamic models that are linearly described by non-equilibrium thermochemical data. Then Markov Chain Monte Carlo (MCMC) is used to optimize the candidate models from the parameter generation to phase boundary data.

Cu-Mg phase diagram from a database created with and optimized by ESPEI. See the Cu-Mg Example.¶
History¶
The ESPEI package is based on a fork of pycalphad-fitting. The name and idea of ESPEI are originally based off of Shang, Wang, and Liu, ESPEI: Extensible, Self-optimizing Phase Equilibrium Infrastructure for Magnesium Alloys Magnes. Technol. 2010 617-622 (2010).
Implementation details for ESPEI have been described in the following publications:
Bocklund et al., MRS Communications 9(2) (2019) 1–10. doi:10.1557/mrc.2019.59
Otis et al., JOM 69 (2017) doi:10.1007/s11837-017-2318-6
Richard Otis’s thesis
Change log¶
What’s New¶
Development: 0.8.2+0.g64db6ce.dirty¶
0.8.2 (2021-05-05)¶
0.8.1 (2021-04-22)¶
This is a minor release that fixes a performance regression and retires unused utility code.
Fixes a performance regression in
_sample_solution_constitution
that could cause getting ZPF data for MCMC to be extremely slow. (@bocklund - issue 174)The
flexible_open_string
andadd_bibtex_to_bib_database
utilities were removed. Both were unusued in ESPEI. ESPEI no longer depends onbibtexparser
. (@bocklund - issue 171)
0.8 (2021-04-19)¶
This is a major release with bug fixes and a backward compatible public API, but breaking changes in the behavior of parameter selection and MCMC parameter estimation. Some internal functions were deprecated.
Improvements¶
Revamped internal logging. For users, ESPEI now has namespaced logging and filters out all non-ESPEI logs (e.g. dask and matplotlib). This change also fixed a bug where changing the verbosity in Jupyter was not taking effect. (@bocklund - issue 165)
Fixed a bug where scalar weights of non-equilibrium thermochemical datasets were not being broadcasted correctly and raised errors. (@bocklund - issue 154)
Fixed a bug where non-equilibrium thermochemical datasets using broadcasted temperatures and compositions were broadcasted against the values incorrectly. (@bocklund - issue 154)
Allow disabling datasets semantically using
disabled: true
in JSON datasets. (@bocklund - issue 153)Users can now pass custom SER reference data to override SER phases, mass, H298, and S298 for existing elements or new elements. Includes better warnings for common errors when the SER data is incompatible with the phases being fit. (@bocklund - issue 158)
Fixed a bug in computing activity error in MCMC where species were not correctly generated from the pure comopnents. (@bocklund - issue 152)
Breaking changes¶
Driving forces in ZPF error are now computed from local minimum solutions rather than global minimum solutions. This change significantly improves the convergence for any phases with stable or metastable miscibility gaps. It also prevents users from prescribing phase composition conditions that cannot be satisfied. See the linked GitHub issue for a detailed description of the rationale and implementation of this change. (@bocklund - issue 151)
Removed automatically added ideal exclusions, which was deprecated in ESPEI 0.7. Non-equilibrium thermochemical data should use the
excluded_model_contributions
key to excludeidmix
,mag
or other model contributions. (@bocklund - issue 168)
Deprecations¶
Setting
mcmc.scheduler
to the string"None"
to get a serial scheduler is deprecated. Users should usenull
in YAML/JSON orNone
in Python.Deprecated
multiplot
andeqdataplot
in favor of having users composebinplot
anddataplot
. pycalphad’sbinplot
is much faster thanmultiplot
. The extra functional call added is worth removing the maintenance burden and allows users to understand more explictly the difference between plotting data and plotting the calculated phase diagram. The documentation was updated to reflect this change and no longer usesmultiplot
. (@bocklund - issue 162)
0.7.12 (2021-03-16)¶
This is a minor bugfix release that updates the SGTE reference state data for carbon and more strictly specifies dependences. No changes to the code were made since 0.7.11.
0.7.11 (2021-03-12)¶
This is a minor bugfix release with backwards compatible changes.
0.7.10 (2020-11-14)¶
This is a minor bugfix release that addresses a potential inconsistency with hyphen/underscore usage in dask configuration files (@bocklund - issue 136).
0.7.9 (2020-11-12)¶
This is a minor maintenance release that automatically disables work stealing (users are no longer required to configure this themselves) (@bocklund - issue 134).
0.7.8 (2020-11-10)¶
This is a bug fix release with backwards compatible changes.
0.7.7 (2020-04-11)¶
This is a minor feature and bug fix release with backwards compatible changes.
Preliminary support for thermochemical error for arbitrary properties (@bocklund - issue 124)
Update the preferred method for disabling tracefile, probfile, logfile, and no scheduler in YAML to use
null
instead of"None"
(@bocklund - issue 125)Fix a bug in
truncate_arrays
andoptimal_parameters
to allow some zeros (@bocklund - issue 122)Enable custom unary reference states for parameter generation with entry_points plugin system (@bocklund - issue 121)
0.7.6 (2020-03-27)¶
This is a minor bug fix release.
0.7.5 (2020-03-09)¶
This release includes performance optimizations, bug fixes and new features for MCMC simulations.
This version of ESPEI now requires pycalphad 0.8.2 or later for the features below.
Fitting subsystems of a large database is explicitly supported and tested for all implemented MCMC data types. Fixes a bug in ZPF error and activity error where having phases in the database that are inactive in the subsystem would raise errors (@bocklund - issue 118).
Computing thermochemical error and phase boundary (ZPF) error are now optimized to reduce overhead time in dependencies (@bocklund - issue 117)
A new feature for calculating approximate driving force for phase boundary data is implemented, which can give performance improvements of 3x-10x, depending on the system (@bocklund - issue 115)
0.7.4 (2019-12-09)¶
This release includes small fixes for parameter generation.
0.7.3 (2019-12-02)¶
This change includes several new features and performance improvements.
Drop Python 2 support (Python 2 is no longer supported on January 1, 2020).
Update dask and distributed support to versions >=2. (@bocklund)
Users can tweak the AICc penalty factor for each phase to nudge parameter selection towards adding more or fewer parameters based on user modeling intuition. (@bocklund)
Allow for tracefile and probfile to be set to None. (@jwsiegel2510)
Weighting individual datasets in single phase fitting is now implemented via scikit-learn. (@bocklund)
Performance improvements by reducing overhead. (@bocklund)
Increased solver accuracy by using pycalphad’s exact Hessian solver. (@bocklund)
Support writing SER reference state information to the ELEMENT keyword in TDBs based on the SGTE unary 5 database. (@bocklund)
MCMC now calculates the likelihood of the initial parameter set so the starting point can be reasonably compared. (@bocklund)
Fixed a bug where mis-aligned configurations and site occupancies in single phase datasets passed the dataset checker (@bocklund)
0.7.2 (2019-06-12)¶
This is a small bugfix release that fixes the inability to provide the EmceeOptimizer a restart_trace
.
0.7.1 (2019-06-03)¶
This is a significant update reflecting many internal improvements, new features, and bug fixes. Users using the YAML input or the run_espei
Python API should see entirely backwards compatible changes with ESPEI 0.6.2.
pycalphad 0.8, which introduced many key features for these changes is now required. This should almost completely eliminate the time to build phases due to the symengine backend (phases will likely build in less time than to call the MCMC objective function). Users can expect a slight performance improvement for MCMC fitting.
Improvements¶
Priors can now be specified and are documented online.
Weights for different datasets are added and are supported by a
"weight"
key at the top level of any dataset.Weights for different types of data are added. These are controlled via the input YAML and are documented there.
A new internal API is introduced for generic fitting of parameters to datasets in the
OptimizerBase
class. The MCMC optimizer in emcee was migrated to this API (themcmc_fit
function is now deprecated, but still works until the next major version of ESPEI). A simple SciPy-based optimizer was implemented using this API.Parameter selection can now be passed initial databases with parameters (e.g. for adding magnetic or other parameters manually).
pycalphad’s reference state support can now be used to properly reference out different types of model contributions (ideal mixing, magnetic, etc.). This is especially useful for DFT thermochemical data which does not include model contributions from ideal mixing or magnetic heat capacity. Useful for experimental data which does include ideal mixing (previously ESPEI assumed all data
Datasets and input YAML files now have a tag system where tags that are specified in the input YAML can override any keys/values in the JSON datasets at runtime. This is useful for tagging data with different weights/model contribution exclusions (e.g. DFT tags may get lower weights and can be set to exclude model contributions). If no tags are applied, removing ideal mixing from all thermochemical data is applied automatically for backwards compatibility. This backwards compatibility feature will be removed in the next major version of ESPEI (all model contributions will be included by default and exclusions must be specified manually).
Bug fixes¶
Bug fixed where asymmetric ternary parameters were not properly replaced in SymPy
Fixed error where ZPF error was considering the chemical potentials of stoichiometric phases in the target hyperplane (they are meaningless)
Report the actual file paths when dask’s work-stealing is set to false.
Errors in the ZPF error function are no longer swallowed with -np.inf error. Any errors should be reported as bugs.
Fix bug where subsets of symbols to fit are not built properly for thermochemical data
Other¶
Documentation recipe added for plot_parameters
[Developer] ZPF and thermochemical datasets now have an function to get all the data up front in a dictionary that can be used in the functions for separation of concerns and calculation efficiency by not recalculating the same thing every iteration.
[Developer] a function to generate the a context dict to pass to lnprob now exists. It gets the datasets automatically using the above.
[Developer] transition to pycalphad’s new build_callables function, taking care of the
v.N
state variable.[Developer] Load all YAML safely, silencing warnings.
0.6.2 (2018-11-27)¶
This backwards-compatible release includes several bug fixes and improvements.
Updated branding to include the new ESPEI logo. See the logo in the
docs/_static
directory.Add support for fitting excess heat capacity.
Bug fix for broken potassium unary.
Documentation improvements for recipes
pycalphad 0.7.1 fixes for dask, sympy, and gmpy2 should mean that ESPEI should not require package upgrade or downgrades. Please report any installations issues in ESPEI’s Gitter Channel.
[Developers] ESPEI’s
eq_callables_dict
is nowpycalphad.codegen.callables.build_callables
.[Developers] matplotlib plotting tests are removed because nose is no longer supported.
0.6.1 (2018-08-28)¶
This a major release with several important features and bug fixes.
Enable use of ridge regression alpha for parameter selection via the
parameter_generation.ridge_alpha
input parameter.Add ternary parameter selection. Works by default, just add data.
Set memory limit to zero to avoid dask killing workers near the dask memory limits.
Remove ideal mixing from plotting models so that
plot_parameters
gives the correct entropy values.Add recipes documentation that contains some Python code for common utility operations.
Add documentation for running custom distributed schedulers in ESPEI
0.6 (2018-07-02)¶
This is a update including breaking changes to the input files and several minor improvements.
Update input file schema and Python API to be more consistent so that the
trace
always refers to the collection of chains andchain
refers to individual chains. Additionally removed some redundancy in the parameters nested under themcmc
heading, e.g.mcmc_steps
is nowiterations
andmcmc_save_interval
is nowsave_interval
in the input file and Python API. See Writing Input documentation for all of the updates.The default save interval is now 1, which is more reasonable for most MCMC systems with significant numbers of phase equilibria.
Bug fixes for plotting and some better plotting defaults for plotting input data
Dataset parsing and cleaning improvements.
Documentation improvements (see the PDF!)
0.5.2 (2018-04-28)¶
This is a major bugfix release for MCMC multi-phase fitting runs for single phase data.
Fixed a major issue where single phase thermochemical data was always compared to Gibbs energy, giving incorrect errors in MCMC runs.
Single phase errors in ESPEI incorrectly compared values with ideal mixing contributions to data, which is excess only.
Fixed a bug where single phase thermochemical data with that are dependent on composition and pressure and/or temperature were not fit correctly.
Added utilities for analyzing ESPEI results and add them to the Cu-Mg example docs.
0.5.1 (2018-04-17)¶
This is a minor bugfix release.
Parameter generation for phases with vacancies would produce incorrect parameters because the vacancy site fractions were not being correctly removed from the contributions due to their treatment as
Species
objects inpycalphad >=0.7
.
0.5 (2018-04-03)¶
Parameter selection now uses the corrected AIC, which further prevents overparameterization where there is sparse training data.
Activity and single phase thermochemical data can now be included in MCMC fitting runs. Including single phase data can help anchor metastable phases to DFT data when they are not on the stable phase diagram. See the Gathering input data documentation for information on how to input activity data.
Dataset checking has been improved. Now there are checks to make sure sublattice interactions are properly sorted and mole fractions sum to less than 1.0 in ZPF data.
Support for fitting phases with arbitrary pycalphad Models in MCMC, including (charged and neutral) species and ionic liquids. There are several consequences of this:
ESPEI requires support on
pycalphad >=0.7
ESPEI now uses pycalphad
Model
objects directly. Using the JIT compiled Models has shown up to a 50% performance improvement in MCMC runs.Using JIT compiled
Model
objects required the use ofcloudpickle
everywhere. Due to challenges in overridingpickle
for upstream packages, we now rely solely ondask
for scheduler tasks, includingmpi
viadask-mpi
. Note that users must turn offwork-stealing
in their~/.dask/config.yaml
file.
[Developers] Each method for calculating error in MCMC has been moved into a module for that method in an
error_functions
subpackage. One top level function from each module should be imported into themcmc.py
and used inlnprob
. Developers should then just customizelnprob
.[Developers] Significant internal docs improvements: all non-trivial functions have complete docstrings.
0.4.1 (2018-02-05)¶
Enable plotting of isothermal sections with data using
dataplot
(andmultiplot
, etc.)Tielines are now plotted in
dataplot
for isothermal sections and T-x phase diagramsAdd a useful
ravel_conditions
method to unpack conditions from datasets
0.4 (2017-12-29)¶
MCMC is now deterministic by default (can be toggled off with the
mcmc.deterministic
setting).Added support for having no scheduler (running with no parallelism) with the
mcmc.scheduler
option set toNone
. This may be useful for debugging.Logging improvements
Extraneous warnings that may be confusing for users and dirty the log are silenced.
A warning is added for when there are no datasets found.
Fixed a bug where logging was silenced with the dask scheduler
Add
optimal_parameters
utility function as a helper to get optimal parameter sets for analysisSeveral improvements to plotting
Users can now plot phase diagram data alone with
dataplot
, useful for checking datasets visually. This changes the API fordataplot
to no longer infer the conditions from an equilibriumDataset
(from pycalphad). That functionality is preserved ineqdataplot
.Experimental data points are now plotted with unique symbols depending on the reference key in the dataset. This is for both phase diagram and single phase parameter plots.
Options to control plotting parameters (e.g. symbol size) and take user supplied Axes and Figures in the plotting functions. The symbol size is now smaller by default.
Documentation improvements for API and separation of theory from the Cu-Mg example
Fixes a bug where elements with single character names would not find the correct reference state (which are typically named GHSERCC for the example of C).
[Developer] All MCMC code is moved from the
paramselect
module to themcmc
module to separate these tasks[Developer] Support for arbitrary user reference states (so long as the reference state is in the
refdata
module and follows the same format as SGTE91)
0.3.1.post2 (2017-10-31)¶
Propagate the new entry point to setup.py
0.3.1.post1 (2017-10-31)¶
Fix for module name/function conflict in entry point
0.3.1 (2017-10-31)¶
ESPEI is much easier to run interactively in Python and in Jupyter Notebooks
Reference data is now included in ESPEI instead of in pycalphad
Several reference data fixes including support for single character elements (‘V’, ‘B’, ‘C’, …)
Support for using multiprocessing to parallelize MCMC runs, used by default (@olivia-higgins)
Improved documentation for installing and developing ESPEI
0.3.post2 (2017-09-20)¶
Add input-schema.yaml file to installer
0.3.post1 (2017-09-20)¶
Add LICENSE to manifest
0.3 (2017-09-20)¶
ESPEI input is now described by a file. This change is breaking. Old command line arguments are not supported. See Writing input files for a full description of all the inputs.
New input options are supported, including modifying the number of chains and standard deviation from the mean
ESPEI is now available on conda-forge
TinyDB 2 support is dropped in favor of TinyDB 3 for conda-forge deployment
Allow for restarting previous mcmc calculations with a trace file
Add Cu-Mg example to documentation
0.2.1 (2017-08-17)¶
Fixes to the 0.2 release plotting interface
multiplot
is renamed frommulti_plot
, as in docs.Fixed an issue where phases in datasets, but not in equilibrium were not plotted by dataplot and raised an error.
0.2 (2017-08-15)¶
New
multiplot
interface for convenient plotting of phase diagrams + data.dataplot
function underlies key data plotting features and can be used witheqplot
. See their API docs for examples. Will break existing code using multiplot.MPI support for local/HPC runs. Only single node runs are explicitly supported currently. Use
--scheduler='MPIPool'
command line option. Requiresmpi4py
.Default debug reporting of acceptance ratios
Option (and default) to output the log probability array matching the trace. Use
--probfile
option to control.Optimal parameters are now chosen based on lowest error in chain.
Bug fixes including
py2/3 compatibility
Unicode datasets
handling of singular matrix errors from pycalphad’s
equilibrium
reporting of failed conditions
0.1.5 (2017-08-02)¶
Significant error checking of JSON inputs.
Add new
--check-datasets
option to check the datasets at path. It should be run before you run ESPEI fittings. All errors must be resolved before you run.Move the espei script module from
fit.py
torun_espei.py
.Better docs building with mocking
Google docstrings are now NumPy docstrings
0.1.4 (2017-07-24)¶
Documentation improvements for usage and API docs
Fail fast on JSON errors
0.1.3 (2017-06-23)¶
Fix bad version pinning in setup.py
Explicitly support Python 2.7
0.1.2 (2017-06-23)¶
Fix dask incompatibility due to new API usage
0.1.1 (2017-06-23)¶
Fix a bug that caused logging to raise if bokeh isn’t installed
0.1 (2017-06-23)¶
ESPEI is now a package! New features include
Use emcee for MCMC fitting rather than pymc
Support single-phase only fitting
More control options for running ESPEI from the command line
Better support for incremental saving of the chain
Control over output with logging over printing
Significant code cleanup
Better usage documentation
See what’s new!
Cu-Mg Example¶
The Cu-Mg binary system is an interesting and simple binary subsystem for light metal alloys. It has been modeled in the literature by Coughanowr et al. 1, Zuo and Chang 2 and Zhou et al. 3 and was featured as a case study in Computational Thermodynamics The Calphad Method by Lukas, Fries, & Sundman 4.
Here we will combine density functional theory and experimental calculations of single-phase data to generate a first-principles phase diagram. Then that database will be used as a starting point for a Markov Chain Monte Carlo (MCMC) Bayesian optimization of the parameters to fit zero-phase fraction data.
Input data¶
All of the input data for ESPEI is stored in a public ESPEI-datasets repository on GitHub. The data in this repository is Creative Commons Attribution 4.0 (CC-BY-4.0) licensed and may be used, commercialized or reused freely.
In order to run ESPEI with the data in ESPEI-datasets, you should clone this repository to your computer. Files referred to throughout this tutorial are found in the CU-MG folder. The input files will be very breifly explained in this tutorial so that you are able to know their use. A more detailed description of the files is found on the Making ESPEI datasets page.
If you make changes or additions, you are encouraged to share these back to the ESPEI-datasets repository so that others may benefit from this data as you have. You may then add your name to the CONTRIBUTORS file as described in the README.
Phases and CALPHAD models¶
The Cu-Mg system contains five stable phases: Liquid, disordered fcc and hcp, the C15 Laves phase and the CuMg2 phase. All of these phases will be modeled as solution phases, except for CuMg2, which will be represented as a stoichiometric compound. The phase names and corresponding sublattice models are as follows:
LIQUID: (CU, MG)1
FCC_A1: (CU, MG)1 (VA)1
HCP_A3: (CU, MG)1 (VA)1
LAVES_C15: (CU, MG)2 (CU, MG)1
CUMG2: (CU)1 (MG)2
These phase names and sublattice models are described in the JSON file Cu-Mg-input.json file as seen below
{
"components": ["CU", "MG", "VA"],
"phases": {
"LIQUID" : {
"sublattice_model": [["CU", "MG"]],
"sublattice_site_ratios": [1]
},
"CUMG2": {
"sublattice_model": [["CU"], ["MG"]],
"sublattice_site_ratios": [1, 2]
},
"FCC_A1": {
"sublattice_model": [["CU", "MG"], ["VA"]],
"sublattice_site_ratios": [1, 1]
},
"HCP_A3": {
"sublattice_site_ratios": [1, 0.5],
"sublattice_model": [["CU", "MG"], ["VA"]]
},
"LAVES_C15": {
"sublattice_site_ratios": [2, 1],
"sublattice_model": [["CU", "MG"], ["CU", "MG"]]
}
}
}
ESPEI¶
ESPEI has two types of fitting – parameter generation and MCMC optimization. The parameter generation step uses experimental and first-principles data of the derivatives of the Gibbs free energy to parameterize the Gibbs energies of each individual phase. The MCMC optimization step fits the generated parameters to experimental phase equilibria data. These two fitting procedures can be used together to fully assess a given system. For clarity, we will preform these steps separately to fit Cu-Mg. The next two sections are devoted to describing ESPEI’s parameter generation and optimization.
Though it should be no problem for this case, since the data has already been
used, you should get in the habit of checking datasets before running ESPEI.
ESPEI has a tool to help find and report problems in your datasets. This is
automatically run when you load the datasets, but will fail on the first error.
Running the following commmand (assuming from here on that you are in the
CU-MG
folder from ESPEI-datasets):
espei --check-datasets input-data
The benefit of the this approach is that all of the datasets will be checked and
reported at once. If there are any failures, a list of them will be reported
with the two main types of errors being JSONError
, for which you should read
the JSON section of Making ESPEI datasets, or DatasetError
, which are related to
the validity of your datasets scientifically (maching conditions and values
shape, etc.). The DatasetError
messages are designed to be clear, so please
open an issue on GitHub
if there is any confusion.
First-principles phase diagram¶
By using the Cu-Mg-input.json
phase description for the fit settings and
passing all of the input data in the input-data
folder, we can first use
ESPEI to generate a phase diagram based on single-phase experimental and DFT
data. Currently all of the input datasets must be formation properties, and it
can be seen that the formation enthalpies are defined from DFT and experiments
for the Laves and CuMg2 phases. Mixing enthalpies are defined for the for the
fcc, hcp, and Laves phases from DFT and for liquid from experimental
measurements.
The following command will generate a database named cu-mg_dft.tdb
with
parameters selected and fit by ESPEI:
espei --input espei-in.yaml
where espei-in.yaml
is a ESPEI input file with
the following contents
system:
phase_models: Cu-Mg-input.json
datasets: input-data
generate_parameters:
excess_model: linear
ref_state: SGTE91
output:
output_db: cu-mg_dft.tdb
The calculation should be relatively quick, on the order of a minute of runtime.
With the above command, only mininmal output (warnings) will be reported. You
can increase the verbosity to report info messages by setting the
output.verbosity
key to 1
or debug messages with 2
.
With the following code, we can look at the generated phase diagram and compare it to our data.
# First-principles phase diagram
from pycalphad import Database, binplot, variables as v
from espei.datasets import load_datasets, recursive_glob
from espei.plot import dataplot
import matplotlib.pyplot as plt
# load the experimental and DFT datasets
datasets = load_datasets(recursive_glob('input-data', '*.json'))
# set up the pycalphad phase diagram calculation
dbf = Database('cu-mg_dft.tdb')
comps = ['CU', 'MG', 'VA']
phases = ['LIQUID', 'FCC_A1', 'HCP_A3', 'CUMG2', 'LAVES_C15']
conds = {v.P: 101325, v.T: (300, 1500, 10), v.X('MG'): (0, 1, 0.01)}
# plot the phase diagram and data
ax = binplot(dbf, comps, phases, conds)
dataplot(comps, phases, conds, datasets, ax=ax)
ax.figure.savefig('cu-mg_dft_phase_diagram.png')
Which should result in the following figure

First-principles Cu-Mg phase diagram from the single-phase fitting in ESPEI¶
We can see that the phase diagram is already very reasonable compared to the experimental points. The liquidus temperatures and the solubilities of the fcc and Laves phases are the key differences between the equilibrium data and our first-principles phase diagram. The next section will discuss using ESPEI to optimize the parameters selected and calculated based on all the data.
MCMC optimization¶
With the data in the CU-MG input data, ESPEI generated 18 parameters to fit. For systems with more components, solution phases, and input data, may more parameters could be required to describe the thermodynamics of the specific system well. Because they describe Gibbs free energies, parameters in CALPHAD models are highly correlated in both single-phase descriptions and for describing equilibria between phases. For large systems, global numerical optimization of many parameters simultaneously is computationally intractable.
To combat the problem of optimizing many paramters, ESPEI uses MCMC, a stochastic optimzation method.
Now we will use our zero phase fraction equilibria data to optimize our
first-principles database with MCMC. The following command will take the
database we created in the single-phase parameter selection and perform a MCMC
optimization, creating a cu-mg_mcmc.tdb
:
espei --input espei-in.yaml
where espei-in.yaml
is an ESPEI input file with
the following structure
system:
phase_models: Cu-Mg-input.json
datasets: input-data
mcmc:
iterations: 1000
input_db: cu-mg_dft.tdb
output:
output_db: cu-mg_mcmc.tdb
ESPEI defaults to run 1000 iterations and depends on calculating equilibrium in pycalphad several times for each iteration and the optimization is compute-bound. Fortunately, MCMC optimzations are embarrasingly parallel and ESPEI allows for parallelization using dask or with MPI using mpi4py (single-node only at the time of writing - we are working on it).
Note that you may also see messages about convergence failures or about droppping conditions. These refer to failures to calculate the log-probability or in the pycalphad solver’s equilibrium calculation. They are not detrimental to the optimization accuracy, but overall optimization may be slower because those parameter proposals will never be accepted (they return a log-probability of \(-\infty\)).
Finally, we can use the newly optimized database to plot the phase diagram
# Optimized phase diagram from ESPEI's MCMC fitting
from pycalphad import Database, binplot, variables as v
from espei.datasets import load_datasets, recursive_glob
from espei.plot import dataplot
import matplotlib.pyplot as plt
# load the experimental and DFT datasets
datasets = load_datasets(recursive_glob('input-data', '*.json'))
# set up the pycalphad phase diagram calculation
dbf = Database('cu-mg_mcmc.tdb')
comps = ['CU', 'MG', 'VA']
phases = ['LIQUID', 'FCC_A1', 'HCP_A3', 'CUMG2', 'LAVES_C15']
conds = {v.P: 101325, v.T: (300, 1500, 10), v.X('MG'): (0, 1, 0.01)}
# plot the phase diagram and data
ax = binplot(dbf, comps, phases, conds)
dataplot(comps, phases, conds, datasets, ax=ax)
ax.figure.savefig('cu-mg_mcmc_phase_diagram.png')

Optimized Cu-Mg phase diagram from the MCMC fitting in ESPEI¶
Analyzing ESPEI Results¶
After finishing a MCMC run, you will want to analyze your results.
All of the MCMC results will be maintained in two output files, which
are serialized NumPy arrays. The file names are set in your
espei-in.yaml
file. The filenames are set by output.tracefile
and output.probfile
(documentation)
and the defaults are trace.npy
and lnprob.npy
, respectively.
The tracefile
contains all of the parameters that were proposed over
all chains and iterations (the trace). The probfile
contains all of
calculated log probabilities for all chains and iterations (as negative
numbers, by convention).
There are several aspects of your data that you may wish to analyze. The next sections will explore some of the options.
Probability convergence¶
First we’ll plot how the probability changes for all of the chains as a function of iterations. This gives a qualitative view of convergence. There are several quantitative metrics that we won’t explore here, such as autocorrelation. Qualitatively, this run does not appear converged after 115 iterations.
# remove next line if not using iPython or Juypter Notebooks
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from espei.analysis import truncate_arrays
trace = np.load('trace.npy')
lnprob = np.load('lnprob.npy')
trace, lnprob = truncate_arrays(trace, lnprob)
ax = plt.gca()
ax.set_yscale('log')
ax.set_ylim(1e7, 1e10)
ax.set_xlabel('Iterations')
ax.set_ylabel('- lnprob')
num_chains = lnprob.shape[0]
for i in range(num_chains):
ax.plot(-lnprob[i,:])
plt.show()

Visualizing the trace of each parameter¶
We would like to see how each parameter changed during the iterations. For brevity in the number of plots we’ll plot all the chains for each parameter on the same plot. Here we are looking to see how the parameters explore the space and converge to a solution.
# remove next line if not using iPython or Juypter Notebooks
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from espei.analysis import truncate_arrays
trace = np.load('trace.npy')
lnprob = np.load('lnprob.npy')
trace, lnprob = truncate_arrays(trace, lnprob)
num_chains = trace.shape[0]
num_parameters = 3 # only plot the first three parameter, for all of them use `trace.shape[2]`
for parameter in range(num_parameters):
ax = plt.figure().gca()
ax.set_xlabel('Iterations')
ax.set_ylabel('Parameter value')
for chain in range(num_chains):
ax.plot(trace[chain, :, parameter])
plt.show()



Corner plots¶
Note: You must install the corner
package before using it
(conda install corner
or pip install corner
).
In a corner plot, the distributions for each parameter are plotted along the diagonal and covariances between them under the diagonal. A more circular covariance means that parameters are not correlated to each other, while elongated shapes indicate that the two parameters are correlated. Strongly correlated parameters are expected for some parameters in CALPHAD models within phases or for phases in equilibrium, because increasing one parameter while decreasing another would give a similar error.
# remove next line if not using iPython or Juypter Notebooks
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import corner
from espei.analysis import truncate_arrays
trace = np.load('trace.npy')
lnprob = np.load('lnprob.npy')
trace, lnprob = truncate_arrays(trace, lnprob)
# flatten the along the first dimension containing all the chains in parallel
fig = corner.corner(trace.reshape(-1, trace.shape[-1]))
plt.show()

Ultimately, there are many features to explore and we have only covered a few basics. Since all of the results are stored as arrays, you are free to analyze using whatever methods are relevant.
Summary¶
ESPEI allows thermodynamic databases to be easily reoptimized with little user interaction, so more data can be added later and the database reoptimized at the cost of only computer time. In fact, the existing database from estimates can be used as a starting point, rather than one directly from first-principles, and the database can simply be modified to match any new data.
References¶
- 1
Coughanowr, C. A., Ansara, I., Luoma, R., Hamalainen, M. & Lukas, H. L. Assessment of the Cu-Mg system. Zeitschrift f{ü}r Met. 82, 574–581 (1991).
- 2
Zuo, Y. U. E. & Chang, Y. A. Thermodynamic calculation of the Mg-Cu phase diagram. Zeitschrift f{ü}r Met. 84, 662–667 (1993).
- 3
Zhou, S. et al. Modeling of Thermodynamic Properties and Phase Equilibria for the Cu-Mg Binary System. J. Phase Equilibria Diffus. 28, 158–166 (2007). doi:10.1007/s11669-007-9022-0
- 4
Lukas, H., Fries, S. G. & Sundman, B. Computational Thermodynamics The Calphad Method. (Cambridge University Press, 2007). doi:10.1017/CBO9780511804137
Acknowledgements¶
Credit for initially preparing the datasets goes to Aleksei Egorov.
ESPEI YAML input files¶
This page aims to completely describe the ESPEI input file in the YAML format. Possibly useful links are the YAML refcard and the (possibly less useful) Full YAML specification. These are all key value pairs in the format
key: value
They are nested for purely organizational purposes.
top_level_key:
key: value
As long as keys are nested under the correct heading, they have no required order. All of the possible keys are
system:
phase_models
datasets
tags
output:
verbosity
logfile
output_db
tracefile
probfile
generate_parameters:
excess_model
ref_state
ridge_alpha
aicc_penalty_factor
input_db
mcmc:
iterations
prior
save_interval
cores
scheduler
input_db
restart_trace
chains_per_parameter
chain_std_deviation
deterministic
approximate_equilibrium
data_weights
symbols
The next sections describe each of the keys individually.
If a setting has a default of required
it must be set explicitly.
system¶
The system
key is intended to describe the specific system you are fitting, including the components, phases, and the data to fit to.
phase_models¶
- type
string
- default
required
The JSON file describing the CALPHAD models for each phase. See Phase Descriptions for an example of how to write this file.
datasets¶
- type
string
- default
required
The path to a directory containing JSON files of input datasets.
The file extension to each of the datasets must be named as .json
, but they can otherwise be named freely.
For an examples of writing these input JSON files, see Making ESPEI datasets.
tags¶
- type
dict
- default
required
Mapping of keys to values to add to datasets with matching tags. These can be used to dynamically drive values in datasets without adjusting the datasets themselves. Useful for adjusting weights or other values in datasets in bulk. For an examples of using tags in input JSON files, see Tags.
output¶
verbosity¶
- type
int
- default
0
Controls the logging level. Most users will probably want to use Info
or Trace
.
Warning
logs should almost never occur and this log level will be
relatively quiet. Debug
is a fire hose of information, but may be useful in
fixing calculation errors or adjusting weights.
Value |
Log Level |
---|---|
0 |
Warning |
1 |
Info |
2 |
Trace |
3 |
Debug |
logfile¶
- type
string
- default
null
Name of the file that the logs (controlled by verbosity
) will be output to.
The default is None
(in Python, null
in YAML), meaning the logging will
be output to stdout and stderr.
output_db¶
- type
string
- default
out.tdb
The database to write out. Can be any file format that can be written by a pycalphad Database.
tracefile¶
- type
string
- default
trace.npy
Name of the file that the MCMC trace is written to.
The array has shape (number of chains, iterations, number of parameters)
.
The array is preallocated and padded with zeros, so if you selected to take 2000 MCMC iterations, but only got through 1500, the last 500 values would be all 0.
You must choose a unique file name.
An error will be raised if file specified by tracefile
already exists.
If you don’t want a file to be output (e.g. for debugging), you can enter null
.
probfile¶
- type
string
- default
lnprob.npy
Name of the file that the MCMC ln probabilities are written to.
The array has shape (number of chains, iterations)
.
The array is preallocated and padded with zeros, so if you selected to take 2000 MCMC iterations, but only got through 1500, the last 500 values would be all 0.
You must choose a unique file name.
An error will be raised if file specified by probfile
already exists.
If you don’t want a file to be output (e.g. for debugging), you can enter null
.
generate_parameters¶
The options in generate_parameters
are used to control parameter selection and fitting to single phase data.
This should be used if you have input thermochemical data, such as heat capacities and mixing energies.
Generate parameters will use the Akaike information criterion to select model parameters and fit them, creating a database.
excess_model¶
- type
string
- default
required
- options
linear
Which type of model to use for excess mixing parameters. Currently only linear is supported.
The exponential model is planned, as well as support for custom models.
ref_state¶
- type
string
- default
required
- options
SGTE91 | SR2016
The reference state to use for the pure elements and lattice stabilities. Currently only SGTE91 and SR2016 (for certain elements) is supported.
There are plans to extend to support custom reference states.
ridge_alpha¶
- type
float
- default
1.0e-100
Controls the ridge regression hyperparameter, $ alpha $, as given in the following equation for the ridge regression problem
ridge_alpha
should be a positive floating point number which scales the relative contribution of parameter magnitudes to the residuals.
If an exponential form is used, the floating point value must have a decimal place before the e
,
that is 1e-4
is invalid while 1.e-4
is valid. More generally, the floating point must match the following
regular expression per the YAML 1.1 spec: [-+]?([0-9][0-9_]*)?\.[0-9.]*([eE][-+][0-9]+)?
.
aicc_penalty_factor¶
- type
dict
- default
null
This parameter is a mapping from a phase name and property to a penalty factor to apply to the AICc number of parameters. The default is null
, which means that all the penalty factors are one (1) for all phases, which means no bias for more or fewer parameters compared to the textbook definition of AICc. If phases or data are not included, the penalty factors remain one.
Increasing the penalty factor will increase the penalty for more parameters, so it will bias parameter selection to choose fewer parameters. This can be especially useful when there is not many data points and an exact fit is possible (e.g. 4 points and 4 parameters), but modeling intutition would suggest that fewer parameters are required. A negative penalty factor will bias ESPEI’s parameter selection to choose more parameters, which can be useful for generating more degrees of freedom for MCMC.
aicc_penalty_factor:
BCC_A2:
HM: 5.0
SM: 5.0
LIQUID:
HM: 2.0
SM: 2.0
input_db¶
- type
string
- default
null
A file path that can be read as a pycalphad Database, which can provide existing parameters to add as a starting point for parameter generation, for example magnetic parameters.
If you have single phase data, ESPEI will try to fit parameters to that data regardless of whether or not parameters were passed in for that phase. You must be careful to only add initial parameters that do not have data that ESPEI will try to fit. For example, do not include liquid enthalpy of mixing data for ESPEI to fit if you are providing an initial set of parameters.
mcmc¶
The options in mcmc
control how Markov Chain Monte Carlo is performed using the emcee package.
In order to run an MCMC fitting, you need to specify one and only one source of parameters somewhere in the input file.
The parameters can come from including a generate_parameters
step, or by specifying the mcmc.input_db
key with a file to load as pycalphad Database.
If you choose to use the parameters from a database, you can then further control settings based on whether it is the first MCMC run for a system (you are starting fresh) or whether you are continuing from a previous run (a ‘restart’).
iterations¶
- type
int
- default
required
Number of iterations to perform in emcee. Each iteration consists of accepting one step for each chain in the ensemble.
prior¶
- type
list or dict
- default
{‘name’: ‘zero’}
Either a single prior dictionary or a list of prior dictionaries corresponding to the number of parameters. See Specifying Priors for examples and details on writing priors.
save_interval¶
- type
int
- default
1
Controls the interval (in number of iterations) for saving the MCMC chain and probability files. By default, new files will be written out every iteration. For large files (many mcmc iterations and chains per parameter), these might become expensive to write out to disk.
cores¶
- type
int
- min
1
How many cores from available cores to use during parallelization with dask or emcee. If the chosen number of cores is larger than available, then this value is ignored and espei defaults to using the number available.
Cores does not take affect for MPIPool scheduler option. MPIPool requires the number of processors be set directly with MPI.
scheduler¶
- type
string
- default
dask
- options
dask | null | JSON file
Which scheduler to use for parallelization.
You can choose from either dask
, null
, or pass the path to a JSON scheduler file created by dask-distributed.
Choosing dask
allows for the choice of cores used through the cores key.
Choosing null
will result in no parallel scheduler being used. This is useful for debugging.
Passing the path to a JSON scheduler file will use the resources set up by the scheduler.
JSON file schedulers are most useful because schedulers can be started on MPI clusters using dask-mpi
command.
See Advanced Schedulers for more information.
input_db¶
- type
string
- default
null
A file path that can be read as a pycalphad Database. The parameters to fit will be taken from this database.
For a parameter to be fit, it must be a symbol where the name starts with VV
, e.g. VV0001
.
For a TDB
formatted database, this means that the free parameters must be functions of a single value that are used in your parameters.
For example, the following is a valid symbol to fit:
FUNCTION VV0000 298.15 10000; 6000 N !
restart_trace¶
- type
string
- default
null
If you have run a previous MCMC calculation, then you will have a trace file that describes the position and history of all of the chains from the run.
You can use these chains to start the emcee run and pick up from where you left off in the MCMC run by passing the trace file (e.g. chain.npy
) to this key.
If you are restarting from a previous calculation, you must also specify the same database file (with input_db
) as you used to run that calculation.
chains_per_parameter¶
- type
int
- default
2
This controls the number of chains to run in the MCMC calculation as an integer multiple of the number of parameters.
This parameter can only be used when initializing the first MCMC run. If you are restarting a calculation, the number of chains per parameter is fixed by the number you chose previously.
Ensemble samplers require at least 2*p
chains for p
fitting parameters to be able to make proposals.
If chains_per_parameter = 2
, then the number of chains if there are 10 parameters to fit is 20.
The value of chains_per_parameter
must be an EVEN integer.
chain_std_deviation¶
- type
float
- default
0.1
The standard deviation to use when initializing chains in a Gaussian distribution from a set of parameters as a fraction of the parameter.
A value of 0.1 means that for parameters with values (-1.5, 2000, 50000)
the chains will be initialized using those values as the mean and (0.15, 200, 5000)
as standard deviations for each parameter, respectively.
This parameter can only be used when initializing the first MCMC run. If you are restarting a calculation, the standard deviation for your chains are fixed by the value you chose previously.
You may technically set this to any positive value, you would like. Be warned that too small of a standard deviation may cause convergence to a local minimum in parameter space and slow convergence, while a standard deviation that is too large may cause convergence to meaningless thermodynamic descriptions.
approximate_equilibrium¶
- type
bool
- default
False
If True, an approximate version of pycalphad’s equilibrium()
function will
be used to calculate the driving force for phase boundary data. It uses
pycalphad’s starting_point
to construct a approximate equilibrium
hyperplanes of the lowest energy solution from a numerical sampling of each
active phases’s internal degrees of freedom. This can give speedups of up to
10x for calculating the ZPF likelihood, but may miss low energy solutions that
are not sampled well numerically, especially for phases with many sublattices,
which have low energy solutions far from the endmembers.
deterministic¶
- type
bool
- default
True
Toggles whether ESPEI runs are deterministic. If this is True, running
ESPEI with the same Database and initial settings (either the same
chains_per_parameter
and chain_std_deviation
or the same
restart_trace
) will result in exactly the same results.
Starting two runs with the same TDB or with parameter generation (which is deterministic) will result in the chains being at exactly the same position after 100 iterations. If these are both restarted after 100 iterations for another 50 iterations, then the final chain after 150 iterations will be the same.
It is important to note that this is only explictly True when starting at the same point. If Run 1 and Run 2 are started with the same initial parameters and Run 1 proceeds 50 iterations while Run 2 proceeds 100 iterations, restarting Run 1 for 100 iterations and Run 2 for 50 iterations (so they are both at 150 total iterations) will NOT give the same result.
data_weights¶
- type
dict
- default
{‘ZPF’: 1.0, ‘ACR’: 1.0, ‘HM’: 1.0, ‘SM’: 1.0, ‘CPM’: 1.0}
Each type of data can be weighted: zero phase fraction (ZPF
), activity
(ACR
) and the different types of thermochemical error. These weights are
used to modify the initial standard deviation of each data type by
symbols¶
- type
list[str]
- default
null
By default, any symbol in the database following the naming pattern VV#### where #### is any number is optimized by ESPEI. If this option is set, this can be used to manually fit a subset of the degrees of freedom in the system, or fit degrees of freedom that do not folow the naming convention of ‘VV####’:
symbols: ['VV0000', 'FF0000', ...]
Specifying Priors¶
In Bayesian statistics, data are used to update prior distributions for all parameters to calculate posterior distributions. A basic introduction to priors and Bayesian statistics can be found in “Kruschke, J. (2014). Doing Bayesian data analysis: A tutorial with R, JAGS, and Stan. Academic Press.”. A more advanced treatment is given in “Gelman, A., Stern, H. S., Carlin, J. B., Dunson, D. B., Vehtari, A., & Rubin, D. B. (2013). Bayesian data analysis. Chapman and Hall/CRC.”.
ESPEI provides a flexible interface to specify priors your want to use for a variety of parameters of different sign and magnitude through the espei.priors.PriorSpec
class.
This section will cover how to
Define flexible, built-in priors using the YAML input and ESPEI script
Use custom priors programatically
Built-in Priors¶
ESPEI has several built-in priors that correspond to functions in scipy.stats
: uniform
, normal
, and triangular
.
There is also a special (improper) zero
prior that always gives $$ ln p = 0 $$, which is the default.
Each scipy.stats
prior is typically specified using several keyword argument
parameters, e.g. loc
and scale
, which have special meaning for the
different distribution functions.
In order to be flexible to specifying these arguments when the CALPHAD
parameters they will be used for are not known beforehand, ESPEI uses a small
language to specify how the distribution hyperparameters can be set relative to
the CALPHAD parameters.
Basically, the PriorSpec
objects are created with the name of the distribution
and the hyperparameters that are modified with
one of the modifier types: absolute
, relative
, shift_absolute
, or shift_relative
.
For example, the loc
parameter might become loc_relative
and scale
might
become scale_shift_relative
.
Here are some examples of how the modifier parameters of value v
modify the hyperparameters when given a CALPHAD parameter of value p
:
_absolute=v
always take the exact value passed in,v
;loc_absolute=-20
gives a value ofloc=-20
._relative=v
gives ,v*p
;scale_absolute=0.1
withp=10000
gives a value ofscale=10000*0.1=1000
._shift_absolute=v
gives ,p + v
;scale_shift_absolute=-10
withp=10000
gives a value ofscale=10000+(-10)=9990
._shift_relative=v
gives ,p + v*abs(p)
;loc_shift_relative=-0.5
withp=-1000
gives a value ofloc=-1000+abs(-1000)*0.5=-1500
.
Note that the hyperparameter prefixes (loc
or scale
) are arbitrary and any hyperparameters used in the statistical distributions (e.g. c
for the triangular distribution) could be used.
YAML¶
Prior can be specified in the YAML input as a list of dictionaries for different parameters.
Since Python objects cannot be instantiated in the YAML files, the PriorSpec
can be described a dictionary of
{'name': <<NAME>>, 'loc_relative': <<VALUE>>, 'scale_relative': <<VALUE>>, ...}
.
Some common examples in YAML format are as follows:
# normal prior, centered on parameter, standard deviation of 0.25*parameter
prior:
name: normal
loc_relative: 1.0
scale_relative: 0.25
# uniform prior from 0 to 2*parameter (or negative(2*parameter) to 0)
prior:
name: uniform
loc_shift_relative: -1.0
scale_relative: 2.0
# triangular prior, centered on parameter, from -0.5*parameter to 0.5*parameter
prior:
name: triangular
loc_shift_relative: -0.5
scale_relative: 1.0
Graphically, these are shown below:

Example priors compared to initialized parameters.¶
As a side note: the priors in YAML files can be passed as Python dictionaries, e.g.:
# normal prior, centered on parameter, standard deviation of 0.25*parameter
prior: {'name': 'normal', 'loc_relative': 1.0, 'scale_relative': 0.5}
Additionally, different priors can be specified using a list of prior specs that match the total degrees of freedom (VV-parameters) in the system. For example, a two parameter system could use a normal and a triangular prior simultaneously:
# two priors:
# first a normal prior, centered on parameter, standard deviation of 0.25*parameter
# second a triangular prior, centered on parameter, from -0.5*parameter to 0.5*parameter
prior: [{'name': 'normal', 'loc_relative': 1.0, 'scale_relative': 0.5}, {'name': 'triangular', 'loc_shift_relative': -0.5, 'scale_relative': 1.0}]
Custom Priors¶
Generally speaking, a custom prior in ESPEI is any Python object that has a logpdf
method that takes a parameter and returns the natural log of the probability
density function for that parameter. Any distribution you can create
using the functions in scipy.stats
, such as norm
, is valid.
A list of these custom priors can be passed to ESPEI similar to using built-in priors, but only from the Python interface (not YAML).
The number of priors must match the number of parameters, but you can also mix these with the PriorSpec
objects as desired.
An example of fitting two parameters using a custom gamma distributions with minima at 10 and 100, respectively.
from scipy.stats import gamma
my_priors = [gamma(a=1, loc=10), gamma(a=1, loc=100)]
from espei.espei_script import get_run_settings, run_espei
input_dict = {
'system': {
'phase_models': 'phases.json',
'datasets': 'input-data',
},
'mcmc': {
'iterations': '1000',
'input_db': 'param_gen.tdb', # must have two parameters to fit
'prior': my_priors,
},
}
run_espei(get_run_settings(input_dict))
Making ESPEI datasets¶
JSON Format¶
ESPEI has a single input style in JSON format that is used for all data entry. For those unfamiliar with JSON, it is fairly similar to Python dictionaries with some rigid requirements
All string quotes must be double quotes. Use
"key"
instead of'key'
.Numbers should not have leading zeros.
00.123
should be0.123
and012.34
must be12.34
.Lists and nested key-value pairs cannot have trailing commas.
{"nums": [1,2,3,],}
is invalid and should be{"nums": [1,2,3]}
.
These errors can be challenging to track down, particularly if you are only reading the JSON error messages in Python. A visual editor is encouraged for debugging JSON files such as JSONLint. A quick reference to the format can be found at Learn JSON in Y minutes.
ESPEI has support for checking all of your input datasets for errors, which you should always use before you attempt to run ESPEI.
This error checking will report all of the errors at once and all errors should be fixed.
Errors in the datasets will prevent fitting.
To check the datasets at path my-input-data/
you can run espei --check-datasets my-input-data
.
Phase Descriptions¶
The JSON file for describing CALPHAD phases is conceptually similar to a setup file in Thermo-Calc’s PARROT module.
At the top of the file there is the refdata
key that describes which reference state you would like to choose.
Currently the reference states are strings referring to dictionaries in pycalphad.refdata
only "SGTE91"
is implemented.
Each phase is described with the phase name as they key in the dictionary of phases.
The details of that phase is a dictionary of values for that key.
There are 4 possible entries to describe a phase: sublattice_model
, sublattice_site_ratios
, equivalent_sublattices
, and aliases
.
sublattice_model
is a list of lists, where each internal list contains all of the components in that sublattice.
The BCC_B2
sublattice model is [["AL", "NI", "VA"], ["AL", "NI", "VA"], ["VA"]]
, thus there are three sublattices where the first two have Al, Ni, and vacancies.
sublattice_site_ratios
should be of the same length as the sublattice model (e.g. 3 for BCC_B2
).
The sublattice site ratios can be fractional or integers and do not have to sum to unity.
The optional equivalent_sublattices
key is a list of lists that describe which sublattices are symmetrically equivalent.
Each sub-list in equivalent_sublattices
describes the indices (zero-indexed) of sublattices that are equivalent.
For BCC_B2
the equivalent sublattices are [[0, 1]]
, meaning that the sublattice at index 0 and index 1 are equivalent.
There can be multiple different sets (multiple sub-lists) of equivalent sublattices and there can be many equivalent sublattices within a sublattice (see FCC_L12
).
If no equivalent_sublattice
key exists, it is assumed that there are none.a
Finally, the aliases
key is used to refer to other phases that this sublattice model can describe when symmetry is accounted for.
Aliases are used here to describe the BCC_A2
and FCC_A1
, which are the disordered phases of BCC_B2
and FCC_L12
, respectively.
Notice that the aliased phases are not otherwise described in the input file.
Multiple phases can exist with aliases to the same phase, e.g. FCC_L12
and FCC_L10
can both have FCC_A1
as an alias.
{
"refdata": "SGTE91",
"components": ["AL", "NI", "VA"],
"phases": {
"LIQUID" : {
"sublattice_model": [["AL", "NI"]],
"sublattice_site_ratios": [1]
},
"BCC_B2": {
"aliases": ["BCC_A2"],
"sublattice_model": [["AL", "NI", "VA"], ["AL", "NI", "VA"], ["VA"]],
"sublattice_site_ratios": [0.5, 0.5, 1],
"equivalent_sublattices": [[0, 1]]
},
"FCC_L12": {
"aliases": ["FCC_A1"],
"sublattice_model": [["AL", "NI"], ["AL", "NI"], ["AL", "NI"], ["AL", "NI"], ["VA"]],
"sublattice_site_ratios": [0.25, 0.25, 0.25, 0.25, 1],
"equivalent_sublattices": [[0, 1, 2, 3]]
},
"AL3NI1": {
"sublattice_site_ratios": [0.75, 0.25],
"sublattice_model": [["AL"], ["NI"]]
},
"AL3NI2": {
"sublattice_site_ratios": [3, 2, 1],
"sublattice_model": [["AL"], ["AL", "NI"], ["NI", "VA"]]
},
"AL3NI5": {
"sublattice_site_ratios": [0.375, 0.625],
"sublattice_model": [["AL"], ["NI"]]
}
}
}
Units¶
Energies are in
J/mol-atom
(and the derivatives follow)All compositions are mole fractions
Temperatures are in Kelvin
Pressures in Pascal
Non-equilibrium Thermochemical Data¶
Non-equilibrium thermochemical data is used where the internal degrees of freedom for a phase are known. This type of data is the only data that can be used for parameter generation, but it can also be used in Bayesian parameter estimation.
Two examples follow. The first dataset has some data for the formation heat capacity for BCC_B2.
The
components
andphases
keys simply describe those found in this entry.Use the
reference
key for bookkeeping the source of the data.The
comment
key and value can be used anywhere in the data to keep notes for your reference. It takes no effect.The
solver
the internal degrees of freedom and and site ratios are described for the phase.sublattice_configurations
is a list of different configurations, that should correspond to the sublattices for the phase descriptions. Non-mixing sublattices are represented as a string, while mixing sublattices are represented as a lists. Thus an endmember forBCC_B2
(as in this example) is["AL", "NI", VA"]
and if there were mixing (as in the next example) it might be["AL", ["AL", "NI"], "VA"]
. Mixing also means that thesublattice_occupancies
key must be specified, but that is not the case in this example. It is important to note that any mixing configurations must have any ideal mixing contributions removed. Regardless of whether there is mixing or not, the length of this list should always equal the number of sublattices in the phase, though the sub-lists can have mixing up to the number of components in that sublattice. Note that thesublattice_configurations
is a list of these lists. That is, there can be multiple sublattice configurations in a single dataset. See the second example in this section for such an example.The
conditions
describe temperatures (T
) and pressures (P
) as either scalars or one-dimensional lists.The type of quantity is expressed using the
output
key. This can in principle be any thermodynamic quantity, but currently onlyCPM*
,SM*
, andHM*
(where*
is either nothing,_MIX
or_FORM
) are supported. Support for changing reference states is planned but not yet implemented, so all thermodynamic quantities must be formation quantities (e.g.HM_FORM
orHM_MIX
, etc.). This issue is tracked by ESPEI #85 on GitHubvalues
is a 3-dimensional array where each value is theoutput
for a specific condition of pressure, temperature, and sublattice configurations from outside to inside. Alternatively, the size of the array must be(len(P), len(T), len(subl_config))
. In the example below, the shape of thevalues
array is (1, 12, 1) as there is one pressure scalar, one sublattice configuration, and 12 temperatures.There is also a key,
excluded_model_contributions
, which will make those contributions of pycalphad’sModel
not be fit to when doing parameter selection or MCMC. This is useful for cases where the type of data used does not include some specificModel
contributions that parameters may already exist for. For example, DFT formation energies do not include ideal mixing or (CALPHAD-type) magnetic model contributions, but formation energies from experiments would include these contributions so experimental formation energies should not be excluded.
{
"reference": "Yi Wang et al 2009",
"components": ["AL", "NI", "VA"],
"phases": ["BCC_B2"],
"solver": {
"mode": "manual",
"sublattice_site_ratios": [0.5, 0.5, 1],
"sublattice_configurations": [["AL", "NI", "VA"]],
"comment": "NiAl sublattice configuration (2SL)"
},
"conditions": {
"P": 101325,
"T": [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110]
},
"excluded_model_contributions": ["idmix", "mag"],
"output": "CPM_FORM",
"values": [[[ 0 ],
[-0.0173 ],
[-0.01205],
[ 0.12915],
[ 0.24355],
[ 0.13305],
[-0.1617 ],
[-0.51625],
[-0.841 ],
[-1.0975 ],
[-1.28045],
[-1.3997 ]]]
}
In the second example below, there is formation enthalpy data for multiple sublattice configurations.
All of the keys and values are conceptually similar.
Here, instead of describing how the output
quantity changes with temperature or pressure, we are instead only comparing HM_FORM
values for different sublattice configurations.
The key differences from the previous example are that there are 9 different sublattice configurations described by sublattice_configurations
and sublattice_occupancies
.
Note that the sublattice_configurations
and sublattice_occupancies
should have exactly the same shape.
Sublattices without mixing should have single strings and occupancies of one.
Sublattices that do have mixing should have a site ratio for each active component in that sublattice.
If the sublattice of a phase is ["AL", "NI", "VA"]
, it should only have two occupancies if only ["AL", "NI"]
are active in the sublattice configuration.
The last difference to note is the shape of the values
array.
Here there is one pressure, one temperature, and 9 sublattice configurations to give a shape of (1, 1, 9).
{
"reference": "C. Jiang 2009 (constrained SQS)",
"components": ["AL", "NI", "VA"],
"phases": ["BCC_B2"],
"solver": {
"sublattice_occupancies": [
[1, [0.5, 0.5], 1],
[1, [0.75, 0.25], 1],
[1, [0.75, 0.25], 1],
[1, [0.5, 0.5], 1],
[1, [0.5, 0.5], 1],
[1, [0.25, 0.75], 1],
[1, [0.75, 0.25], 1],
[1, [0.5, 0.5], 1],
[1, [0.5, 0.5], 1]
],
"sublattice_site_ratios": [0.5, 0.5, 1],
"sublattice_configurations": [
["AL", ["NI", "VA"], "VA"],
["AL", ["NI", "VA"], "VA"],
["NI", ["AL", "NI"], "VA"],
["NI", ["AL", "NI"], "VA"],
["AL", ["AL", "NI"], "VA"],
["AL", ["AL", "NI"], "VA"],
["NI", ["AL", "VA"], "VA"],
["NI", ["AL", "VA"], "VA"],
["VA", ["AL", "NI"], "VA"]
],
"comment": "BCC_B2 sublattice configuration (2SL)"
},
"conditions": {
"P": 101325,
"T": 300
},
"output": "HM_FORM",
"values": [[[-40316.61077, -56361.58554,
-49636.39281, -32471.25149, -10890.09929,
-35190.49282, -38147.99217, -2463.55684,
-15183.13371]]]
}
Equilibrium Thermochemical Data¶
Equilibrium thermochemical data is used when the internal degrees of freedom are not known. This is typically true for experimental thermochemical data. Some cases where this type of data is useful, compared to non-equilibrium thermochemical data are:
Activity data
Enthalpy of formation data in region with two or more phases in equilibrium
Enthalpy of formation for a phase with multiple sublattice, e.g. the σ phase
This type of data can not be used in parameter selection, because a core assumption of parameter selection is that the site fractions are known.
Note
Only activity data is supported at the moment. Support for other data types is tracked by ESPEI #104 on GitHub.
Activity data is similar to non-equilibrium thermochemical data, except we must enter a reference state and the solver
key is no longer required, since we do not know the internal degrees of freedom. A key detail is that the phases
key must specify all phases that are possible to form.
An example for Mg activties in Cu-Mg follows, with data digitized from S.P. Garg, Y.J. Bhatt, C. V. Sundaram, Thermodynamic study of liquid Cu-Mg alloys by vapor pressure measurements, Metall. Trans. 4 (1973) 283–289. doi:10.1007/BF02649628.
{
"components": ["CU", "MG", "VA"],
"phases": ["LIQUID", "FCC_A1", "HCP_A3"],
"reference_state": {
"phases": ["LIQUID"],
"conditions": {
"P": 101325,
"T": 1200,
"X_MG": 1.0
}
},
"conditions": {
"P": 101325,
"T": 1200,
"X_CU": [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]
},
"output": "ACR_MG",
"values": [[[0.0057,0.0264,0.0825,0.1812,0.2645,0.4374,0.5852,0.7296,0.882,1.0]]],
"reference": "garg1973thermodynamic",
"comment": "Digitized Figure 3 and converted from activity coefficients."
}
Phase Boundary Data¶
The phase boundary data JSON input files are similar to other types of input, but instead of scalar values
for the property of interest, the values
key represents the phase regions active in a single phase equilbrium.
Notice that the type of data we are entering in the output
key is ZPF
(zero-phase fraction) rather than CP_FORM
or H_MIX
.
Each entry in the ZPF list is a list of all phases in equilibrium, here [["AL3NI2", ["NI"], [0.4083]], ["BCC_B2", ["NI"], [0.4340]]]
where each phase entry has the name of the phase, the composition element, and the composition of the tie line point.
If there is no corresponding tie line point, such as on a liquidus line, then one of the compositions will be null
: [["LIQUID", ["NI"], [0.6992]], ["BCC_B2", ["NI"], [null]]]
.
Three- or n-phase equilibria are described as expected: [["LIQUID", ["NI"], [0.752]], ["BCC_B2", ["NI"], [0.71]], ["FCC_L12", ["NI"], [0.76]]]
.
Note that for higher-order systems the component names and compositions are lists and should be of length c-1
, where c
is the number of components.
{
"components": ["AL", "NI"],
"phases": ["AL3NI2", "BCC_B2"],
"conditions": {
"P": 101325,
"T": [1348, 1176, 977]
},
"output": "ZPF",
"values": [
[["AL3NI2", ["NI"], [0.4083]], ["BCC_B2", ["NI"], [0.4340]]],
[["AL3NI2", ["NI"], [0.4114]], ["BCC_B2", ["NI"], [0.4456]]],
[["AL3NI2", ["NI"], [0.4114]], ["BCC_B2", ["NI"], [0.4532]]]
],
"reference": "37ALE"
}
Tags¶
Tags are a flexible method to adjust many ESPEI datasets simultaneously and drive them via the ESPEI’s input YAML file.
Each dataset can have a "tags"
key, with a corresponding value of a list of tags, e.g. ["dft"]
.
Any tag modifications present in the input YAML file are applied to the datasets before ESPEI is run.
They can be used in many creative ways, but some suggested ways include to add weights or to exclude model contributions, e.g. for DFT data that should not have contributions for a CALPHAD magnetic model or ideal mixing energy. An example of using the tags in an input file looks like:
{
"components": ["CR", "FE", "VA"],"phases": ["BCC_A2"],
"solver": {"mode": "manual", "sublattice_site_ratios": [1, 3],
"sublattice_configurations": [[["CR", "FE"], "VA"]],
"sublattice_occupancies": [[[0.5, 0.5], 1.0]]},
"conditions": {"P": 101325, "T": 300},
"output": "HM_MIX",
"values": [[[10000]]],
"tags": ["dft"]
}
An example input YAML looks like
system:
phase_models: CR-FE.json
datasets: FE-NI-datasets-sep
tags:
dft:
excluded_model_contributions: ["idmix", "mag"]
generate_parameters:
excess_model: linear
ref_state: SGTE91
ridge_alpha: 1.0e-20
output:
verbosity: 2
output_db: out.tdb
This will add the key "excluded_model_contributions"
to all datasets that have the "dft"
tag:
{
"components": ["CR", "FE", "VA"],"phases": ["BCC_A2"],
"solver": {"mode": "manual", "sublattice_site_ratios": [1, 3],
"sublattice_configurations": [[["CR", "FE"], "VA"]],
"sublattice_occupancies": [[[0.5, 0.5], 1.0]]},
"conditions": {"P": 101325, "T": 300},
"output": "HM_MIX",
"values": [[[10000]]],
"excluded_model_contributions": ["idmix", "mag"]
}
Common Mistakes and Notes¶
A single element sublattice is different in a phase model (
[["A", "B"], ["A"]]]
) than a sublattice configuration ([["A", "B"], "A"]
).Make sure you use the right units (
J/mole-atom
, mole fractions, Kelvin, Pascal)Mixing configurations should not have ideal mixing contributions.
All types of data can have a
weight
key at the top level that will weight the standard deviation parameter in MCMC runs for that dataset. If a single dataset should have different weights applied, multiple datasets should be created.
Recipes¶
Here you can find some useful snippets of code to make using ESPEI easier.
Get optimal parameter TDB files from a trace¶
Creating TDBs of optimal parameters from a tracefile and probfile:
"""
This script updates an input TDB file with the optimal parameters from an ESPEI run.
Change the capitalized variables to your desired input and output filenames.
"""
INPUT_TDB_FILENAME = 'CU-MG_param_gen.tdb'
OUTPUT_TDB_FILENAME = 'CU-MG_opt_params.tdb'
TRACE_FILENAME = 'trace.npy'
LNPROB_FILENAME = 'lnprob.npy'
import numpy as np
from pycalphad import Database
from espei.analysis import truncate_arrays
from espei.utils import database_symbols_to_fit, optimal_parameters
trace = np.load(TRACE_FILENAME)
lnprob = np.load(LNPROB_FILENAME)
trace, lnprob = truncate_arrays(trace, lnprob)
dbf = Database(INPUT_TDB_FILENAME)
opt_params = dict(zip(database_symbols_to_fit(dbf), optimal_parameters(trace, lnprob)))
dbf.symbols.update(opt_params)
dbf.to_file(OUTPUT_TDB_FILENAME)
Plot phase equilibria data¶
When compiling ESPEI datasets of phase equilibria data, it can be useful to plot the data to check that it matches visually with what you are expecting. This script plots a binary phase diagram.
TIP: Using this in Jupyter Notebooks make it really fast to update and watch your progress.
"""
This script will create a plot in a couple seconds from a datasets directory
that you can use to check your phase equilibria data.
Change the capitalized variables to the system information and the
directory of datasets you want to plot.
"""
COMPONENTS = ['CU', 'MG', 'VA']
INDEPENDENT_COMPONENT = "MG" # component to plot on the x-axis
PHASES = ['BCC_A2', 'CUMG2', 'FCC_A1', 'LAVES_C15', 'LIQUID']
DATASETS_DIRECTORY = "~/my-datasets/CU-MG"
X_MIN, X_MAX = 0.0, 1.0
Y_MIN, Y_MAX = 400, 1400
# script starts here, you shouldn't have to edit below this line
import os
from espei.plot import dataplot
from espei.datasets import recursive_glob, load_datasets
from pycalphad import variables as v
import matplotlib.pyplot as plt
plt.figure(figsize=(10,8))
ds = load_datasets(recursive_glob(os.path.expanduser(DATASETS_DIRECTORY), '*.json'))
conds = {v.P: 101325, v.T: (1,1,1), v.X(INDEPENDENT_COMPONENT): (1, 1, 1)}
dataplot(COMPONENTS, PHASES, conds, ds)
plt.xlim(X_MIN, X_MAX)
plt.ylim(Y_MIN, Y_MAX)
plt.show()
The script gives the following output:
Plot phase diagram with data¶
%matplotlib inline
from pycalphad import Database, binplot, variables as v
from espei.datasets import load_datasets, recursive_glob
from espei.plot import dataplot
import matplotlib.pyplot as plt
# load the experimental and DFT datasets
dataset_dir = "input-data"
dataset_dir = "/Users/brandon/Projects/2020-workshop-material/ESPEI/input-data/run"
datasets = load_datasets(recursive_glob(dataset_dir, "*.json"))
# set up the pycalphad phase diagram calculation
dbf = Database("/Users/brandon/Projects/2020-workshop-material/ESPEI/mcmc-tmp.tdb")
comps = ["CR", "NI", "VA"]
phases = ["LIQUID", "FCC", "BCC"]
conds = {v.P: 101325, v.T: (700, 2200, 10), v.X("CR"): (0, 1, 0.01)}
# plot the phase diagram and data
fig = plt.figure(dpi=150)
ax = fig.gca()
binplot(dbf, comps, phases, conds, plot_kwargs={"ax": ax})
dataplot(comps, phases, conds, datasets, ax=ax)
ax.set_title("Cr-Ni\nParameter Generation")
ax.set_ylim(conds[v.T][0], conds[v.T][1])
ax.set_xlabel("X(CR)")
ax.set_ylabel("Temperature (K)")
fig.show()
Plot thermochemical properties parameters with data¶
Parameter selection in ESPEI fits Calphad parameters to thermochemical data.
MCMC can adjust these parameters.
In both cases, it may be useful to compare the energies of specific
interactions to the model predictions. The
espei.plot.plot_interaction()
code will plot the predicted
interaction from the database against the available data, if any.
"""
This script plots a single interaction in a database compared to data.
"""
# Settings
INPUT_TDB_FILENAME = 'CU-MG_param_gen.tdb'
DATASET_DIRECTORY = 'input-data'
PHASE_NAME = 'LIQUID'
# CONFIGURATION must be a tuple of the configuration to be plotted.
# This can only plot one endmember or interaction at a time.
# Note that the outside tuples are the whole configuration
# and the insides are for each individual sublattice.
# Single sublattices *MUST* have the comma after the
# object in order to be a tuple, not just parantheses.
# some examples:
# ('CU', 'MG') # endmember
# (('CU', 'MG'),) # (('CU', 'MG')) is invalid because it will become ('CU', 'MG')
# ('MG', ('CU', 'MG'))
CONFIGURATION = (('CU', 'MG'),)
# Plot the parameter
import matplotlib.pyplot as plt
from pycalphad import Database
from espei.datasets import load_datasets, recursive_glob
from espei.plot import plot_interaction
dbf = Database(INPUT_TDB_FILENAME)
comps = sorted(dbf.elements)
ds = load_datasets(recursive_glob(DATASET_DIRECTORY, '*.json'))
plot_interaction(dbf, comps, PHASE_NAME, CONFIGURATION, 'HM_MIX', datasets=ds)
plt.show()
Running for the single sublattice LIQUID phase in Cu-Mg gives the following output after parameter selection:
Visualize probability convergence¶
Convergence can be qualitatively estimated by looking at how the log-probability changes for all of the chains as a function of iterations.
# remove next line if not using iPython or Juypter Notebooks
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from espei.analysis import truncate_arrays
trace = np.load('trace.npy')
lnprob = np.load('lnprob.npy')
trace, lnprob = truncate_arrays(trace, lnprob)
ax = plt.gca()
ax.set_yscale('log')
ax.set_xlabel('Iterations')
ax.set_ylabel('- lnprob')
ax.plot(-lnprob.T)
plt.show()

Visualize the trace of each parameter¶
Looking at how each parameter chain evolves across the chains can show if any particular chains are diverging from the rest, if there are multiple modes being explored, or how wide the distribution of parameters are relative to each other.
# remove next line if not using iPython or Juypter Notebooks
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from espei.analysis import truncate_arrays
trace = np.load('trace.npy')
lnprob = np.load('lnprob.npy')
trace, lnprob = truncate_arrays(trace, lnprob)
num_chains = trace.shape[0]
num_parameters = trace.shape[2]
for parameter in range(num_parameters):
ax = plt.figure().gca()
ax.set_xlabel('Iterations')
ax.set_ylabel('Parameter value')
ax.plot(trace[..., parameter].T)
plt.show()
The example below is for one parameter. Running the snippet above will plot all of the parameters on separate plots.

Plot a corner plot¶
Note: You must install the corner
package before using it
(conda install corner
or pip install corner
).
In a corner plot, the distributions for each parameter are plotted along the diagonal and covariances between them under the diagonal. A more circular covariance means that parameters are not correlated to each other, while elongated shapes indicate that the two parameters are correlated. Strongly correlated parameters are expected for some parameters in CALPHAD models within phases or for phases in equilibrium, because increasing one parameter while decreasing another would give a similar likelihood.
# remove next line if not using iPython or Juypter Notebooks
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import corner
from espei.analysis import truncate_arrays
trace = np.load('trace.npy')
lnprob = np.load('lnprob.npy')
trace, lnprob = truncate_arrays(trace, lnprob)
# flatten the along the first dimension containing all the chains in parallel
fig = corner.corner(trace.reshape(-1, trace.shape[-1]))
plt.show()

Plot ZPF driving forces¶
This visualization can be used as a diagnostic for understanding which ZPF data are contributing the most driving force towards the likelihood. Note that these driving forces are unweighted, since the weight is applied when computing the log-likelihood of each driving force.
import numpy as np
import matplotlib.pyplot as plt
from pycalphad import Database, binplot, variables as v
from pycalphad.core.utils import extract_parameters
from espei.datasets import load_datasets, recursive_glob
from espei.error_functions.zpf_error import get_zpf_data, calculate_zpf_driving_forces
# User input variables
TDB_PATH = 'mcmc.tdb'
DATASETS_DIR = '../input-data'
COMPS = ['CR', 'NI', 'VA']
INDEP_COMP = v.X('NI') # binary assumed
CONDS = {v.N: 1, v.P: 101325, v.T: (500, 2200, 20), INDEP_COMP: (0, 1, 0.01)}
CMAP = 'hot'
outfile = 'driving-forces.png'
parameters = {} # e.g. {'VV0001': 10000.0}
approximate_equilibrium = False
# Script below:*
dbf = Database(TDB_PATH)
phases = list(dbf.phases.keys())
# Get the datasets, construct ZPF data and compute driving forces
# Driving forces and weights are ragged 2D arrays of shape (len(zpf_data), len(vertices in each zpf_data))
ds = load_datasets(recursive_glob(DATASETS_DIR, '*.json'))
zpf_data = get_zpf_data(dbf, COMPS, phases, ds, parameters=parameters)
param_vec = extract_parameters(parameters)[1]
driving_forces, weights = calculate_zpf_driving_forces(zpf_data, param_vec, approximate_equilibrium=approximate_equilibrium)
# Construct the plotting compositions, temperatures and driving forces
# Each should have len() == (number of vertices)
# Driving forces already have the vertices unrolled so we can concatenate directly
Xs = []
Ts = []
dfs = []
for data, data_driving_forces in zip(zpf_data, driving_forces):
for phase_region in data['phase_regions']:
for vertex_comp_cond, df in zip(phase_region.comp_conds, data_driving_forces):
if any(val is None for val in vertex_comp_cond.values()):
continue
dfs.append(df)
Ts.append(phase_region.potential_conds[v.T])
# Binary assumptions here
assert len(vertex_comp_cond) == 1
if INDEP_COMP in vertex_comp_cond:
Xs.append(vertex_comp_cond[INDEP_COMP])
else:
# Switch the dependent and independent component
Xs.append(1.0 - tuple(vertex_comp_cond.values())[0])
# Plot the phase diagram with driving forces
fig = plt.figure(dpi=100)
ax = fig.gca()
binplot(dbf, COMPS, phases, CONDS, plot_kwargs={'ax': ax}, eq_kwargs={'parameters': parameters})
sm = plt.cm.ScalarMappable(cmap=CMAP)
sm.set_array(dfs)
ax.scatter(Xs, Ts, c=dfs, cmap=CMAP, edgecolors='k')
fig.colorbar(sm, ax=ax, pad=0.25)
if outfile is not None:
fig.savefig(outfile)
else:
fig.show()

Use a custom unary reference state¶
Unary reference state data provides three pieces of information about pure elements to ESPEI:
Stable element reference (SER) data, giving the stable phase, atomic mass, \(H298\) and \(S298\) of each element
Gibbs energy of each element in its SER phase
Optional lattice stability functions for selected phases, often relative to the stable element reference energy
By default, ESPEI uses the SGTE91 reference state using the functions defined by Dinsdale 1.
ESPEI can be provided custom unary reference states for parameter generation. Some common use cases for custom reference states are:
Testing new unary descriptions in an assessment
Using ESPEI to model systems with ficticious components, like a pseudo-binary
Using a custom reference state is very easy once it is created or installed. Instead of generating parameters with:
system:
phase_models: my-phases.json
datasets: my-input-datasets
generate_parameters:
excess_model: linear
ref_state: SGTE91
A custom reference state called MyCustomReferenceState
could be used by:
system:
phase_models: my-phases.json
datasets: my-input-datasets
generate_parameters:
excess_model: linear
ref_state: MyCustomReferenceState
Using the template package below, you can create a Python package of custom reference data to install for yourself, and optionally to distribute to others.
Quickstart: Skeleton package¶
If you are not comfortable developing a Python package using the details below, that’s okay! We have provided a skeleton package that can be downloaded and installed to give you a working example.
Running the example¶
Following these steps will give you a working unary reference state for Al and
Ag named CustomRefstate2020
. Assuming you have git
and a working Python
environment, starting from the command line:
Clone the skeleton repository:
git clone https://github.com/PhasesResearchLab/ESPEI-unary-refstate-skeleton
Enter the downloaded repository:
cd ESPEI-unary-refstate-skeleton
Install the package using
pip
:pip install -e .
This will install the packaged, named espei_refstate_customrefstate2020
,
and provide a reference state named CustomRefstate2020
.
We can use that by passing using ref_state: CustomRefstate2020
in the
generate_parameters
heading in ESPEI’s YAML input.
If you have ESPEI installed already, you can test that this works by:
Enter the
espei-example
directory:cd espei-example
Run the YAML input file using ESPEI (note: it’s safe to ignore a warning that no datsets were found - we aren’t fitting any parameters to data here):
espei --in gen_Ag-Al.yaml
If it was successful, you should have ran the YAML file:
system:
phase_models: Ag-Al.json
datasets: input-datasets
generate_parameters:
excess_model: linear
ref_state: CustomRefstate2020
and generated a database, out.tdb
, containing our custom GHSERAG
function (among others):
FUNCTION GHSERAG 298.15 118.202013*T - 7209.512; 1234.93 Y 190.266404*T -
15095.252; 3000.0 N !
and lattice stabilities for phases defined in the reference state and the system Ag-Al.json
, such as GHCPAG
.
Finally, since this reference state is probably not useful for developing any databases, uninstall the package by running pip uninstall espei_refstate_customrefstate2020
and removing the directory espei_refstate_customrefstate2020.egg-info
from the root directory if one exists.
Using the skeleton to create your own database¶
If you want to use the skeleton to create your own reference state to provide
ESPEI, you can follow the steps below. To keep the steps concrete, we’ll create
a reference state for Cu called Bocklund2019
following the unary
description published for Cu in Bocklund et al. 2. within the
segmented regression approach by Roslyakova
et al. 3.
Assuming that you are fresh (without the skeleton downloaded yet):
Clone the skeleton repository:
git clone https://github.com/PhasesResearchLab/ESPEI-unary-refstate-skeleton
Enter the downloaded repository:
cd ESPEI-unary-refstate-skeleton
Update the
NAME = 'CustomRefstate2020'
parameter insetup.py
toNAME = 'Bocklund2019'
In the
refstate.py
module, create theBockund2019Stable
,Bockund2019
, and (optionally)Bocklund2019SER
dictionaries (see Creating the reference state dictionaries for more details)Delete the
CustomRefstate2020Stable
andCustomRefstate2020
variablesAdd the stable phase Gibbs energy for Cu to the
Bockund2019Stable
variable. Note thatOrderedDict
is defined in thecollections
module in the Python standard library.Bocklund2019Stable = OrderedDict([ ('CU', Piecewise((-0.0010514335*T**2 + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 11038.0904080745, And(T >= 0.01, T < 103.57591)), (-2.15621953171362e-6*T**3 + 0.000288560900942072*T**2 - 0.13879113947248*T*log(T) + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) + 0.574637617323048*T - 11042.8822142647, And(T >= 103.57591, T < 210.33309)), (-0.002432585*T**2 + 0.4335558862135*T*log(T) + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 2.20049706600083*T - 11002.7543747764, And(T >= 210.33309, T < 1357.77)), (-31.38*T*log(T) + 183.555483717662*T - 12730.2995781851 + 7.42232714807953e+28/T**9, And(T >= 1357.77, T < 3200.0)), (0, True))), ])
Add the lattice stability for all elements, including the stable phase, to the
Bocklund2019
variableBocklund2019 = OrderedDict([ (('CU', 'HCP_A3'), Piecewise((-3.38438862938597e-7*T**3 - 0.00121182291077191*T**2 + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 0.321147237334052*T - 10441.4393392344, And(T >= 0.01, T < 298.15)), (1.29223e-7*T**3 - 0.00265684*T**2 - 24.112392*T*log(T) + 130.685235*T - 7170.458 + 52478/T, And(T >= 298.15, T < 1357.77)), (-31.38*T*log(T) + 184.003828*T - 12942.0252504739 + 3.64167e+29/T**9, And(T >= 1357.77, T < 3200.0)), (0, True))), (('CU', 'FCC_A1'), Piecewise((Symbol('GHSERCU'), And(T < 10000.0, T >= 1.0)), (0, True))), (('CU', 'LIQUID'), Piecewise((-3.40056501515466e-7*T**3 - 0.00121066539331185*T**2 + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 10.033338832193*T + 2379.36422209194, And(T >= 0.01, T < 298.15)), (-5.8489e-21*T**7 + 1.29223e-7*T**3 - 0.00265684*T**2 - 24.112392*T*log(T) + 120.973331*T + 5650.32106235287 + 52478/T, And(T >= 298.15, T < 1357.77)), (-31.38*T*log(T) + 173.881484*T + 409.498458129716, And(T >= 1357.77, T < 3200.0)), (0, True))), ])
(Optional) Add the SER data. If you don’t add this data, the SGTE91 data will be used as a fallback
Bocklund2019SER = OrderedDict([ ('CU', {'phase': 'FCC_A1', 'mass': 63.546, 'H298': 5004.1, 'S298': 33.15}), ])
Install the package as editable using
pip
:pip install -e .
You can now use your reference state in ESPEI, and even change the definitions on the fly.
Creating the reference state dictionaries¶
To define the reference Gibbs energy, lattice stabilities, and SER data you must define three ordered dictionaries:
<NAME>SER
, mapping element names to dictionaries of SER data<NAME>Stable
, mapping element names to Gibbs energy expressions for the stable phase<NAME>
, mapping pairs of(element name, phase name)
to lattice stability expressions
The Gibbs energy expressions must be defined as valid symbolic expressions
using SymPy Symbol
objects and pycalphad StateVariable
objects (e.g.
v.T
, v.P
), which can be (but are not required to be) piecewise in
temperature. Any SymPy functions can be used (exp
, log
, Piecewise
,
…). Any valid Python syntax or functions can be used, including those not
available in commercial software (for example, direct exponentiation with
non-integer powers). Any expression supported by pycalphad Model
objects
can be used, but note that the TDB files that ESPEI writes using these
expressions may not be compatible with commercial software.
It’s important to note that the users probably want to add a (0, True)
expression/condition pair to the end of any Piecewise expressions used. Since
pycalphad does not automatically extrapolate the piecewise expressions outside
of thier valid ranges, this condition will allow the solver to be numerically
stable, returning zero instead of NaN.
For <NAME>
lattice stability data, all GHSER symbols will have a two
letter element name, regardless of how many letters the element name has. This
is to prevent abbreviation name clashes in commercial software. For example,
GHSERC could represent the Gibbs energy for carbon (C), but also be a
valid abbreviation for calcium (CA). Using GHSERCC automatically fixes this
issue, but be aware to use Symbol(“GHSERCC”) in the case of single letter
phase names.
Detailed Information¶
Setting up setup.py¶
If you want to go dig deeper into how the skeleton works, ESPEI uses the
entry_points
feature of setuptools
to treat additional reference states as plugins.
A package providing a reference state to ESPEI should provide a module that has
three dictionaries: <NAME>Stable
, <NAME>
, and (optional) <NAME>SER
,
according to the Creating the reference state dictionaries section above. The module can
have any name, <MODULE>
, (the skeleton uses refstate.py
). ESPEI looks
for the entry_point
called espei.reference_states
following the example
from the setuptools documentation.
Concretely, the entry_point
should be described by:
# setup.py
from setuptools import setup
setup(# ...
entry_points={'espei.reference_states': '<NAME> = <MODULE>'}
)
where <NAME>
and <MODULE>
are replaced by the corresponding name of the
reference state and the name of the module with the reference states defined.
Interested readers may also find the entry_points specification here.
Debugging¶
If you want to test whether your modules are found, you can run the following Python code to show what reference states were found
import espei
print(espei.refdata.INSERTED_USER_REFERENCE_STATES)
If you do this after installing the unchanged
skeleton package package from this
repository, you should find CustomRefstate2020 is printed and the
dictionaries espei.refdata.CustomRefstate2020Stable
and
espei.refdata.CustomRefstate2020
should be defined in the espei.refdata
module. For more details on the implementation, see the
espei.refdata.find_and_insert_user_refstate
function.
References¶
- 1
A.T. Dinsdale, Calphad 15(4) (1991) 317-425, doi:10.1016/0364-5916(91)90030-N
- 2
Bocklund et al., MRS Communications 9(2) (2019) 1–10. doi:10.1557/mrc.2019.59
- 3
I. Roslyakova et al., Calphad 55 (2016) 165–180. doi:10.1016/j.calphad.2016.09.001
Advanced Schedulers¶
ESPEI uses dask-distributed for parallelization and provides an easy way to deploy clusters locally via TCP with the mcmc.scheduler: dask
setting.
Sometimes ESPEI’s dask scheduling options are not sufficiently flexible for different environments.
As an alternative to setting the cores with the mcmc.scheduler: dask
setting,
you can provide ESPEI with a scheduler file from dask that has information about
how to connect to a dask parallel scheduler.
This is generally a two step process of
Starting a scheduler with workers and writing a scheduler file
Running ESPEI and connecting to the existing scheduler
In order to let the system manage the memory and prevent dask from pausing or killing workers, the memory limit should be set to zero.
Starting a scheduler¶
MPI-based dask scheduler¶
Dask provides a dask-mpi
package that sets this up for you and creates a scheduler file to pass to ESPEI.
The scheduler information will be serialized as a JSON file that you set in your ESPEI input file.
The dask-mpi package (version 2.0.0 or greater) must be installed before you can use it:
conda install -c conda-forge --yes "dask-mpi>=2"
Note that you may also need a particular MPI implementation, conda-forge provides packages for OpenMPI or MPICH. You can pick a particular one by installing dask-mpi using either:
conda install -c conda-forge --yes "dask-mpi>=2" "mpi=*=openmpi"
or
conda install -c conda-forge --yes "dask-mpi>=2" "mpi=*=mpich"
or let conda pick one for you by not including any.
To start the scheduler and workers in the background, you can run the dask-mpi
command (use dask-mpi --help
to check the arguments).
The following command will start a scheduler on the main MPI task, then a worker for each remaining MPI task that mpirun
sees.
mpirun dask-mpi --scheduler-file my_scheduler.json --nthreads 1 --memory-limit 0 &
Generic scheduler¶
If you need further customization of dask schedulers, you can start a distributed Client any way you like, then write out the scheduler file for ESPEI to use.
For example, if you name the following file start_scheduler.py
, you can run this Python script in the background, which will contain the scheduler and workers, then ESPEI will connect to it.
# start_scheduler.py
from distributed import Client, LocalCluster
from tornado.ioloop import IOLoop
if __name__ == '__main__':
loop = IOLoop()
cluster = LocalCluster(n_workers=4, threads_per_worker=1, memory_limit=0)
client = Client(cluster)
client.write_scheduler_file('my-scheduler.json')
loop.start() # keeps the scheduler running
loop.close()
Running start_scheduler.py &
, will run this process in the background with 4 processes.
ESPEI Input¶
After starting the scheduler on the cluster, you run ESPEI like normal.
For the most part, this ESPEI input file is the same as you use locally, except the scheduler
parameter is set to the name of your scheduler file.
Here is an example for Bayesian parameter estimation using MCMC starting from a generated TDB with a scheduler file named my-scheduler.json
:
system:
phase_models: my-phases.json
datasets: my-input-data
mcmc:
iterations: 1000
input_db: my-tdb.tdb
scheduler: my-scheduler.json
Example Queue Script - MPI¶
To run on through a queueing system, you’ll often use queue scripts that start batch jobs.
This example will create an MPI scheduler using dask-mpi
via mpirun
(or other MPI executable).
Since many MPI jobs are run through batch schedulers, an example script for a PBS job looks like:
#!/bin/bash
#PBS -l nodes=1:ppn=20
#PBS -l walltime=48:00:00
#PBS -A open
#PBS -N espei-mpi
#PBS -o espei-mpi.out
#PBS -e espei-mpi.error
# starts the scheduler on MPI and creates the scheduler file called 'my_scheduler.json'
# you can replace this line with any script that starts a scheduler
# e.g. a `start_scheduler.py` file
# make sure it ends with `&` to run the process in the background
mpirun dask-mpi --scheduler-file my_scheduler.json --nthreads 1 --memory-limit 0 &
# runs ESPEI as normal
espei --in espei-mpi-input.yaml
References¶
See http://distributed.readthedocs.io/en/latest/setup.html?highlight=dask-mpi#using-mpi for more details.
API Documentation¶
espei package¶
Subpackages¶
espei.error_functions package¶
Calculate error due to measured activities.
-
espei.error_functions.activity_error.
calculate_activity_error
(dbf, comps, phases, datasets, parameters=None, phase_models=None, callables=None, data_weight=1.0)¶ Return the sum of square error from activity data
- Parameters
dbf (pycalphad.Database) – Database to consider
comps (list) – List of active component names
phases (list) – List of phases to consider
datasets (espei.utils.PickleableTinyDB) – Datasets that contain single phase data
parameters (dict) – Dictionary of symbols that will be overridden in pycalphad.equilibrium
phase_models (dict) – Phase models to pass to pycalphad calculations
callables (dict) – Callables to pass to pycalphad
data_weight (float) – Weight for standard deviation of activity measurements, dimensionless. Corresponds to the standard deviation of differences in chemical potential in typical measurements of activity, in J/mol.
- Returns
A single float of the sum of square errors
- Return type
float
Notes
General procedure: 1. Get the datasets 2. For each dataset
Calculate reference state equilibrium
Calculate current chemical potentials
Find the target chemical potentials
Calculate error due to chemical potentials
-
espei.error_functions.activity_error.
chempot_error
(sample_chempots, target_chempots, std_dev=10.0)¶ Return the sum of square error from chemical potentials
- sample_chempotsnumpy.ndarray
Calculated chemical potentials
- target_activitynumpy.ndarray
Chemical potentials to target
- std_devfloat
Standard deviation of activity measurements in J/mol. Corresponds to the standard deviation of differences in chemical potential in typical measurements of activity.
- Returns
Error due to chemical potentials
- Return type
float
-
espei.error_functions.activity_error.
target_chempots_from_activity
(component, target_activity, temperatures, reference_result)¶ Return an array of experimental chemical potentials for the component
- Parameters
component (str) – Name of the component
target_activity (numpy.ndarray) – Array of experimental activities
temperatures (numpy.ndarray) – Ravelled array of temperatures (of same size as
exp_activity
).reference_result (xarray.Dataset) – Dataset of the equilibrium reference state. Should contain a singe point calculation.
- Returns
Array of experimental chemical potentials
- Return type
numpy.ndarray
Convenience function to create a context for the built in error functions
-
espei.error_functions.context.
setup_context
(dbf, datasets, symbols_to_fit=None, data_weights=None, make_callables=True)¶ Set up a context dictionary for calculating error.
- Parameters
dbf (Database) – A pycalphad Database that will be fit
datasets (PickleableTinyDB) – A database of single- and multi-phase data to fit
symbols_to_fit (list of str) – List of symbols in the Database that will be fit. If None (default) are passed, then all parameters prefixed with VV followed by a number, e.g. VV0001 will be fit.
Notes
A copy of the Database is made and used in the context. To commit changes back to the original database, the dbf.symbols.update method should be used.
Calculate error due to equilibrium thermochemical properties.
-
class
espei.error_functions.equilibrium_thermochemical_error.
EqPropData
(dbf, species, phases, potential_conds, composition_conds, models, params_keys, phase_records, output, samples, weight, reference)¶ Bases:
tuple
-
composition_conds
: Sequence[Dict[pycalphad.variables.MoleFraction, float]]¶ Alias for field number 4
-
dbf
: pycalphad.io.database.Database¶ Alias for field number 0
-
models
: Dict[str, pycalphad.model.Model]¶ Alias for field number 5
-
output
: str¶ Alias for field number 8
-
params_keys
: Dict[str, float]¶ Alias for field number 6
-
phase_records
: Sequence[Dict[str, pycalphad.core.phase_rec.PhaseRecord]]¶ Alias for field number 7
-
phases
: Sequence[str]¶ Alias for field number 2
-
potential_conds
: Dict[pycalphad.variables.StateVariable, float]¶ Alias for field number 3
-
reference
: str¶ Alias for field number 11
-
samples
: numpy.ndarray¶ Alias for field number 9
-
species
: Sequence[pycalphad.variables.Species]¶ Alias for field number 1
-
weight
: numpy.ndarray¶ Alias for field number 10
-
-
espei.error_functions.equilibrium_thermochemical_error.
build_eqpropdata
(data: tinydb.table.Document, dbf: pycalphad.io.database.Database, parameters: Optional[Dict[str, float]] = None, data_weight_dict: Optional[Dict[str, float]] = None) → espei.error_functions.equilibrium_thermochemical_error.EqPropData¶ Build EqPropData for the calculations corresponding to a single dataset.
- Parameters
data (tinydb.database.Document) – Document corresponding to a single ESPEI dataset.
dbf (Database) – Database that should be used to construct the Model and PhaseRecord objects.
parameters (Optional[Dict[str, float]]) – Mapping of parameter symbols to values.
data_weight_dict (Optional[Dict[str, float]]) – Mapping of a data type (e.g. HM or SM) to a weight.
- Returns
- Return type
-
espei.error_functions.equilibrium_thermochemical_error.
calc_prop_differences
(eqpropdata: espei.error_functions.equilibrium_thermochemical_error.EqPropData, parameters: numpy.ndarray, approximate_equilibrium: Optional[bool] = False) → Tuple[numpy.ndarray, numpy.ndarray]¶ Calculate differences between the expected and calculated values for a property
- Parameters
eqpropdata (EqPropData) – Data corresponding to equilibrium calculations for a single datasets.
parameters (np.ndarray) – Array of parameters to fit. Must be sorted in the same symbol sorted order used to create the PhaseRecords.
approximate_equilibrium (Optional[bool]) – Whether or not to use an approximate version of equilibrium that does not refine the solution and uses
starting_point
instead.
- Returns
Pair of * differences between the calculated property and expected property * weights for this dataset
- Return type
Tuple[np.ndarray, np.ndarray]
-
espei.error_functions.equilibrium_thermochemical_error.
calculate_equilibrium_thermochemical_probability
(eq_thermochemical_data: Sequence[espei.error_functions.equilibrium_thermochemical_error.EqPropData], parameters: numpy.ndarray, approximate_equilibrium: Optional[bool] = False) → float¶ Calculate the total equilibrium thermochemical probability for all EqPropData
- Parameters
eq_thermochemical_data (Sequence[EqPropData]) – List of equilibrium thermochemical data corresponding to the datasets.
parameters (np.ndarray) – Values of parameters for this iteration to be updated in PhaseRecords.
approximate_equilibrium (Optional[bool], optional) –
eq_thermochemical_data –
- Returns
Sum of log-probability for all thermochemical data.
- Return type
float
-
espei.error_functions.equilibrium_thermochemical_error.
get_equilibrium_thermochemical_data
(dbf: pycalphad.io.database.Database, comps: Sequence[str], phases: Sequence[str], datasets: espei.utils.PickleableTinyDB, parameters: Optional[Dict[str, float]] = None, data_weight_dict: Optional[Dict[str, float]] = None) → Sequence[espei.error_functions.equilibrium_thermochemical_error.EqPropData]¶ Get all the EqPropData for each matching equilibrium thermochemical dataset in the datasets
- Parameters
dbf (Database) – Database with parameters to fit
comps (Sequence[str]) – List of pure element components used to find matching datasets.
phases (Sequence[str]) – List of phases used to search for matching datasets.
datasets (PickleableTinyDB) – Datasets that contain single phase data
parameters (Optional[Dict[str, float]]) – Mapping of parameter symbols to values.
data_weight_dict (Optional[Dict[str, float]]) – Mapping of a data type (e.g. HM or SM) to a weight.
Notes
Found datasets will be subsets of the components and phases. Equilibrium thermochemical data is assumed to be any data that does not have the solver key, and does not have an output of ZPF or ACR (which correspond to different data types than can be calculated here.)
- Returns
- Return type
Sequence[EqPropData]
Calculate error due to thermochemical quantities: heat capacity, entropy, enthalpy.
-
espei.error_functions.non_equilibrium_thermochemical_error.
calculate_non_equilibrium_thermochemical_probability
(dbf, thermochemical_data, parameters=None)¶ Calculate the weighted single phase error in the Database
- Parameters
dbf (pycalphad.Database) – Database to consider
thermochemical_data (list) – List of thermochemical data dicts
parameters (np.ndarray) – Array of parameters to calculate the error with.
- Returns
A single float of the residual sum of square errors
- Return type
float
Notes
There are different single phase values, HM_MIX, SM_FORM, CP_FORM, etc. Each of these have different units and the error cannot be compared directly. To normalize all of the errors, a normalization factor must be used. Equation 2.59 and 2.60 in Lukas, Fries, and Sundman “Computational Thermodynamics” shows how this can be considered. Each type of error will be weighted by the reciprocal of the estimated uncertainty in the measured value and conditions. The weighting factor is calculated by $ p_i = (Delta L_i)^{-1} $ where $ Delta L_i $ is the uncertainty in the measurement. We will neglect the uncertainty for quantities such as temperature, assuming they are small.
-
espei.error_functions.non_equilibrium_thermochemical_error.
calculate_points_array
(phase_constituents, configuration, occupancies=None)¶ Calculate the points array to use in pycalphad calculate calls.
Converts the configuration data (and occupancies for mixing data) into the points array by looking up the indices in the active phase constituents.
- Parameters
phase_constituents (list) – List of active constituents in a phase
configuration (list) – List of the sublattice configuration
occupancies (list) – List of sublattice occupancies. Required for mixing sublattices, otherwise takes no effect.
- Returns
- Return type
numpy.ndarray
Notes
Errors will be raised if components in the configuration are not in the corresponding phase constituents sublattice.
-
espei.error_functions.non_equilibrium_thermochemical_error.
get_prop_samples
(desired_data, constituents)¶ Return data values and the conditions to calculate them using pycalphad.calculate
- Parameters
desired_data (List[Dict[str, Any]]) – List of dataset dictionaries that contain the values to sample
constituents (List[List[str]]) – Names of constituents in each sublattice.
- Returns
Dictionary of condition kwargs for pycalphad’s calculate and the expected values
- Return type
Dict[str, Union[float, ArrayLike, List[float]]]
-
espei.error_functions.non_equilibrium_thermochemical_error.
get_thermochemical_data
(dbf, comps, phases, datasets, weight_dict=None, symbols_to_fit=None)¶ - Parameters
dbf (pycalphad.Database) – Database to consider
comps (list) – List of active component names
phases (list) – List of phases to consider
datasets (espei.utils.PickleableTinyDB) – Datasets that contain single phase data
weight_dict (dict) – Dictionary of weights for each data type, e.g. {‘HM’: 200, ‘SM’: 2}
symbols_to_fit (list) – Parameters to fit. Used to build the models and PhaseRecords.
- Returns
List of data dictionaries to iterate over
- Return type
list
Calculate driving_force due to ZPF tielines.
The general approach is similar to the PanOptimizer rough search method.
With all phases active, calculate the chemical potentials of the tieline endpoints via
equilibrium
calls. Done inestimate_hyperplane
.Calculate the target chemical potentials, which are the average chemical potentials of all of the current chemical potentials at the tieline endpoints.
Calculate the current chemical potentials of the desired single phases
The error is the difference between these chemical potentials
There’s some special handling for tieline endpoints where we do not know the composition conditions to calculate chemical potentials at.
-
class
espei.error_functions.zpf_error.
PhaseRegion
(region_phases, potential_conds, comp_conds, phase_points, phase_flags, dbf, species, phases, models, phase_records)¶ Bases:
tuple
-
comp_conds
: Sequence[Dict[pycalphad.variables.MoleFraction, float]]¶ Alias for field number 2
-
dbf
: pycalphad.io.database.Database¶ Alias for field number 5
-
models
: Dict[str, pycalphad.model.Model]¶ Alias for field number 8
-
phase_flags
: Sequence[str]¶ Alias for field number 4
-
phase_points
: Sequence[Union[int, float, complex, str, bytes, numpy.generic, Sequence[Union[int, float, complex, str, bytes, numpy.generic]], Sequence[Sequence[Any]], numpy.typing._array_like._SupportsArray]]¶ Alias for field number 3
-
phase_records
: Sequence[Dict[str, pycalphad.core.phase_rec.PhaseRecord]]¶ Alias for field number 9
-
phases
: Sequence[str]¶ Alias for field number 7
-
potential_conds
: Dict[pycalphad.variables.StateVariable, float]¶ Alias for field number 1
-
region_phases
: Sequence[str]¶ Alias for field number 0
-
species
: Sequence[pycalphad.variables.Species]¶ Alias for field number 6
-
-
espei.error_functions.zpf_error.
calculate_zpf_driving_forces
(zpf_data: Sequence[Dict[str, Any]], parameters: Optional[Union[int, float, complex, str, bytes, numpy.generic, Sequence[Union[int, float, complex, str, bytes, numpy.generic]], Sequence[Sequence[Any]], numpy.typing._array_like._SupportsArray]] = None, approximate_equilibrium: bool = False, short_circuit: bool = False) → Tuple[List[List[float]], List[List[float]]]¶ Calculate error due to phase equilibria data
- zpf_dataSequence[Dict[str, Any]]
Datasets that contain single phase data
- parametersArrayLike
Array of parameters to calculate the error with.
- approximate_equilibriumbool
Whether or not to use an approximate version of equilibrium that does not refine the solution and uses
starting_point
instead.- short_circuit: bool
If True, immediately return a size 1 array with a driving force of
np.nan
(failed hyperplane) ornp.inf
(failed driving force). Can save computational time if the caller will aggregate driving forces.
- Returns
Driving forces and weights as ragged 2D arrays with shape
(len(zpf_data), len(vertices in each zpf_data))
- Return type
Tuple[List[List[float]], List[List[float]]]
Notes
The physical picture of the standard deviation is that we’ve measured a ZPF line. That line corresponds to some equilibrium chemical potentials. The standard deviation is the standard deviation of those ‘measured’ chemical potentials.
-
espei.error_functions.zpf_error.
calculate_zpf_error
(zpf_data: Sequence[Dict[str, Any]], parameters: Optional[numpy.ndarray] = None, data_weight: int = 1.0, approximate_equilibrium: bool = False) → float¶ Calculate the likelihood due to phase equilibria data.
For detailed documentation, see
calculate_zpf_driving_forces
- Returns
Log probability of ZPF driving forces
- Return type
float
-
espei.error_functions.zpf_error.
driving_force_to_hyperplane
(target_hyperplane_chempots: numpy.ndarray, comps: Sequence[str], phase_region: espei.error_functions.zpf_error.PhaseRegion, vertex_idx: int, parameters: numpy.ndarray, approximate_equilibrium: bool = False) → float¶ Calculate the integrated driving force between the current hyperplane and target hyperplane.
-
espei.error_functions.zpf_error.
estimate_hyperplane
(phase_region: espei.error_functions.zpf_error.PhaseRegion, parameters: numpy.ndarray, approximate_equilibrium: bool = False) → numpy.ndarray¶ Calculate the chemical potentials for the target hyperplane, one vertex at a time
Notes
This takes just one set of phase equilibria, a phase region, e.g. a dataset point of [[‘FCC_A1’, [‘CU’], [0.1]], [‘LAVES_C15’, [‘CU’], [0.3]]] and calculates the chemical potentials given all the phases possible at the given compositions. Then the average chemical potentials of each end point are taken as the target hyperplane for the given equilibria.
-
espei.error_functions.zpf_error.
extract_conditions
(all_conditions: Dict[pycalphad.variables.StateVariable, numpy.ndarray], idx: int) → Dict[pycalphad.variables.StateVariable, float]¶ Conditions are either scalar or 1d arrays for the conditions in the entire dataset. This function extracts the condition corresponding to the current region, based on the index in the 1d condition array.
-
espei.error_functions.zpf_error.
extract_phases_comps
(phase_region)¶ Extract the phase names, phase compositions and any phase flags from each tie-line point in the phase region
-
espei.error_functions.zpf_error.
get_zpf_data
(dbf: pycalphad.io.database.Database, comps: Sequence[str], phases: Sequence[str], datasets: espei.utils.PickleableTinyDB, parameters: Dict[str, float])¶ Return the ZPF data used in the calculation of ZPF error
- Parameters
comps (list) – List of active component names
phases (list) – List of phases to consider
datasets (espei.utils.PickleableTinyDB) – Datasets that contain single phase data
parameters (dict) – Dictionary mapping symbols to optimize to their initial values
- Returns
List of data dictionaries with keys
weight
,data_comps
andphase_regions
.data_comps
are the components for the data in question.phase_regions
are the ZPF phases, state variables and compositions.- Return type
list
Functions for calculating error.
espei.optimizers package¶
Defines a OptNode and OptGraph to be used by OptimizerBase subclasses. Together they define the path of one or more optimizations and can be used to store and replay optimization history.
-
class
espei.optimizers.graph.
OptGraph
(root)¶ Bases:
object
Directed acyclic graph of optimal parameters.
Notes
The OptGraph defines a directed acyclic graph of commits. Each commit corresponds to a single OptNode. The root node is intended to be the fresh parameters from the database before any optimization. Therefore, any path from the root node to any other node represents a set of optimizations to the parameters in the database.
-
add_node
(node, parent)¶
-
-
class
espei.optimizers.graph.
OptNode
(parameters, datasets, node_id=None)¶ Bases:
object
Node as the result of an optimization.
-
parameters
¶ - Type
dict
-
datasets
¶ - Type
-
id
¶ - Type
int
-
children
¶ - Type
list of OptNode
Notes
OptNodes are individual nodes in the graph that correspond to the result of a call to fit - they represent optimized parameters given the parent state and some data (also part of the OptNode).
Each OptNode can only be derived from one set of parameters, however one parameter state may be a branching point to many new parameter states, so an OptNode can have only one parent, but many children.
-
-
class
espei.optimizers.opt_base.
OptimizerBase
(dbf)¶ Bases:
object
Enable fitting and replaying fitting steps
-
commit
()¶
-
discard
()¶ Discard all staged nodes
-
fit
(symbols, datasets, *args, **kwargs)¶
-
static
predict
(params, context)¶ Given a set of parameters and a context, return the resulting sum of square error.
- Parameters
params (list) – 1 dimensional array of parameters
context (dict) – Dictionary of arguments/keyword arguments to pass to functions
- Returns
- Return type
float
-
reset_database
()¶ Set the Database to the state of the current node
-
-
class
espei.optimizers.opt_mcmc.
EmceeOptimizer
(dbf, scheduler=None)¶ Bases:
espei.optimizers.opt_base.OptimizerBase
An optimizer using an EnsembleSampler based on Goodman and Weare [1] implemented in emcee [2]
-
scheduler
¶ An object implementing a map function
- Type
mappable
-
save_interval
¶ Interval of iterations to save the tracefile and probfile.
- Type
int
-
tracefile
¶ Filename to store the trace with NumPy.save. Array has shape (chains, iterations, parameters). Defaults to None.
- Type
str
-
probfile
¶ filename to store the log probability with NumPy.save. Has shape (chains, iterations)
- Type
str
References
[1] Goodman and Weare, Ensemble Samplers with Affine Invariance. Commun. Appl. Math. Comput. Sci. 5, 65-80 (2010). [2] Foreman-Mackey, Hogg, Lang, Goodman, emcee: The MCMC Hammer. Publ. Astron. Soc. Pac. 125, 306-312 (2013).
-
do_sampling
(chains, iterations)¶
-
static
get_priors
(prior, symbols, params)¶ Build priors for a particular set of fitting symbols and initial parameters. Returns a dict that should be used to update the context.
- Parameters
prior (dict or PriorSpec or None) – Prior to initialize. See the docs on
symbols (list of str) – List of symbols that will be fit
params (list of float) – List of parameter values corresponding to the symbols. These should be the initial parameters that the priors will be based off of.
-
static
initialize_chains_from_trace
(restart_trace)¶
-
static
initialize_new_chains
(params, chains_per_parameter, std_deviation, deterministic=True)¶ Return an array of num_samples from a Gaussian distribution about each parameter.
- Parameters
params (ndarray) – 1D array of initial parameters that will be the mean of the distribution.
num_samples (int) – Number of chains to initialize.
chains_per_parameter (int) – number of chains for each parameter. Must be an even integer greater or equal to 2. Defaults to 2.
std_deviation (float) – Fractional standard deviation of the parameters to use for initialization.
deterministic (bool) – True if the parameters should be generated deterministically.
- Returns
- Return type
ndarray
Notes
Parameters are sampled from
normal(loc=param, scale=param*std_deviation)
. A parameter of zero will produce a standard deviation of zero and therefore only zeros will be sampled. This will break emcee’s StretchMove for this parameter and only zeros will be selected.
-
static
predict
(params, **ctx)¶ Calculate lnprob = lnlike + lnprior
-
save_sampler_state
()¶ Convenience function that saves the trace and lnprob if they haven’t been set to None by the user.
Requires that the sampler attribute be set.
-
-
class
espei.optimizers.opt_scipy.
SciPyOptimizer
(dbf)¶ Bases:
espei.optimizers.opt_base.OptimizerBase
-
static
predict
(params, ctx)¶ Given a set of parameters and a context, return the resulting sum of square error.
- Parameters
params (list) – 1 dimensional array of parameters
context (dict) – Dictionary of arguments/keyword arguments to pass to functions
- Returns
- Return type
float
-
static
-
exception
espei.optimizers.utils.
OptimizerError
¶ Bases:
BaseException
espei.parameter_selection package¶
Building candidate models
-
espei.parameter_selection.model_building.
build_candidate_models
(configuration, features)¶ Return a dictionary of features and candidate models
- Parameters
configuration (tuple) – Configuration tuple, e.g. ((‘A’, ‘B’, ‘C’), ‘A’)
features (dict) – Dictionary of {str: list} of generic features for a model, not considering the configuration. For example: {‘CPM_FORM’: [sympy.S.One, v.T, v.T**2, v.T**3]}
- Returns
Dictionary of {feature: [candidate_models])
- Return type
dict
Notes
Currently only works for binary and ternary interactions.
Candidate models match the following spec: 1. Candidates with multiple features specified will have 2. orders of parameters (L0, L0 and L1, …) have the same number of temperatures
Note that high orders of parameters with multiple temperatures are not required to contain all the temperatures of the low order parameters. For example, the following parameters can be generated L0: A L1: A + BT
-
espei.parameter_selection.model_building.
build_feature_sets
(temperature_features, interaction_features)¶ Return a list of broadcasted features
- Parameters
temperature_features (list) – List of temperature features that will become a successive_list, such as [TlogT, T-1, T2]
interaction_features (list) – List of interaction features that will become a successive_list, such as [YS, YS*Z, YS*Z**2]
- Returns
- Return type
list
Notes
This allows two sets of features, e.g. [TlogT, T-1, T2] and [YS, YS*Z, YS*Z**2] and generates a list of feature sets where the temperatures and interactions are broadcasted successively.
Generates candidate feature sets like: L0: A + BT, L1: A L0: A , L1: A + BT
but not lists that are not successive: L0: A + BT, L1: Nothing, L2: A L0: Nothing, L1: A + BT
There’s still some debate whether it makes sense from an information theory perspective to add a L1 B term without an L0 B term. However this might be more representative of how people usually model thermodynamics.
Does not distribute multiplication/sums or make assumptions about the elements of the feature lists. They can be strings, ints, objects, tuples, etc..
The number of features (related to the complexity) is a geometric series. For $N$ temperature features and $M$ interaction features, the total number of feature sets should be $N*(1-N**M)/(1-N)$. If $N=1$, then there are $M$ total feature sets.
-
espei.parameter_selection.model_building.
make_successive
(xs)¶ Return a list of successive combinations
- Parameters
xs (list) – List of elements, e.g. [X, Y, Z]
- Returns
List of combinations where each combination include all the preceding elements
- Return type
list
Examples
>>> make_successive(['W', 'X', 'Y', 'Z']) [['W'], ['W', 'X'], ['W', 'X', 'Y'], ['W', 'X', 'Y', 'Z']]
Tools for construction Redlich-Kister polynomials used in parameter selection.
-
espei.parameter_selection.redlich_kister.
calc_interaction_product
(site_fractions)¶ Calculate the interaction product for sublattice site fractions
Callers should take care that the site fractions correspond to constituents in sorted order, since there’s an order-dependent subtraction.
- Parameters
site_fractions (List[List[float]]) – List of site fractions for each sublattice. The list should a ragged 2d list of shape (sublattices, site fractions).
- Returns
A scalar for binary interactions and a list of 3 floats for ternary interactions
- Return type
Union[float, List[float]]
Examples
>>> # interaction product for an (A) site_fractions >>> calc_interaction_product([[1.0]]) 1.0 >>> # interaction product for [(A,B), (A,B)(A)] site fractions that are equal >>> calc_interaction_product([[0.5, 0.5]]) 0.0 >>> calc_interaction_product([[0.5, 0.5], 1]) 0.0 >>> # interaction product for an [(A,B)] site_fractions >>> calc_interaction_product([[0.1, 0.9]]) -0.8 >>> # interaction product for an [(A,B)(A,B)] site_fractions >>> calc_interaction_product([[0.2, 0.8], [0.4, 0.6]]) 0.12 >>> # ternary case, (A,B,C) interaction >>> calc_interaction_product([[0.333, 0.333, 0.334]]) [0.333, 0.333, 0.334] >>> # ternary 2SL case, (A,B,C)(A) interaction >>> calc_interaction_product([[0.333, 0.333, 0.334], 1.0]) [0.333, 0.333, 0.334]
Fit, score and select models
-
espei.parameter_selection.selection.
fit_model
(feature_matrix, data_quantities, ridge_alpha, weights=None)¶ Return model coefficients fit by scikit-learn’s LinearRegression
- Parameters
feature_matrix (ndarray) – (M*N) regressor matrix. The transformed model inputs (y_i, T, P, etc.)
data_quantities (ndarray) – (M,) response vector. Target values of the output (e.g. HM_MIX) to reproduce.
ridge_alpha (float) – Value of the $alpha$ hyperparameter used in ridge regression. Defaults to 1.0e-100, which should be degenerate with ordinary least squares regression. For now, the parameter is applied to all features.
- Returns
List of model coefficients of shape (N,)
- Return type
list
Notes
Solve Ax = b. x are the desired model coefficients. A is the ‘feature_matrix’. b corrresponds to ‘data_quantities’.
-
espei.parameter_selection.selection.
score_model
(feature_matrix, data_quantities, model_coefficients, feature_list, weights, aicc_factor=None, rss_numerical_limit=1e-16)¶ Use the AICc to score a model that has been fit.
- Parameters
feature_matrix (ndarray) – (M*N) regressor matrix. The transformed model inputs (y_i, T, P, etc.)
data_quantities (ndarray) – (M,) response vector. Target values of the output (e.g. HM_MIX) to reproduce.
model_coefficients (list) – List of fitted model coefficients to be scored. Has shape (N,).
feature_list (list) – Polynomial coefficients corresponding to each column of ‘feature_matrix’. Has shape (N,). Purely a logging aid.
aicc_factor (float) – Multiplication factor for the AICc’s parameter penalty.
rss_numerical_limit (float) – Anything with an absolute value smaller than this is set to zero.
- Returns
A model score
- Return type
float
Notes
Solve Ax = b, where ‘feature_matrix’ is A and ‘data_quantities’ is b.
The likelihood function is a simple least squares with no regularization. The form of the AIC is valid under assumption all sample variances are random and Gaussian, model is univariate. It is assumed the model here is univariate with T.
-
espei.parameter_selection.selection.
select_model
(candidate_models, ridge_alpha, weights, aicc_factor=None)¶ Select a model from a series of candidates by fitting and scoring them
- Parameters
candidate_models (list) – List of tuples of (features, feature_matrix, data_quantities)
ridge_alpha (float) – Value of the $alpha$ hyperparameter used in ridge regression. Defaults to 1.0e-100, which should be degenerate with ordinary least squares regression. For now, the parameter is applied to all features.
aicc_factor (float) – Multiplication factor for the AICc’s parameter penalty.
- Returns
Tuple of (feature_list, model_coefficients) for the highest scoring model
- Return type
tuple
Tools used across parameter selection modules
-
espei.parameter_selection.utils.
get_data_quantities
(desired_property, fixed_model, fixed_portions, data, sample_condition_dicts)¶ - Parameters
desired_property (str) – String property corresponding to the features that could be fit, e.g. HM, SM_FORM, CPM_MIX
fixed_model (pycalphad.Model) – Model with all lower order (in composition) terms already fit. Pure element reference state (GHSER functions) should be set to zero.
fixed_portions (List[sympy.Expr]) – SymPy expressions for model parameters and interaction productions for higher order (in T) terms for this property, e.g. [0, 3.0*YS*v.T]. In [qty]/mole-formula.
data (List[Dict[str, Any]]) – ESPEI single phase datasets for this property.
- Returns
np.ndarray[ – Ravelled data quantities in [qty]/mole-formula
- Return type
]
Notes
pycalphad Model parameters (and therefore fixed_portions) are stored as per mole-formula quantites, but the calculated properties and our data are all in [qty]/mole-atoms. We multiply by mole-atoms/mole-formula to convert the units to [qty]/mole-formula.
-
espei.parameter_selection.utils.
shift_reference_state
(desired_data, feature_transform, fixed_model, mole_atoms_per_mole_formula_unit)¶ Shift _MIX or _FORM data to a common reference state in per mole-atom units.
- Parameters
desired_data (List[Dict[str, Any]]) – ESPEI single phase dataset
feature_transform (Callable) – Function to transform an AST for the GM property to the property of interest, i.e. entropy would be
lambda GM: -sympy.diff(GM, v.T)
fixed_model (pycalphad.Model) – Model with all lower order (in composition) terms already fit. Pure element reference state (GHSER functions) should be set to zero.
mole_atoms_per_mole_formula_unit (float) – Number of moles of atoms in every mole atom unit.
- Returns
Data for this feature in [qty]/mole-formula in a common reference state.
- Return type
np.ndarray
- Raises
ValueError –
Notes
pycalphad Model parameters are stored as per mole-formula quantites, but the calculated properties and our data are all in [qty]/mole-atoms. We multiply by mole-atoms/mole-formula to convert the units to [qty]/mole-formula.
Submodules¶
espei.analysis module¶
Tools for analyzing ESPEI runs
-
espei.analysis.
truncate_arrays
(trace_array, prob_array=None)¶ Return slides of ESPEI output arrays with any empty remaining iterations (zeros) removed.
- Parameters
trace_array (np.ndarray) – Array of the trace from an ESPEI run. Should have shape (chains, iterations, parameters)
prob_array (np.ndarray) – Array of the lnprob output from an ESPEI run. Should have shape (chains, iterations)
- Returns
A slide of the zeros-removed trace array is returned if only the trace is passed. Otherwise a tuple of both the trace and lnprob are returned.
- Return type
np.ndarry or (np.ndarray, np.ndarray)
Examples
>>> from espei.analysis import truncate_arrays >>> trace = np.array([[[1, 0], [2, 0], [3, 0], [0, 0]], [[0, 2], [0, 4], [0, 6], [0, 0]]]) # 3 iterations of 4 allocated >>> truncate_arrays(trace).shape (2, 3, 2)
espei.citing module¶
Define citations for ESPEI
espei.core_utils module¶
Internal utilities for developer use. May not be useful to users.
-
espei.core_utils.
get_data
(comps, phase_name, configuration, symmetry, datasets, prop)¶ Return list of cleaned single phase datasets matching the passed arguments.
- Parameters
comps (list) – List of string component names
phase_name (str) – Name of phase
configuration (tuple) – Sublattice configuration as a tuple, e.g. (“CU”, (“CU”, “MG”))
symmetry (list of lists) – List of sublattice indices with symmetry
datasets (espei.utils.PickleableTinyDB) – Database of datasets to search for data
prop (list) – String name of the property of interest.
- Returns
List of datasets matching the arguments.
- Return type
list
-
espei.core_utils.
get_prop_data
(comps, phase_name, prop, datasets, additional_query=None)¶ Return datasets that match the components, phase and property
- Parameters
comps (list) – List of components to get data for
phase_name (str) – Name of the phase to get data for
prop (str) – Property to get data for
datasets (espei.utils.PickleableTinyDB) – Datasets to search for data
additional_query (tinydb.Query) – A TinyDB Query object to search for. If None, a Query() will be created that does nothing.
- Returns
List of dictionary datasets that match the criteria
- Return type
list
-
espei.core_utils.
ravel_conditions
(values, *conditions, **kwargs)¶ Broadcast and flatten conditions to the shape dictated by the values.
Special handling for ZPF data that does not have nice array values.
- Parameters
values (list) – Multidimensional lists of values
conditions (list) – List of conditions to broadcast. Must be the same length as the number of dimensions of the values array. In code, the following must be True: all([s == len(cond) for s, cond in zip(values.shape, conditions)])
zpf (bool, optional) – Whether to consider values as a special case of ZPF data (not an even grid of conditions) Default is False
- Returns
Tuple of ravelled conditions
- Return type
tuple
Notes
The current implementation of ZPF data only has the shape for one condition and this assumption is hardcoded in various places.
Here we try to be as general as possible by explicitly calculating the shape of the ZPF values.
A complication of this is that the user of this function must pass the correct conditions because usually T and P are specified in ZPF (but, again, only one can actually be a condition given the current shape).
-
espei.core_utils.
ravel_zpf_values
(desired_data, independent_comps, conditions=None)¶ Unpack the phases and compositions from ZPF data. Dependent components are converted to independent components.
- Parameters
desired_data (espei.utils.PickleableTinyDB) – The selected data
independent_comps (list) – List of indepdendent components. Used for mass balance component conversion
conditions (dict) – Conditions to filter for. Right now only considers fixed temperatures
- Returns
A dictonary of list of lists of tuples. Each dictionary key is the number of phases in equilibrium, e.g. a key “2” might have values [[(PHASE_NAME_1, {‘C1’: X1, ‘C2’: X2}, refkey), (PHASE_NAME_2, {‘C1’: X1, ‘C2’: X2}, refkey)], …] Three would have three inner tuples and so on.
- Return type
dict
-
espei.core_utils.
recursive_map
(f, x)¶ map, but over nested lists
- Parameters
f (callable) – Function to apply to x
x (list or value) – Value passed to v
- Returns
- Return type
list or value
-
espei.core_utils.
symmetry_filter
(x, config, symmetry)¶ Return True if the candidate sublattice configuration has any symmetry which matches the phase model symmetry.
- Parameters
x (dict) – the candidate dataset ‘solver’ dict. Must contain the “sublattice_configurations” key
config (list) – the configuration of interest: e.g. [‘AL’, [‘AL’, ‘NI’], ‘VA’]
symmetry (list) – tuple of tuples where each inner tuple is a group of equivalent sublattices. A value of ((0, 1), (2, 3, 4)) means that sublattices at indices 0 and 1 are symmetrically equivalent to each other and sublattices at indices 2, 3, and 4 are symetrically equivalent to each other.
- Returns
- Return type
bool
espei.database_utils module¶
Provides utilities for creating and working with Databases in ESPEI
-
espei.database_utils.
initialize_database
(phase_models, ref_state, dbf=None, fallback_ref_state='SGTE91')¶ Return a Database boostraped with elements, species, phases and unary lattice stabilities.
- Parameters
phase_models (Dict[str, Any]) – Dictionary of components and phases to fit.
ref_state (str) – String of the reference data to use, e.g. ‘SGTE91’ or ‘SR2016’
dbf (Optional[Database]) – Initial pycalphad Database that can have parameters that would not be fit by ESPEI
fallback_ref_state (str) – String of the reference data to use for SER data, defaults to ‘SGTE91’
- Returns
A new pycalphad Database object, or a modified one if it was given.
- Return type
Database
espei.datasets module¶
-
exception
espei.datasets.
DatasetError
¶ Bases:
Exception
Exception raised when datasets are invalid.
Modify datasets using the tags system
- Parameters
datasets (PickleableTinyDB) – Datasets to modify
tags (dict) – Dictionary of {tag: update_dict}
- Returns
- Return type
Notes
In general, everything replaces or is additive. We use the following update rules: 1. If the update value is a list, extend the existing list (empty list if key does not exist) 2. If the update value is scalar, override the previous (deleting any old value, if present) 3. If the update value is a dict, update the exist dict (empty dict if dict does not exist) 4. Otherwise, the value is updated, overriding the previous
Examples
>>> from espei.utils import PickleableTinyDB >>> from tinydb.storages import MemoryStorage >>> ds = PickleableTinyDB(storage=MemoryStorage) >>> doc_id = ds.insert({'tags': ['dft'], 'excluded_model_contributions': ['contrib']}) >>> my_tags = {'dft': {'excluded_model_contributions': ['idmix', 'mag'], 'weight': 5.0}} >>> from espei.datasets import apply_tags >>> apply_tags(ds, my_tags) >>> all_data = ds.all() >>> all(d['excluded_model_contributions'] == ['contrib', 'idmix', 'mag'] for d in all_data) True >>> all(d['weight'] == 5.0 for d in all_data) True
-
espei.datasets.
check_dataset
(dataset)¶ Ensure that the dataset is valid and consistent.
Currently supports the following validation checks: * data shape is valid * phases and components used match phases and components entered * individual shapes of keys, such as ZPF, sublattice configs and site ratios
Planned validation checks: * all required keys are present
Note that this follows some of the implicit assumptions in ESPEI at the time of writing, such that conditions are only P, T, configs for single phase and essentially only T for ZPF data.
- Parameters
dataset (dict) – Dictionary of the standard ESPEI dataset.
- Returns
- Return type
None
- Raises
DatasetError – If an error is found in the dataset
-
espei.datasets.
clean_dataset
(dataset)¶ Clean an ESPEI dataset dictionary.
- Parameters
dataset (dict) – Dictionary of the standard ESPEI dataset. dataset : dic
- Returns
Modified dataset that has been cleaned
- Return type
dict
Notes
Assumes a valid, checked dataset. Currently handles * Converting expected numeric values to floats
-
espei.datasets.
load_datasets
(dataset_filenames, include_disabled=False)¶ Create a PickelableTinyDB with the data from a list of filenames.
- Parameters
dataset_filenames ([str]) – List of filenames to load as datasets
- Returns
- Return type
-
espei.datasets.
recursive_glob
(start, pattern='*.json')¶ Recursively glob for the given pattern from the start directory.
- Parameters
start (str) – Path of the directory to walk while for file globbing
pattern (str) – Filename pattern to match in the glob.
- Returns
List of matched filenames
- Return type
[str]
espei.espei_script module¶
Automated fitting script.
A minimal run must specify an input.json and a datasets folder containing input files.
-
espei.espei_script.
get_run_settings
(input_dict)¶ Validate settings from a dict of possible input.
Performs the following actions: 1. Normalize (apply defaults) 2. Validate against the schema
- Parameters
input_dict (dict) – Dictionary of input settings
- Returns
Validated run settings
- Return type
dict
- Raises
ValueError –
-
espei.espei_script.
log_version_info
()¶ Print version info to the log
-
espei.espei_script.
main
()¶ Handle starting ESPEI from the command line. Parse command line arguments and input file.
-
espei.espei_script.
run_espei
(run_settings)¶ Wrapper around the ESPEI fitting procedure, taking only a settings dictionary.
- Parameters
run_settings (dict) – Dictionary of input settings
- Returns
- Return type
Either a Database (for generate parameters only) or a tuple of (Database, sampler)
espei.logger module¶
Implement an ESPEILogger with customized logging levels and methods
-
class
espei.logger.
ESPEILogger
(name, level=0)¶ Bases:
logging.Logger
-
TRACE
= 15¶
-
trace
(*args, **kwargs)¶
-
-
espei.logger.
config_logger
(verbosity=0, filename=None, reset_handlers=True)¶ Configure the root logger with the appropriate level and filename.
Uses ESPEI’s verbosity levels:
0: Warning
1: Info
2: Trace
3: Debug
If the
filename
is None, logs will be output to stderr.
espei.paramselect module¶
The paramselect module handles automated parameter selection for linear models.
Automated Parameter Selection End-members
Note: All magnetic parameters from literature for now. Note: No fitting below 298 K (so neglect third law issues for now).
For each step, add one parameter at a time and compute AICc with max likelihood.
Cp - TlnT, T**2, T**-1, T**3 - 4 candidate models (S and H only have one required parameter each. Will fit in full MCMC procedure)
Choose parameter set with best AICc score.
-
espei.paramselect.
fit_formation_energy
(dbf, comps, phase_name, configuration, symmetry, datasets, ridge_alpha=None, aicc_phase_penalty=None, features=None)¶ Find suitable linear model parameters for the given phase. We do this by successively fitting heat capacities, entropies and enthalpies of formation, and selecting against criteria to prevent overfitting. The “best” set of parameters minimizes the error without overfitting.
- Parameters
dbf (Database) – pycalphad Database. Partially complete, so we know what degrees of freedom to fix.
comps ([str]) – Names of the relevant components.
phase_name (str) – Name of the desired phase for which the parameters will be found.
configuration (ndarray) – Configuration of the sublattices for the fitting procedure.
symmetry ([[int]]) – Symmetry of the sublattice configuration.
datasets (PickleableTinyDB) – All the datasets desired to fit to.
ridge_alpha (float) – Value of the $alpha$ hyperparameter used in ridge regression. Defaults to 1.0e-100, which should be degenerate with ordinary least squares regression. For now, the parameter is applied to all features.
aicc_feature_factors (dict) – Map of phase name to feature to a multiplication factor for the AICc’s parameter penalty.
features (dict) – Maps “property” to a list of features for the linear model. These will be transformed from “GM” coefficients e.g., {“CPM_FORM”: (v.T*sympy.log(v.T), v.T**2, v.T**-1, v.T**3)} (Default value = None)
- Returns
{feature: estimated_value}
- Return type
dict
-
espei.paramselect.
fit_ternary_interactions
(dbf, phase_name, symmetry, endmembers, datasets, ridge_alpha=None, aicc_phase_penalty=None)¶ Fit ternary interactions for a database in place
- Parameters
dbf (Database) – pycalphad Database to add parameters to
phase_name (str) – Name of the phase to fit
symmetry (list) – List of symmetric sublattices, e.g. [[0, 1, 2], [3, 4]]
endmembers (list) – List of endmember tuples, e.g. [(‘CU’, ‘MG’)]
datasets (PickleableTinyDB) – TinyDB database of datasets
ridge_alpha (float) – Value of the $alpha$ hyperparameter used in ridge regression. Defaults to 1.0e-100, which should be degenerate with ordinary least squares regression. For now, the parameter is applied to all features.
- Returns
Modified the Database in place
- Return type
None
-
espei.paramselect.
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
- Return type
pycalphad.Database
-
espei.paramselect.
get_next_symbol
(dbf)¶ Return a string name of the next free symbol to set
- Parameters
dbf (Database) – pycalphad Database. Must have the
varcounter
attribute set to an integer.- Returns
- Return type
str
-
espei.paramselect.
phase_fit
(dbf, phase_name, symmetry, datasets, refdata, ridge_alpha, aicc_penalty=None, aliases=None)¶ Generate an initial CALPHAD model for a given phase and sublattice model.
- Parameters
dbf (Database) – pycalphad Database to add parameters to.
phase_name (str) – Name of the phase.
symmetry ([[int]]) – Sublattice model symmetry.
datasets (PickleableTinyDB) – All datasets to consider for the calculation.
refdata (dict) – Maps tuple(element, phase_name) -> SymPy object defining energy relative to SER
ridge_alpha (float) – Value of the $alpha$ hyperparameter used in ridge regression. Defaults to 1.0e-100, which should be degenerate with ordinary least squares regression. For now, the parameter is applied to all features.
aicc_penalty (dict) – Map of phase name to feature to a multiplication factor for the AICc’s parameter penalty.
aliases (Dict[str, str]) – Mapping of possible aliases to the Database phase names.
- Returns
Modifies the dbf.
- Return type
None
espei.plot module¶
Plotting of input data and calculated database quantities
-
espei.plot.
dataplot
(comps, phases, conds, datasets, tielines=True, ax=None, plot_kwargs=None, tieline_plot_kwargs=None)¶ Plot datapoints corresponding to the components, phases, and conditions.
- Parameters
comps (list) – Names of components to consider in the calculation.
phases ([]) – Names of phases to consider in the calculation.
conds (dict) – Maps StateVariables to values and/or iterables of values.
datasets (PickleableTinyDB) –
tielines (bool) – If True (default), plot the tie-lines from the data
ax (matplotlib.Axes) – Default axes used if not specified.
plot_kwargs (dict) – Additional keyword arguments to pass to the matplotlib plot function for points
tieline_plot_kwargs (dict) – Additional keyword arguments to pass to the matplotlib plot function for tielines
- Returns
A plot of phase equilibria points as a figure
- Return type
matplotlib.Axes
Examples
>>> from espei.datasets import load_datasets, recursive_glob >>> from espei.plot import dataplot >>> datasets = load_datasets(recursive_glob('.', '*.json')) >>> my_phases = ['BCC_A2', 'CUMG2', 'FCC_A1', 'LAVES_C15', 'LIQUID'] >>> my_components = ['CU', 'MG' 'VA'] >>> conditions = {v.P: 101325, v.T: (500, 1000, 10), v.X('MG'): (0, 1, 0.01)} >>> dataplot(my_components, my_phases, conditions, datasets)
-
espei.plot.
eqdataplot
(eq, datasets, ax=None, plot_kwargs=None)¶ Plot datapoints corresponding to the components and phases in the eq Dataset. A convenience function for dataplot.
- Parameters
eq (xarray.Dataset) – Result of equilibrium calculation.
datasets (PickleableTinyDB) – Database of phase equilibria datasets
ax (matplotlib.Axes) – Default axes used if not specified.
plot_kwargs (dict) – Keyword arguments to pass to dataplot
- Returns
- Return type
A plot of phase equilibria points as a figure
Examples
>>> from pycalphad import equilibrium, Database, variables as v >>> from pycalphad.plot.eqplot import eqplot >>> from espei.datasets import load_datasets, recursive_glob >>> datasets = load_datasets(recursive_glob('.', '*.json')) >>> dbf = Database('my_databases.tdb') >>> my_phases = list(dbf.phases.keys()) >>> eq = equilibrium(dbf, ['CU', 'MG', 'VA'], my_phases, {v.P: 101325, v.T: (500, 1000, 10), v.X('MG'): (0, 1, 0.01)}) >>> ax = eqplot(eq) >>> ax = eqdataplot(eq, datasets, ax=ax)
-
espei.plot.
multiplot
(dbf, comps, phases, conds, datasets, eq_kwargs=None, plot_kwargs=None, data_kwargs=None)¶ Plot a phase diagram with datapoints described by datasets. This is a wrapper around pycalphad.equilibrium, pycalphad’s eqplot, and dataplot.
- Parameters
dbf (Database) – pycalphad thermodynamic database containing the relevant parameters.
comps (list) – Names of components to consider in the calculation.
phases (list) – Names of phases to consider in the calculation.
conds (dict) – Maps StateVariables to values and/or iterables of values.
datasets (PickleableTinyDB) – Database of phase equilibria datasets
eq_kwargs (dict) – Keyword arguments passed to pycalphad equilibrium()
plot_kwargs (dict) – Keyword arguments passed to pycalphad eqplot()
data_kwargs (dict) – Keyword arguments passed to dataplot()
- Returns
- Return type
A phase diagram with phase equilibria data as a figure
Examples
>>> from pycalphad import Database, variables as v >>> from pycalphad.plot.eqplot import eqplot >>> from espei.datasets import load_datasets, recursive_glob >>> datasets = load_datasets(recursive_glob('.', '*.json')) >>> dbf = Database('my_databases.tdb') >>> my_phases = list(dbf.phases.keys()) >>> multiplot(dbf, ['CU', 'MG', 'VA'], my_phases, {v.P: 101325, v.T: 1000, v.X('MG'): (0, 1, 0.01)}, datasets)
-
espei.plot.
plot_endmember
(dbf, comps, phase_name, configuration, output, datasets=None, symmetry=None, x='T', ax=None, plot_kwargs=None, dataplot_kwargs=None)¶ Return one set of plotted Axes with data compared to calculated parameters
- Parameters
dbf (Database) – pycalphad thermodynamic database containing the relevant parameters.
comps (Sequence[str]) – Names of components to consider in the calculation.
phase_name (str) – Name of the considered phase phase
configuration (Tuple[Tuple[str]]) – ESPEI-style configuration
output (str) – Model property to plot on the y-axis e.g.
'HM_MIX'
, or'SM_MIX'
. Must be a'_MIX'
property.datasets (tinydb.TinyDB) –
symmetry (list) – List of lists containing indices of symmetric sublattices e.g. [[0, 1], [2, 3]]
ax (plt.Axes) – Default axes used if not specified.
plot_kwargs (Optional[Dict[str, Any]]) – Keyword arguments to
ax.plot
for the predicted data.dataplot_kwargs (Optional[Dict[str, Any]]) – Keyword arguments to
ax.plot
the observed data.
- Returns
- Return type
plt.Axes
-
espei.plot.
plot_interaction
(dbf, comps, phase_name, configuration, output, datasets=None, symmetry=None, ax=None, plot_kwargs=None, dataplot_kwargs=None)¶ Return one set of plotted Axes with data compared to calculated parameters
- Parameters
dbf (Database) – pycalphad thermodynamic database containing the relevant parameters.
comps (Sequence[str]) – Names of components to consider in the calculation.
phase_name (str) – Name of the considered phase phase
configuration (Tuple[Tuple[str]]) – ESPEI-style configuration
output (str) – Model property to plot on the y-axis e.g.
'HM_MIX'
, or'SM_MIX'
. Must be a'_MIX'
property.datasets (tinydb.TinyDB) –
symmetry (list) – List of lists containing indices of symmetric sublattices e.g. [[0, 1], [2, 3]]
ax (plt.Axes) – Default axes used if not specified.
plot_kwargs (Optional[Dict[str, Any]]) – Keyword arguments to
ax.plot
for the predicted data.dataplot_kwargs (Optional[Dict[str, Any]]) – Keyword arguments to
ax.plot
the observed data.
- Returns
- Return type
plt.Axes
-
espei.plot.
plot_parameters
(dbf, comps, phase_name, configuration, symmetry, datasets=None, fig=None, require_data=True)¶ Plot parameters of interest compared with data in subplots of a single figure
- Parameters
dbf (Database) – pycalphad thermodynamic database containing the relevant parameters.
comps (list) – Names of components to consider in the calculation.
phase_name (str) – Name of the considered phase phase
configuration (tuple) – Sublattice configuration to plot, such as (‘CU’, ‘CU’) or ((‘CU’, ‘MG’), ‘CU’)
symmetry (list) – List of lists containing indices of symmetric sublattices e.g. [[0, 1], [2, 3]]
datasets (PickleableTinyDB) – ESPEI datasets to compare against. If None, nothing is plotted.
fig (matplotlib.Figure) – Figure to create with axes as subplots.
require_data (bool) – If True, plot parameters that have data corresponding data. Defaults to True. Will raise an error for non-interaction configurations.
- Returns
- Return type
None
Examples
>>> # plot the LAVES_C15 (Cu)(Mg) endmember >>> plot_parameters(dbf, ['CU', 'MG'], 'LAVES_C15', ('CU', 'MG'), symmetry=None, datasets=datasets) >>> # plot the mixing interaction in the first sublattice >>> plot_parameters(dbf, ['CU', 'MG'], 'LAVES_C15', (('CU', 'MG'), 'MG'), symmetry=None, datasets=datasets)
espei.priors module¶
Classes and functions for retrieving statistical priors for given parameters.
-
class
espei.priors.
DistributionParameter
(parameter, param_type='absolute')¶ Bases:
object
Handle generating absolute, scaling, shifting parameters.
Examples
>>> dp = DistributionParameter(5.0, 'absolute') # always get back 5 >>> dp.value(1.0) == 5.0 True >>> dp = DistributionParameter(-2.0, 'relative') # multiply by -2 >>> dp.value(2.0) == -4.0 True >>> dp = DistributionParameter(-1.0, 'shift_absolute') # subtract 1 >>> dp.value(2.0) == 1.0 True >>> dp = DistributionParameter(-0.5, 'shift_relative') # subtract 1/2 value >>> dp.value(2.0) == 1.0 True
-
SUPPORTED_TYPES
= ('absolute', 'relative', 'shift_absolute', 'shift_relative', 'identity')¶
-
value
(p)¶ Return the distribution parameter value modified by the parameter and type.
- Parameters
p (float) – Input parameter to modify.
- Returns
- Return type
float
-
-
class
espei.priors.
PriorSpec
(name, **parameters)¶ Bases:
object
Specification template for instantiating priors.
-
SUPPORTED_PRIORS
= ('normal', 'uniform', 'triangular', 'zero')¶
-
get_prior
(value)¶ Instantiate a prior as described in the spec
Examples
>>> import numpy as np >>> from espei.priors import PriorSpec >>> tri_spec = {'name': 'triangular', 'loc_shift_relative': -0.5, 'scale_shift_relative': 0.5, 'c': 0.5} >>> np.isneginf(PriorSpec(**tri_spec).get_prior(10).logpdf(5.1)) False >>> np.isneginf(PriorSpec(**tri_spec).get_prior(10).logpdf(4.9)) True
-
-
espei.priors.
build_prior_specs
(prior_spec, parameters)¶ Get priors from given parameters
- Parameters
prior_spec (PriorSpec or dict) – Either a prior spec dict (to instantiate), a PriorSpec, or a list of either. If a list is passed, it must correspond to the parameters.
parameters (list) – List of parameters that the priors will be instantiated by
- Returns
- Return type
Examples
>>> s_norm = {'name': 'normal', 'scale_relative': 0.1, 'loc_identity': 1.0} >>> len(build_prior_specs(s_norm, [10, 100])) == 2 True >>> s_tri = {'name': 'triangular', 'loc_shift_relative': -0.5, 'scale_shift_relative': 0.5, 'c': 0.5} >>> from espei.priors import PriorSpec >>> len(build_prior_specs([s_norm, PriorSpec(**s_tri)], [10, 100])) == 2 True
-
class
espei.priors.
rv_zero
(*args, **kwargs)¶ Bases:
object
A simple class that mimics the scipy.stats.rv_continuous object’s logpdf method, always returning zero.
This class mainly exists for backwards compatibility where no prior is specified.
Examples
>>> import numpy as np >>> rv = rv_zero() >>> np.isclose(rv.logpdf(-np.inf), 0.0) True >>> np.isclose(rv.logpdf(1.0), 0.0) True >>> np.isclose(rv.logpdf(0.0), 0.0) True
-
logpdf
(*args, **kwargs)¶
-
espei.refdata module¶
The refdata module contains pure-element reference state data.
-
espei.refdata.
find_and_insert_user_refstate
(entry_point_plugin_name='espei.reference_states', namespace={'And': And, 'INSERTED_USER_REFERENCE_STATES': [], 'OrderedDict': <class 'collections.OrderedDict'>, 'Piecewise': Piecewise, 'SGTE91': {('AG', 'BCC_A2'): Piecewise((-1.05*T + GHSERAG + 3400, (T >= 298.15) & (T < 3000.0)), (0, True)), ('AG', 'CUB_A13'): Piecewise((-1.8826*T + GHSERAG + 3765.6, (T >= 298.15) & (T < 3000.0)), (0, True)), ('AG', 'FCC_A1'): Piecewise((GHSERAG, (T >= 298.15) & (T < 3000.0)), (0, True)), ('AG', 'HCP_A3'): Piecewise((0.3*T + GHSERAG + 300, (T >= 298.15) & (T < 3000.0)), (0, True)), ('AG', 'LIQUID'): Piecewise((-1.033905e-20*T**7 - 8.89102*T + GHSERAG + 11025.076, (T >= 298.15) & (T < 1234.93)), (-33.472*T*log(T) + 180.964656*T - 3587.111, (T >= 1234.93) & (T < 3000.0)), (0, True)), ('AL', 'BCC_A2'): Piecewise((-4.813*T + GHSERAL + 10083, (T >= 298.15) & (T < 2900.0)), (0, True)), ('AL', 'BCT_A5'): Piecewise((-4.813*T + GHSERAL + 10083, (T >= 298.15) & (T < 2900.0)), (0, True)), ('AL', 'CBCC_A12'): Piecewise((-4.813*T + GHSERAL + 10083.4, (T >= 298.15) & (T < 2900.0)), (0, True)), ('AL', 'CUB_A13'): Piecewise((-4.8116*T + GHSERAL + 10920.44, (T >= 298.15) & (T < 2900.0)), (0, True)), ('AL', 'DIAMOND_A4'): Piecewise((30*T + GHSERAL, (T >= 298.15) & (T < 2900.0)), (0, True)), ('AL', 'FCC_A1'): Piecewise((GHSERAL, (T >= 298.15) & (T < 2900.0)), (0, True)), ('AL', 'HCP_A3'): Piecewise((-1.8*T + GHSERAL + 5481, (T >= 298.15) & (T < 2900.0)), (0, True)), ('AL', 'LIQUID'): Piecewise((7.9337e-20*T**7 - 11.841867*T + GHSERAL + 11005.029, (T >= 298.15) & (T < 700.0)), (7.9337e-20*T**7 - 11.841867*T + GHSERAL + 11005.03, (T >= 700.0) & (T < 933.47)), (-31.748192*T*log(T) + 177.430178*T - 795.996, (T >= 933.47) & (T < 2900.0)), (0, True)), ('AM', 'BCC_A2'): Piecewise((5.0e-12*T**3 + 5.0e-8*T**2 - 4.531331*T + GHSERAM + 5973.805, (T >= 298.15) & (T < 999.0)), (2.291117e-6*T**3 - 0.0190671*T**2 - 15.8832*T*log(T) + 63.93115*T - 7800.332 + 2287195/T, (T >= 999.0) & (T < 1339.0)), (-39.748*T*log(T) + 219.600832*T - 13153.887, (T >= 1339.0) & (T < 1449.0)), (1.801717e-6*T**3 - 0.02736485*T**2 + 33.413*T*log(T) - 326.394464*T + 70352.138 - 17379450/T, (T >= 1449.0) & (T < 2183.6)), (-3.740241*T + GHSERAM + 4777.694, (T >= 2183.6) & (T < 3000.0)), (0, True)), ('AM', 'DHCP'): Piecewise((GHSERAM, (T >= 298.15) & (T < 3000.0)), (0, True)), ('AM', 'FCC_A1'): Piecewise((-6.64773e-7*T**3 - 0.00294694*T**2 - 23.1377*T*log(T) + 99.204329*T - 5224.899 - 18507/T, (T >= 298.15) & (T < 1018.0)), (-3.75233e-7*T**3 - 0.005418*T**2 - 19.4406*T*log(T) + 73.800069*T - 2935.853 - 260435/T, (T >= 1018.0) & (T < 1548.7)), (0.246538*T + GHSERAM - 476.655, (T >= 1548.7) & (T < 3000.0)), (0, True)), ('AM', 'LIQUID'): Piecewise((-14.1205*T + GHSERAM + 19910.7, (T >= 298.15) & (T < 3000.0)), (0, True)), ('AS', 'BCC_A2'): Piecewise((-16.1*T + GHSERAS + 24874, (T >= 298.15) & (T < 1200.0)), (0, True)), ('AS', 'FCC_A1'): Piecewise((-14.74*T + GHSERAS + 24874, (T >= 298.15) & (T < 1200.0)), (0, True)), ('AS', 'HCP_A3'): Piecewise((-14*T + GHSERAS + 24874, (T >= 298.15) & (T < 1200.0)), (0, True)), ('AS', 'LIQUID'): Piecewise((-22.424679*T + GHSERAS + 24442.9, (T >= 298.15) & (T < 1200.0)), (0, True)), ('AS', 'RHOMBOHEDRAL_A7'): Piecewise((GHSERAS, (T >= 298.15) & (T < 1200.0)), (0, True)), ('AU', 'BCC_A2'): Piecewise((-1.1*T + GHSERAU + 4250, (T >= 298.15) & (T < 3200)), (0, True)), ('AU', 'FCC_A1'): Piecewise((GHSERAU, (T >= 298.15) & (T < 3200.0)), (0, True)), ('AU', 'HCP_A3'): Piecewise((1.6*T + GHSERAU + 240.75, (T >= 298.15) & (T < 3200.0)), (0, True)), ('AU', 'LIQUID'): Piecewise((-9.385866*T + GHSERAU + 12552, (T >= 298.15) & (T < 3200.0)), (0, True)), ('B', 'BETA_RHOMBO_B'): Piecewise((GHSERBB, (T >= 298.15) & (T < 6000.0)), (0, True)), ('B', 'DIAMOND_A4'): Piecewise((GHSERBB, (T >= 298.15) & (T < 6000.0)), (0, True)), ('B', 'FCC_A1'): Piecewise((-12.217*T + GHSERBB + 43514, (T >= 298.15) & (T < 6000.0)), (0, True)), ('B', 'GRAPHITE'): Piecewise((GHSERBB + 5000, (T >= 298.15) & (T < 6000.0)), (0, True)), ('B', 'HCP_A3'): Piecewise((-9.706*T + GHSERBB + 50208, (T >= 298.15) & (T < 6000.0)), (0, True)), ('B', 'LIQUID'): Piecewise((-20.268025*T + GHSERBB + 48458.559, (T >= 298.15) & (T < 500.0)), (5.07347e-7*T**3 - 0.007095669*T**2 - 14.9827763*T*log(T) + 82.101722*T + 41119.703 + 335484/T, (T >= 500.0) & (T < 2348.0)), (-31.4*T*log(T) + 200.94731*T + 28842.012, (T >= 2348.0) & (T < 3000.0)), (-21.448954*T + GHSERBB + 50372.665, (T >= 3000.0) & (T < 6000.0)), (0, True)), ('BA', 'BCC_A2'): Piecewise((GHSERBA, (T >= 298.15) & (T < 4000.0)), (0, True)), ('BA', 'FCC_A1'): Piecewise((0.6*T + GHSERBA + 1800, (T >= 298.15) & (T < 4000.0)), (0, True)), ('BA', 'HCP_A3'): Piecewise((1.3*T + GHSERBA + 2000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('BA', 'LIQUID'): Piecewise((9.91223e-7*T**3 - 0.002346416*T**2 - 43.4961089*T*log(T) + 229.540143*T - 9738.988 + 723016/T, (T >= 298.15) & (T < 1000.0)), (2.7e-11*T**3 + 0.002154*T**2 - 45.103*T*log(T) + 235.49642*T - 7381.093 - 365/T, (T >= 1000.0) & (T < 2995.0)), (-4.568042*T + GHSERBA + 3856.393, (T >= 2995.0) & (T < 4000.0)), (0, True)), ('BE', 'BCC_A2'): Piecewise((9.61427e-7*T**3 - 0.008672487*T**2 - 17.1727841*T*log(T) + 109.411712*T - 1076.057 + 242309/T, (T >= 298.15) & (T < 1527.0)), (-30*T*log(T) + 196.411689*T - 6970.378, (T >= 1527.0) & (T < 1560.0)), (-5.9331e-8*T**3 - 0.000103629*T**2 - 27.7823769*T*log(T) + 178.131722*T - 2609.973 - 1250847/T, (T >= 1560.0) & (T < 3000.0)), (0, True)), ('BE', 'FCC_A1'): Piecewise((-1.085*T + GHSERBE + 6349, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BE', 'HCP_A3'): Piecewise((GHSERBE, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BE', 'LIQUID'): Piecewise((4.15958e-7*T**3 - 0.004821347*T**2 - 20.0497038*T*log(T) + 120.362788*T + 7511.838 + 281044/T, (T >= 298.15) & (T < 1560.0)), (-1.117e-9*T**3 - 0.0010572*T**2 - 25.486*T*log(T) + 156.961141*T + 5364.713 + 15920/T, (T >= 1560.0) & (T < 3000.0)), (0, True)), ('BI', 'BCC_A2'): Piecewise((-13.9*T + GHSERBI + 11297, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BI', 'BCT_A5'): Piecewise((GHSERBI + 4184.07, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BI', 'FCC_A1'): Piecewise((-12.5*T + GHSERBI + 9900, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BI', 'HCP_A3'): Piecewise((-11.8*T + GHSERBI + 9900, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BI', 'LIQUID'): Piecewise((-5.9549e-19*T**7 - 20.636509*T + GHSERBI + 11246.066, (T >= 298.15) & (T < 544.55)), (-20.810418*T + GHSERBI + 11336.26 - 1.66145e+25/T**9, (T >= 544.55) & (T < 800.0)), (-20.810418*T + GHSERBI + 11336.259 - 1.66145e+25/T**9, (T >= 800.0) & (T < 1200.0)), (-27.196*T*log(T) + 103.961021*T + 3754.947, (T >= 1200.0) & (T < 3000.0)), (0, True)), ('BI', 'RHOMBOHEDRAL_A7'): Piecewise((GHSERBI, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BI', 'TETRAGONAL_A6'): Piecewise((GHSERBI + 4184.07, (T >= 298.15) & (T < 3000.0)), (0, True)), ('BI', 'TET_ALPHA1'): Piecewise((GHSERBI + 4234, (T >= 298.15) & (T < 3000.0)), (0, True)), ('C', 'DIAMOND_A4'): Piecewise((-0.0004723*T**2 - 24.31*T*log(T) + 175.61*T - 16359.441 + 2698000/T - 261000000.0/T**2 + 11100000000.0/T**3, (T >= 298.15) & (T < 6000.0)), (0, True)), ('C', 'GRAPHITE'): Piecewise((GHSERCC, (T >= 298.15) & (T < 6000.0)), (0, True)), ('C', 'LIQUID'): Piecewise((-24.63*T + GHSERCC + 117369, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CA', 'BCC_A2'): Piecewise((-4.500217e-6*T**3 + 0.0072326*T**2 - 28.2541*T*log(T) + 142.970155*T - 7020.852 + 60578/T, (T >= 298.15) & (T < 716.0)), (-0.0161921*T**2 - 6.276*T*log(T) + 1.999694*T + 1640.475 - 523000/T, (T >= 716.0) & (T < 1115.0)), (-1.704079e-6*T**3 + 0.032543127*T**2 - 143.872698*T*log(T) + 1023.54905*T - 142331.096 + 25353771/T, (T >= 1115.0) & (T < 3000.0)), (0, True)), ('CA', 'FCC_A1'): Piecewise((GHSERCA, (T >= 298.15) & (T < 3000.0)), (0, True)), ('CA', 'HCP_A3'): Piecewise((0.7*T + GHSERCA + 500, (T >= 298.15) & (T < 3000.0)), (0, True)), ('CA', 'LIQUID'): Piecewise((-10.310466*T + GHSERCA + 10799.908, (T >= 298.15) & (T < 500.0)), (3.338303e-6*T**3 - 0.02266537*T**2 - 8.9874787*T*log(T) + 18.2979*T + 7838.856 - 230193/T, (T >= 500.0) & (T < 1115.0)), (-35*T*log(T) + 188.9223*T - 2654.938, (T >= 1115.0) & (T < 3000.0)), (0, True)), ('CD', 'FCC_A1'): Piecewise((-0.92*T + GHSERCD + 892.3, (T >= 298.15) & (T < 1600.0)), (0, True)), ('CD', 'HCP_A3'): Piecewise((GHSERCD, (T >= 298.15) & (T < 1600.0)), (0, True)), ('CD', 'LIQUID'): Piecewise((-10.296916*T + GHSERCD + 6128.444, (T >= 298.15) & (T < 400.0)), (2.8899781e-5*T**3 - 0.115159917*T**2 + 53.1313898*T*log(T) - 371.046869*T + 21716.884 - 1271815/T, (T >= 400.0) & (T < 594.22)), (-29.7064*T*log(T) + 138.251107*T - 3252.303, (T >= 594.22) & (T < 1500.0)), (-9.954373*T + GHSERCD + 5775.186, (T >= 1500.0) & (T < 1600.0)), (0, True)), ('CD', 'TETRAGONAL_A6'): Piecewise((-0.92*T + GHSERCD + 892.3, (T >= 298.15) & (T < 1600.0)), (0, True)), ('CE', 'BCC_A2'): Piecewise((4.784299e-6*T**3 - 0.029098402*T**2 - 7.7305867*T*log(T) - 5.21501*T - 1354.69 - 196303/T, (T >= 298.15) & (T < 1000.0)), (-37.6142*T*log(T) + 187.449688*T - 12101.106, (T >= 1000.0) & (T < 1072.0)), (2.348e-9*T**3 - 5.7145e-5*T**2 - 37.4627992*T*log(T) + 186.333811*T - 11950.375 - 25897/T, (T >= 1072.0) & (T < 4000.0)), (0, True)), ('CE', 'DHCP'): Piecewise((0.56886*T + GHSERCE - 190, (T >= 298.15) & (T < 4000.0)), (0, True)), ('CE', 'FCC_A1'): Piecewise((GHSERCE, (T >= 298.15) & (T < 4000.0)), (0, True)), ('CE', 'HCP_A3'): Piecewise((GHSERCE + 50000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('CE', 'LIQUID'): Piecewise((4.827734e-6*T**3 - 0.02936407*T**2 - 7.5383948*T*log(T) - 11.423898*T + 4117.865 - 198834/T, (T >= 298.15) & (T < 1000.0)), (-37.6978*T*log(T) + 183.023193*T - 6730.605, (T >= 1000.0) & (T < 2000.0)), (-7.346999*T + GHSERCE + 7468.034, (T >= 2000.0) & (T < 4000.0)), (0, True)), ('CO', 'BCC_A2'): Piecewise((-0.7138*T + GHSERCO + 2938, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CO', 'CBCC_A12'): Piecewise((GHSERCO + 4155, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CO', 'CUB_A13'): Piecewise((GHSERCO + 3155, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CO', 'FCC_A1'): Piecewise((-0.615248*T + GHSERCO + 427.591, (T >= 298.15) & (T < 1768.0)), (-0.615253*T + GHSERCO + 427.591, (T >= 1768.0) & (T < 6000.0)), (0, True)), ('CO', 'HCP_A3'): Piecewise((GHSERCO, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CO', 'LIQUID'): Piecewise((-2.19801e-21*T**7 - 8.931932*T + GHSERCO + 15085.037, (T >= 298.15) & (T < 1768.0)), (-40.5*T*log(T) + 243.599944*T - 846.61, (T >= 1768.0) & (T < 6000.0)), (0, True)), ('CR', 'BCC_A2'): Piecewise((GHSERCR, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CR', 'CBCC_A12'): Piecewise((2.7196*T + GHSERCR + 11087, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CR', 'CUB_A13'): Piecewise((0.6276*T + GHSERCR + 15899, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CR', 'FCC_A1'): Piecewise((0.163*T + GHSERCR + 7284, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CR', 'HCP_A3'): Piecewise((GHSERCR + 4438, (T >= 298.15) & (T < 6000.0)), (0, True)), ('CR', 'LIQUID'): Piecewise((2.37615e-21*T**7 - 11.420225*T + GHSERCR + 24339.955, (T >= 298.15) & (T < 2180.0)), (-50*T*log(T) + 335.616316*T - 16459.984, (T >= 2180.0) & (T < 6000.0)), (0, True)), ('CS', 'BCC_A2'): Piecewise((GHSERCS, (T >= 200.0) & (T < 2000.0)), (0, True)), ('CS', 'FCC_A1'): Piecewise((1.3*T + GHSERCS + 500, (T >= 200.0) & (T < 2000.0)), (0, True)), ('CS', 'HCP_A3'): Piecewise((2*T + GHSERCS + 500, (T >= 200.0) & (T < 2000.0)), (0, True)), ('CS', 'LIQUID'): Piecewise((-3.56867e-18*T**7 - 6.931035*T + GHSERCS + 2091.141, (T >= 200.0) & (T < 301.59)), (-6.961111*T + GHSERCS + 2099.779 - 7.8016e+21/T**9, (T >= 301.59) & (T < 2000.0)), (0, True)), ('CU', 'BCC_A2'): Piecewise((-1.255*T + GHSERCU + 4017, (T >= 298.15) & (T < 3200.0)), (0, True)), ('CU', 'FCC_A1'): Piecewise((GHSERCU, (T >= 298.15) & (T < 3200.0)), (0, True)), ('CU', 'HCP_A3'): Piecewise((0.2*T + GHSERCU + 600, (T >= 298.15) & (T < 3200.0)), (0, True)), ('CU', 'LIQUID'): Piecewise((-5.8489e-21*T**7 - 9.511904*T + GHSERCU + 12964.735, (T >= 298.15) & (T < 1357.77)), (-31.38*T*log(T) + 173.881484*T - 46.545, (T >= 1357.77) & (T < 3200.0)), (0, True)), ('DY', 'BCC_A2'): Piecewise((-0.566616181*T + GHSERDY + 1508.1802, (T >= 100.0) & (T < 1000.0)), (2.04076075e-5*T**3 - 0.224042148*T**2 + 391.515418*T*log(T) - 2868.04585*T + 327500.062 - 48652656.5/T, (T >= 1000.0) & (T < 1654.15)), (-50.208*T*log(T) + 291.409631*T - 33708.7949, (T >= 1654.15) & (T < 1685.15)), (-7.7437116e-8*T**3 + 0.0015254673*T**2 - 55.2811171*T*log(T) + 330.318068*T - 40775.4966 + 1776589.32/T, (T >= 1685.15) & (T < 3000.0)), (0, True)), ('DY', 'HCP_A3'): Piecewise((GHSERDY, (T >= 100.0) & (T < 3000.0)), (0, True)), ('DY', 'LIQUID'): Piecewise((-7.5443643*T + GHSERDY + 13196.6185, (T >= 100.0) & (T < 1000.0)), (1.76197799e-5*T**3 - 0.196153225*T**2 + 341.302578*T*log(T) - 2519.78614*T + 300126.971 - 43071677.5/T, (T >= 1000.0) & (T < 1685.15)), (-49.9151*T*log(T) + 282.205014*T - 21864.7344, (T >= 1685.15) & (T < 3000.0)), (0, True)), ('ER', 'HCP_A3'): Piecewise((GHSERER, (T >= 298.15) & (T < 3200.0)), (0, True)), ('ER', 'LIQUID'): Piecewise((-10.241846*T + GHSERER + 19382.102, (T >= 298.15) & (T < 500.0)), (1.316517e-6*T**3 - 0.014414687*T**2 - 12.0761776*T*log(T) + 0.355564*T + 17912.678 - 528122/T, (T >= 500.0) & (T < 1802.0)), (-38.702*T*log(T) + 187.623024*T + 747.131, (T >= 1802.0) & (T < 3200.0)), (0, True)), ('EU', 'BCC_A2'): Piecewise((GHSEREU, (T >= 298.15) & (T < 1900.0)), (0, True)), ('EU', 'LIQUID'): Piecewise((-7.175215*T + GHSEREU + 8382.505, (T >= 298.15) & (T < 400.0)), (5.452934e-6*T**3 - 0.036811218*T**2 + 4.3501554*T*log(T) - 103.688201*T + 10972.726 - 646908/T, (T >= 299.15) & (T < 1095.0)), (-38.11624*T*log(T) + 175.517247*T - 6890.641, (T >= 300.15) & (T < 1900.0)), (0, True)), ('FE', 'BCC_A2'): Piecewise((GHSERFE, (T >= 298.15) & (T < 6000.0)), (0, True)), ('FE', 'CBCC_A12'): Piecewise((GHSERFE + 4745, (T >= 298.15) & (T < 6000.0)), (0, True)), ('FE', 'CUB_A13'): Piecewise((GHSERFE + 3745, (T >= 298.15) & (T < 6000.0)), (0, True)), ('FE', 'FCC_A1'): Piecewise((0.00064*T**2 - 1.15*T*log(T) + 8.282*T + GHSERFE - 1462.4, (T >= 298.15) & (T < 1811.0)), (0.94001*T + GHSERFE - 1713.815 + 4.9251e+30/T**9, (T >= 1811.0) & (T < 6000.0)), (0, True)), ('FE', 'HCP_A3'): Piecewise((0.00064*T**2 - 1.15*T*log(T) + 12.591*T + GHSERFE - 3705.78, (T >= 298.15) & (T < 1811.0)), (5.24951*T + GHSERFE - 3957.199 + 4.9251e+30/T**9, (T >= 1811.0) & (T < 6000.0)), (0, True)), ('FE', 'LIQUID'): Piecewise((-3.67516e-21*T**7 - 6.55843*T + GHSERFE + 12040.17, (T >= 298.15) & (T < 1811.0)), (-46*T*log(T) + 291.302*T - 10838.83, (T >= 1811.0) & (T < 6000.0)), (0, True)), ('GA', 'BCC_A2'): Piecewise((-11.7*T + GHSERGA + 4500, (T >= 200.0) & (T < 4000.0)), (0, True)), ('GA', 'BCT_A5'): Piecewise((-9.8*T + GHSERGA + 3846, (T >= 200.0) & (T < 4000.0)), (0, True)), ('GA', 'FCC_A1'): Piecewise((-10.2*T + GHSERGA + 3800, (T >= 200.0) & (T < 4000.0)), (0, True)), ('GA', 'HCP_A3'): Piecewise((-9.5*T + GHSERGA + 4500, (T >= 200.0) & (T < 4000.0)), (0, True)), ('GA', 'LIQUID'): Piecewise((-7.0171e-17*T**7 - 18.073995*T + GHSERGA + 5491.298, (T >= 200.0) & (T < 302.91)), (-18.681147*T + GHSERGA + 5666.455 - 1.64547e+23/T**9, (T >= 302.91) & (T < 4000.0)), (0, True)), ('GA', 'ORTHORHOMBIC_GA'): Piecewise((GHSERGA, (T >= 200.0) & (T < 4000.0)), (0, True)), ('GA', 'TETRAGONAL_A6'): Piecewise((-10*T + GHSERGA + 3500, (T >= 200.0) & (T < 4000.0)), (0, True)), ('GD', 'BCC_A2'): Piecewise((1.00000001e-7*T*log(T) - 2.11184585*T + GHSERGD + 3233.80866, (T >= 200.0) & (T < 1000.0)), (1.17915728e-5*T**3 - 0.119550229*T**2 + 180.097094*T*log(T) - 1349.58873*T + 152792.743 - 22038836/T, (T >= 1000.0) & (T < 1508.15)), (-38.960425*T*log(T) + 202.222057*T - 15783.7618, (T >= 1508.15) & (T < 1586.15)), (-3.77570269e-8*T**3 + 0.000858222759*T**2 - 41.904333*T*log(T) + 224.817909*T - 19850.5562 + 995428.573/T, (T >= 1586.15) & (T < 3600.0)), (0, True)), ('GD', 'HCP_A3'): Piecewise((GHSERGD, (T >= 200.0) & (T < 3600.0)), (0, True)), ('GD', 'LIQUID'): Piecewise((-8.32179974*T + GHSERGD + 13060.0262, (T >= 200.0) & (T < 1000.0)), (1.06945505e-5*T**3 - 0.108247135*T**2 + 159.352082*T*log(T) - 1208.70685*T + 146262.037 - 19678357/T, (T >= 1000.0) & (T < 1508.15)), (-38.5075*T*log(T) + 192.336215*T - 5397.314, (T >= 1508.15) & (T < 3600.0)), (0, True)), ('GE', 'BCC_A2'): Piecewise((-23.5*T + GHSERGE + 34100, (T >= 298.15) & (T < 3200.0)), (0, True)), ('GE', 'DIAMOND_A4'): Piecewise((GHSERGE, (T >= 298.15) & (T < 3200.0)), (0, True)), ('GE', 'FCC_A1'): Piecewise((-22.3*T + GHSERGE + 36000, (T >= 298.15) & (T < 3200.0)), (0, True)), ('GE', 'HCP_A3'): Piecewise((-21.5*T + GHSERGE + 35000, (T >= 298.15) & (T < 3200.0)), (0, True)), ('GE', 'LIQUID'): Piecewise((8.56632e-21*T**7 - 30.687043*T + GHSERGE + 37141.49, (T >= 298.15) & (T < 900.0)), (8.56632e-21*T**7 - 30.687044*T + GHSERGE + 37141.489, (T >= 900.0) & (T < 1211.4)), (-27.6144*T*log(T) + 126.324186*T + 27243.473, (T >= 1211.4) & (T < 3200.0)), (0, True)), ('HF', 'BCC_A2'): Piecewise((-1.446e-10*T**4 + 8.71923e-7*T**3 - 0.004206605*T**2 - 22.8995*T*log(T) + 103.836026*T + 5370.703 - 22590/T, (T >= 298.15) & (T < 2506.0)), (1.3427829e-5*T**3 - 0.286857065*T**2 + 1087.61412*T*log(T) - 8624.20573*T + 1912456.77 - 610085091.0/T, (T >= 2506.0) & (T < 3000.0)), (0, True)), ('HF', 'FCC_A1'): Piecewise((-2.2*T + GHSERHF + 10000, (T >= 298.15) & (T < 3000.0)), (0, True)), ('HF', 'HCP_A3'): Piecewise((GHSERHF, (T >= 298.15) & (T < 3000.0)), (0, True)), ('HF', 'LIQUID'): Piecewise((-10.953093*T + GHSERHF + 27402.256, (T >= 298.15) & (T < 1000.0)), (1.376466e-6*T**3 - 0.021262021*T**2 + 12.116812*T*log(T) - 149.91739*T + 49731.499 - 4449699/T, (T >= 1000.0) & (T < 2506.0)), (-44*T*log(T) + 265.470523*T - 4247.217, (T >= 2506.0) & (T < 3000.0)), (0, True)), ('HG', 'LIQUID'): Piecewise((GHSERHG, (T >= 200.0) & (T < 2000.0)), (0, True)), ('HG', 'RHOMBO_A10'): Piecewise((-2.4555667e-5*T**3 + 0.01699705*T**2 - 28.847*T*log(T) + 123.274598*T - 10668.401 + 13330/T, (T >= 200.0) & (T < 234.32)), (-2.28298e-7*T**3 + 0.00107555*T**2 - 30.2091*T*log(T) + 135.928158*T - 11425.394 + 35545/T, (T >= 234.32) & (T < 2000.0)), (0, True)), ('HO', 'BCC_A2'): Piecewise((-2.060316*T + GHSERHO + 3731.229, (T >= 298.15) & (T < 600.0)), (-2.060316*T + GHSERHO + 3731.23, (T >= 600.0) & (T < 900.0)), (-2.060317*T + GHSERHO + 3731.229, (T >= 900.0) & (T < 1000.0)), (1.2168911e-5*T**3 - 0.13516576*T**2 + 218.937249*T*log(T) - 1635.74067*T + 185512.056 - 26729747/T, (T >= 1000.0) & (T < 1703.0)), (-48.116*T*log(T) + 272.946988*T - 28867.901, (T >= 1703.0) & (T < 1745.0)), (-1.287517e-6*T**3 + 0.025544089*T**2 - 134.793064*T*log(T) + 939.764197*T - 152754.148 + 32050889/T, (T >= 1745.0) & (T < 3000.0)), (0, True)), ('HO', 'HCP_A3'): Piecewise((GHSERHO, (T >= 298.15) & (T < 3000.0)), (0, True)), ('HO', 'LIQUID'): Piecewise((-9.992194*T + GHSERHO + 17262.172, (T >= 298.15) & (T < 1000.0)), (8.008222e-6*T**3 - 0.088196514*T**2 + 127.957778*T*log(T) - 994.683024*T + 124706.283 - 15727191/T, (T >= 1000.0) & (T < 1703.0)), (-43.932*T*log(T) + 230.793918*T - 9809.781, (T >= 1703.0) & (T < 3000.0)), (0, True)), ('IN', 'BCC_A2'): Piecewise((-0.8*T + GHSERIN + 800, (T >= 298.15) & (T < 3800.0)), (0, True)), ('IN', 'FCC_A1'): Piecewise((-0.1988*T + GHSERIN + 123, (T >= 298.15) & (T < 3800.0)), (0, True)), ('IN', 'HCP_A3'): Piecewise((-0.6868*T + GHSERIN + 533, (T >= 298.15) & (T < 3800.0)), (0, True)), ('IN', 'LIQUID'): Piecewise((-5.59058e-20*T**7 - 7.63686*T + GHSERIN + 3282.092, (T >= 298.15) & (T < 429.75)), (-7.640804*T + GHSERIN + 3283.706 - 3.53116e+22/T**9, (T >= 429.75) & (T < 3800.0)), (0, True)), ('IN', 'TETRAGONAL_A6'): Piecewise((GHSERIN, (T >= 298.15) & (T < 3800.0)), (0, True)), ('IN', 'TET_ALPHA1'): Piecewise((-0.16479*T + GHSERIN + 193, (T >= 298.15) & (T < 3800.0)), (0, True)), ('IR', 'BCC_A2'): Piecewise((-6.9*T + GHSERIR + 32000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('IR', 'FCC_A1'): Piecewise((GHSERIR, (T >= 298.15) & (T < 4000.0)), (0, True)), ('IR', 'HCP_A3'): Piecewise((-0.6*T + GHSERIR + 4000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('IR', 'LIQUID'): Piecewise((-6.312059*T + GHSERIR + 23455.244, (T >= 298.15) & (T < 1000.0)), (2.761831e-6*T**3 - 0.04638802*T**2 + 73.9517579*T*log(T) - 587.632815*T + 102217.789 - 13382612/T, (T >= 1000.0) & (T < 2719.0)), (-59.418*T*log(T) + 411.234043*T - 38347.217, (T >= 2719.0) & (T < 4000.0)), (0, True)), ('K', 'BCC_A2'): Piecewise((GHSERKK, (T >= 200.0) & (T < 2200.0)), (0, True)), ('K', 'FCC_A1'): Piecewise((1.3*T + GHSERKK + 50, (T >= 200.0) & (T < 2200.0)), (0, True)), ('K', 'HCP_A3'): Piecewise((2*T + GHSERKK + 50, (T >= 200.0) & (T < 2200.0)), (0, True)), ('K', 'LIQUID'): Piecewise((-9.44e-19*T**7 - 6.886859*T + GHSERKK + 2318.096, (T >= 200.0) & (T < 336.53)), (-6.902217*T + GHSERKK + 2323.019 - 1.19223e+22/T**9, (T >= 336.53) & (T < 2200.0)), (0, True)), ('LA', 'BCC_A2'): Piecewise((-5.25865e-7*T**3 - 0.004045175*T**2 - 21.7919*T*log(T) + 88.072353*T - 3952.161, (T >= 298.15) & (T < 800.0)), (4.9547989e-5*T**3 - 0.387295093*T**2 + 513.440708*T*log(T) - 3565.08252*T + 321682.673 - 36581228/T, (T >= 800.0) & (T < 1134.0)), (-39.5388*T*log(T) + 218.492988*T - 16377.894, (T >= 1134.0) & (T < 1193.0)), (-4.056395e-6*T**3 + 0.053968535*T**2 - 163.413074*T*log(T) + 1123.34397*T - 136609.91 + 21167204/T, (T >= 1193.0) & (T < 2000.0)), (-6.553756*T + GHSERLA + 7402.894, (T >= 2000.0) & (T < 4000.0)), (0, True)), ('LA', 'DHCP'): Piecewise((GHSERLA, (T >= 298.15) & (T < 4000.0)), (0, True)), ('LA', 'FCC_A1'): Piecewise((-5.25865e-7*T**3 - 0.004045175*T**2 - 21.7919*T*log(T) + 89.878761*T - 6109.797, (T >= 298.15) & (T < 1134.0)), (-3.066199e-6*T**3 + 0.042032405*T**2 - 139.346741*T*log(T) + 955.878375*T - 124598.976 + 20994153/T, (T >= 1134.0) & (T < 2000.0)), (-2.846081*T + GHSERLA + 3009.496, (T >= 2000.0) & (T < 4000.0)), (0, True)), ('LA', 'LIQUID'): Piecewise((2.93775e-6*T**3 - 0.020171603*T**2 - 11.0188191*T*log(T) + 18.23012*T + 5332.653 - 133541/T, (T >= 298.15) & (T < 1134.0)), (-34.3088*T*log(T) + 171.018431*T - 3942.004, (T >= 1134.0) & (T < 2000.0)), (-10.37164*T + GHSERLA + 11666.878, (T >= 2000.0) & (T < 4000.0)), (0, True)), ('LI', 'BCC_A2'): Piecewise((GHSERLI, (T >= 200.0) & (T < 3000.0)), (0, True)), ('LI', 'FCC_A1'): Piecewise((1.3*T + GHSERLI - 108, (T >= 200.0) & (T < 3000)), (0, True)), ('LI', 'HCP_A3'): Piecewise((2*T + GHSERLI - 154, (T >= 200.0) & (T < 3000.0)), (0, True)), ('LI', 'LIQUID'): Piecewise((-5.795621*T + GHSERLI + 2700.205, (T >= 200.0) & (T < 250.0)), (6.3955671e-5*T**3 - 0.182426463*T**2 + 61.6104424*T*log(T) - 362.187078*T + 12015.027 - 559968/T, (T >= 250.0) & (T < 453.6)), (-4.38058e-7*T**3 + 0.002633221*T**2 - 31.2283718*T*log(T) + 172.652183*T - 6057.31 - 102387/T, (T >= 453.6) & (T < 500.0)), (-6.626102*T + GHSERLI + 3005.684, (T >= 500.0) & (T < 3000.0)), (0, True)), ('LU', 'HCP_A3'): Piecewise((GHSERLU, (T >= 298.15) & (T < 3700.0)), (0, True)), ('LU', 'LIQUID'): Piecewise((-4.998883*T + GHSERLU + 12772.12, (T >= 298.15) & (T < 600.0)), (2.890636e-6*T**3 - 0.034238743*T**2 + 20.9392663*T*log(T) - 198.378793*T + 30389.863 - 2398650/T, (T >= 600.0) & (T < 1936.0)), (-47.9068*T*log(T) + 292.091104*T - 18994.687, (T >= 1936.0) & (T < 3700.0)), (0, True)), ('MG', 'BCC_A2'): Piecewise((-2.1*T + GHSERMG + 3100, (T >= 298.15) & (T < 3000.0)), (0, True)), ('MG', 'CBCC_A12'): Piecewise((-3.011*T + GHSERMG + 4602.4, (T >= 298.15) & (T < 3000.0)), (0, True)), ('MG', 'CUB_A13'): Piecewise((-3*T + GHSERMG + 5000, (T >= 298.15) & (T < 3000.0)), (0, True)), ('MG', 'FCC_A1'): Piecewise((-0.9*T + GHSERMG + 2600, (T >= 298.15) & (T < 3000.0)), (0, True)), ('MG', 'HCP_A3'): Piecewise((GHSERMG, (T >= 298.15) & (T < 3000.0)), (0, True)), ('MG', 'LIQUID'): Piecewise((-8.0176e-20*T**7 - 8.83693*T + GHSERMG + 8202.243, (T >= 298.15) & (T < 923.0)), (-34.3088*T*log(T) + 195.324057*T - 5439.869, (T >= 923.0) & (T < 3000.0)), (0, True)), ('MN', 'BCC_A2'): Piecewise((-0.00744271*T**2 - 23.7*T*log(T) + 127.85*T - 3235.3 + 60000/T, (T >= 298.15) & (T < 1519.0)), (-4.5605*T + GHSERMN + 5544.58 - 3.91695e+29/T**9, (T >= 1519.0) & (T < 2000.0)), (0, True)), ('MN', 'CBCC_A12'): Piecewise((GHSERMN, (T >= 298.15) & (T < 2000.0)), (0, True)), ('MN', 'CUB_A13'): Piecewise((-0.00583359*T**2 - 24.8785*T*log(T) + 135.995*T - 5800.4 + 70269/T, (T >= 298.15) & (T < 1519.0)), (-0.9715*T + GHSERMN + 442.65 + 2.310723e+30/T**9, (T >= 1519.0) & (T < 2000.0)), (0, True)), ('MN', 'FCC_A1'): Piecewise((-0.006*T**2 - 24.5177*T*log(T) + 131.884*T - 3439.3 + 69600/T, (T >= 298.15) & (T < 1519.0)), (-2.5984*T + GHSERMN + 2663.31 + 2.205113e+30/T**9, (T >= 1519.0) & (T < 2000.0)), (0, True)), ('MN', 'HCP_A3'): Piecewise((-0.006*T**2 - 24.5177*T*log(T) + 133.007*T - 4439.3 + 69600/T, (T >= 298.15) & (T < 1519.0)), (-1.4754*T + GHSERMN + 1663.31 + 2.205113e+30/T**9, (T >= 1519.0) & (T < 2000.0)), (0, True)), ('MN', 'LIQUID'): Piecewise((-4.41929e-21*T**7 - 12.6208*T + GHSERMN + 17859.91, (T >= 298.15) & (T < 1519.0)), (-48*T*log(T) + 299.036*T - 9993.9, (T >= 1519.0) & (T < 2000.0)), (0, True)), ('MO', 'BCC_A2'): Piecewise((GHSERMO, (T >= 298.15) & (T < 5000.0)), (0, True)), ('MO', 'FCC_A1'): Piecewise((0.63*T + GHSERMO + 15200, (T >= 298.15) & (T < 5000.0)), (0, True)), ('MO', 'HCP_A3'): Piecewise((GHSERMO + 11550, (T >= 298.15) & (T < 5000.0)), (0, True)), ('MO', 'LIQUID'): Piecewise((4.24519e-22*T**7 - 14.694912*T + GHSERMO + 41831.347, (T >= 298.15) & (T < 2896.0)), (-42.63829*T*log(T) + 271.6697*T + 3538.963, (T >= 2896.0) & (T < 5000.0)), (0, True)), ('N', 'LIQUID'): Piecewise((59.02*T + GHSERNN + 29950, (T >= 298.15) & (T < 6000.0)), (0, True)), ('N2', 'GAS'): Piecewise((2*GHSERNN, (T >= 298.15) & (T < 6000.0)), (0, True)), ('NA', 'BCC_A2'): Piecewise((GHSERNA, (T >= 200.0) & (T < 2300.0)), (0, True)), ('NA', 'FCC_A1'): Piecewise((1.3*T + GHSERNA - 50, (T >= 200.0) & (T < 2300.0)), (0, True)), ('NA', 'HCP_A3'): Piecewise((2*T + GHSERNA - 104, (T >= 200.0) & (T < 2300.0)), (0, True)), ('NA', 'LIQUID'): Piecewise((-2.76132e-18*T**7 - 6.95218*T + GHSERNA + 2581.02, (T >= 200.0) & (T < 370.87)), (-7.032656*T + GHSERNA + 2609.444 - 1.65071e+23/T**9, (T >= 370.87) & (T < 2300.0)), (0, True)), ('NB', 'BCC_A2'): Piecewise((GHSERNB, (T >= 298.15) & (T < 6000.0)), (0, True)), ('NB', 'FCC_A1'): Piecewise((1.7*T + GHSERNB + 13500, (T >= 298.15) & (T < 6000.0)), (0, True)), ('NB', 'HCP_A3'): Piecewise((2.4*T + GHSERNB + 10000, (T >= 298.15) & (T < 6000.0)), (0, True)), ('NB', 'LIQUID'): Piecewise((-3.06098e-23*T**7 - 10.816418*T + GHSERNB + 29781.555, (T >= 298.15) & (T < 2750.0)), (-41.77*T*log(T) + 260.756148*T - 7499.398, (T >= 2750.0) & (T < 6000.0)), (0, True)), ('ND', 'BCC_A2'): Piecewise((-0.546281*T + GHSERND + 1437.295, (T >= 298.15) & (T < 400.0)), (7.287217e-6*T**3 - 0.050479*T**2 + 14.9956777*T*log(T) - 153.033976*T + 7312.2 - 831810/T, (T >= 400.0) & (T < 1128.0)), (-44.5596*T*log(T) + 239.677322*T - 18030.266, (T >= 1128.0) & (T < 1289.0)), (1.2408421e-5*T**3 - 0.156030778*T**2 + 311.409193*T*log(T) - 2363.9199*T + 334513.017 - 64319604/T, (T >= 1289.0) & (T < 1800.0)), (0, True)), ('ND', 'DHCP'): Piecewise((GHSERND, (T >= 298.15) & (T < 1800.0)), (0, True)), ('ND', 'FCC_A1'): Piecewise((GHSERND + 500, (T >= 298.15) & (T < 1128.0)), (3.00000011e-7*T*log(T) + 9.99999884e-7*T + GHSERND + 500, (T >= 1128.0) & (T < 1799.0)), (GHSERND + 500, (T >= 1799.0) & (T < 1800.0)), (0, True)), ('ND', 'LIQUID'): Piecewise((-1.585076*T + GHSERND + 5051.743, (T >= 298.15) & (T < 300.0)), (6.860782e-6*T**3 - 0.046955463*T**2 + 5.357301*T*log(T) - 86.593963*T + 5350.01 - 374380/T, (T >= 300.0) & (T < 1128.0)), (-48.7854*T*log(T) + 268.625903*T - 16335.232, (T >= 1128.0) & (T < 1799.0)), (-7.631185*T + GHSERND + 9407.099, (T >= 1799.0) & (T < 1800.0)), (0, True)), ('NI', 'BCC_A2'): Piecewise((-3.556*T + GHSERNI + 8715.084, (T >= 298.15) & (T < 3000.0)), (0, True)), ('NI', 'CBCC_A12'): Piecewise((GHSERNI + 3556, (T >= 298.15) & (T < 3000.0)), (0, True)), ('NI', 'CUB_A13'): Piecewise((GHSERNI + 2092, (T >= 298.15) & (T < 3000.0)), (0, True)), ('NI', 'FCC_A1'): Piecewise((GHSERNI, (T >= 298.15) & (T < 3000.0)), (0, True)), ('NI', 'HCP_A3'): Piecewise((1.255*T + GHSERNI + 1046, (T >= 298.15) & (T < 3000.0)), (0, True)), ('NI', 'LIQUID'): Piecewise((-3.82318e-21*T**7 - 9.397*T + GHSERNI + 16414.686, (T >= 298.15) & (T < 1728.0)), (-43.1*T*log(T) + 268.598*T - 9549.775, (T >= 1728.0) & (T < 3000.0)), (0, True)), ('NP', 'BCC_A2'): Piecewise((5.14743e-7*T**3 - 0.00251865*T**2 - 35.177*T*log(T) + 174.911817*T - 3224.664 + 302225/T, (T >= 298.15) & (T < 856.0)), (-36.401*T*log(T) + 180.807719*T - 2366.486, (T >= 856.0) & (T < 917.0)), (2.707217e-6*T**3 - 0.0343483*T**2 + 30.7734*T*log(T) - 297.324358*T + 50882.281 - 7500100/T, (T >= 917.0) & (T < 1999.0)), (-1.007779*T + GHSERNP - 2786.95, (T >= 1999.0) & (T < 4000.0)), (0, True)), ('NP', 'LIQUID'): Piecewise((2.941883e-6*T**3 - 0.0163885*T**2 - 31.229*T*log(T) + 160.024959*T - 4627.18 + 439915/T, (T >= 298.15) & (T < 917.0)), (-45.3964*T*log(T) + 247.671446*T - 7415.255, (T >= 917.0) & (T < 1799.0)), (-8.10942*T + GHSERNP + 4677.481, (T >= 1799.0) & (T < 4000.0)), (0, True)), ('NP', 'ORTHO_AC'): Piecewise((GHSERNP, (T >= 298.15) & (T < 4000.0)), (0, True)), ('NP', 'TETRAG_AD'): Piecewise((4.98465e-6*T**3 - 0.0161186*T**2 - 34.11*T*log(T) + 183.829213*T - 10157.32 + 532825/T, (T >= 298.15) & (T < 555.0)), (-39.33*T*log(T) + 207.01896*T - 7873.688, (T >= 555.0) & (T < 856.0)), (1.52726e-6*T**3 - 0.01921045*T**2 - 3.4265*T*log(T) - 46.64846*T + 19027.98 - 3564640/T, (T >= 856.0) & (T < 1999.0)), (0.926171*T + GHSERNP - 3978.084, (T >= 1999.0) & (T < 4000.0)), (0, True)), ('O', 'BCC_A2'): Piecewise((GHSEROO + 30000, (T >= 298.15) & (T < 6000.0)), (0, True)), ('O', 'FCC_A1'): Piecewise((GHSEROO + 30000, (T >= 298.15) & (T < 6000.0)), (0, True)), ('O', 'LIQUID'): Piecewise((31.44*T + GHSEROO - 2648.9, (T >= 298.15) & (T < 6000.0)), (0, True)), ('O2', 'GAS'): Piecewise((2*GHSEROO, (T >= 298.15) & (T < 6000.0)), (0, True)), ('OS', 'BCC_A2'): Piecewise((-9*T + GHSEROS + 43500, (T >= 298.15) & (T < 5500.0)), (0, True)), ('OS', 'FCC_A1'): Piecewise((-2.5*T + GHSEROS + 13000, (T >= 298.15) & (T < 5500.0)), (0, True)), ('OS', 'HCP_A3'): Piecewise((GHSEROS, (T >= 298.15) & (T < 5500.0)), (0, True)), ('OS', 'LIQUID'): Piecewise((-8.473743*T + GHSEROS + 36460.17, (T >= 298.15) & (T < 1000.0)), (1.014279e-6*T**3 - 0.020464464*T**2 + 19.9382156*T*log(T) - 198.324341*T + 68715.318 - 6237261/T, (T >= 1000.0) & (T < 3306.0)), (-50*T*log(T) + 336.874526*T - 15903.192, (T >= 3306.0) & (T < 5500.0)), (0, True)), ('P', 'BCC_A2'): Piecewise((-2.418867e-6*T**3 + 0.0034121*T**2 - 25.55*T*log(T) + 135.412002*T + 18792.241 + 160095/T, (T >= 250.0) & (T < 500.0)), (3.93917e-7*T**3 - 0.00957685*T**2 - 14.368*T*log(T) + 64.411737*T + 23045.079 - 141375/T, (T >= 500.0) & (T < 852.35)), (-6.651929e-6*T**3 + 0.067272364*T**2 - 149.449556*T*log(T) + 1012.76962*T - 74639.613 + 12495943/T, (T >= 852.35) & (T < 1500.0)), (4.70235*T + GHSERPP + 28337.756, (T >= 1500.0) & (T < 3000.0)), (0, True)), ('P', 'FCC_A1'): Piecewise((-2.418867e-6*T**3 + 0.0034121*T**2 - 25.55*T*log(T) + 135.534002*T + 10842.441 + 160095/T, (T >= 250.0) & (T < 500.0)), (3.93917e-7*T**3 - 0.00957685*T**2 - 14.368*T*log(T) + 64.533737*T + 15095.279 - 141375/T, (T >= 500.0) & (T < 852.35)), (-6.651929e-6*T**3 + 0.067272364*T**2 - 149.449556*T*log(T) + 1012.89162*T - 82589.413 + 12495943/T, (T >= 852.35) & (T < 1500.0)), (4.82435*T + GHSERPP + 20387.956, (T >= 1500.0) & (T < 3000.0)), (0, True)), ('P', 'LIQUID'): Piecewise((3.9049371e-5*T**3 - 0.002898936*T**2 - 70.7440584*T*log(T) + 434.930931*T - 26316.111 + 1141147/T, (T >= 250.0) & (T < 317.3)), (-26.326*T*log(T) + 133.291873*T - 7232.449, (T >= 317.3) & (T < 1000.0)), (-2.584958*T + GHSERPP + 860.626, (T >= 1000.0) & (T < 3000.0)), (0, True)), ('P', 'RED_P'): Piecewise((-2.418867e-6*T**3 + 0.0034121*T**2 - 25.55*T*log(T) + 148.672002*T - 25976.559 + 160095/T, (T >= 250.0) & (T < 500.0)), (3.93917e-7*T**3 - 0.00957685*T**2 - 14.368*T*log(T) + 77.671737*T - 21723.721 - 141375/T, (T >= 500.0) & (T < 852.35)), (-6.651929e-6*T**3 + 0.067272364*T**2 - 149.449556*T*log(T) + 1026.02962*T - 119408.413 + 12495943/T, (T >= 852.35) & (T < 1500.0)), (17.96235*T + GHSERPP - 16431.044, (T >= 1500.0) & (T < 3000.0)), (0, True)), ('P', 'WHITE_P'): Piecewise((GHSERPP, (T >= 250.0) & (T < 3000.0)), (0, True)), ('PA', 'BCC_A2'): Piecewise((1.337387e-6*T**3 - 0.01322095*T**2 - 18.203*T*log(T) + 71.957409*T + 781.847 - 101600/T, (T >= 298.15) & (T < 1443.0)), (-39.748*T*log(T) + 220.478519*T - 10955.948, (T >= 1443.0) & (T < 1845.0)), (3.343867e-6*T**3 - 0.0637105*T**2 + 171.108*T*log(T) - 1397.15052*T + 284495.194 - 74992000/T, (T >= 1845.0) & (T < 2710.0)), (-2.212452*T + GHSERPA + 2064.512, (T >= 2710.0) & (T < 4000.0)), (0, True)), ('PA', 'BCT_AA'): Piecewise((GHSERPA, (T >= 298.15) & (T < 4000.0)), (0, True)), ('PA', 'LIQUID'): Piecewise((-9.544*T + GHSERPA + 16181.1, (T >= 298.15) & (T < 1088.0)), (3.075017e-6*T**3 - 0.0372478*T**2 + 30.336*T*log(T) - 278.789916*T + 48013.96 - 5064250/T, (T >= 1088.0) & (T < 1845.0)), (-47.2792*T*log(T) + 277.955437*T - 12508.174, (T >= 1845.0) & (T < 2176.0)), (-10.353202*T + GHSERPA + 17441.509, (T >= 2176.0) & (T < 4000.0)), (0, True)), ('PB', 'BCC_A2'): Piecewise((-1.1*T + GHSERPB + 2400, (T >= 298.15) & (T < 2100.0)), (0, True)), ('PB', 'BCT_A5'): Piecewise((3.52*T + GHSERPB + 489, (T >= 298.15) & (T < 2100.0)), (0, True)), ('PB', 'FCC_A1'): Piecewise((GHSERPB, (T >= 298.15) & (T < 2100.0)), (0, True)), ('PB', 'HCP_A3'): Piecewise((T + GHSERPB + 300, (T >= 298.15) & (T < 2100.0)), (0, True)), ('PB', 'LIQUID'): Piecewise((-6.019e-19*T**7 - 7.750683*T + GHSERPB + 4672.124, (T >= 298.15) & (T < 600.61)), (-8.067136*T + GHSERPB + 4853.137 - 8.05448e+25/T**9, (T >= 600.61) & (T < 1200.0)), (-8.067135*T + GHSERPB + 4853.137 - 8.05448e+25/T**9, (T >= 1200.0) & (T < 2100.0)), (0, True)), ('PB', 'RHOMBOHEDRAL_A7'): Piecewise((3.52*T + GHSERPB + 4900, (T >= 298.15) & (T < 2100.0)), (0, True)), ('PB', 'TETRAGONAL_A6'): Piecewise((-2.4395e-7*T**3 - 0.003637462*T**2 - 24.5639065*T*log(T) + 105.253344*T - 7176.855, (T >= 298.15) & (T < 600.61)), (0.001567619*T**2 - 32.5310793*T*log(T) + 157.796282*T - 10057.865 + 8.05448e+25/T**9, (T >= 600.61) & (T < 1200.0)), (2.1489e-5*T**2 - 0.0396834*T*log(T) + 3.5531*T + GHSERPB + 473.23, (T >= 1200.0) & (T < 2100.0)), (0, True)), ('PB', 'TET_ALPHA1'): Piecewise((-2.4395e-7*T**3 - 0.003656801*T**2 - 24.5639065*T*log(T) + 102.153384*T - 7466.885, (T >= 298.15) & (T < 600.61)), (0.001548279*T**2 - 32.5310793*T*log(T) + 154.696322*T - 10347.895 + 8.05448e+25/T**9, (T >= 600.61) & (T < 1200.0)), (2.148e-6*T**2 - 0.0396834*T*log(T) + 0.45314*T + GHSERPB + 183.2, (T >= 1200.0) & (T < 2100.0)), (0, True)), ('PD', 'BCC_A2'): Piecewise((-1.8*T + GHSERPD + 10500, (T >= 298.15) & (T < 4000.0)), (0, True)), ('PD', 'FCC_A1'): Piecewise((GHSERPD, (T >= 298.15) & (T < 4000.0)), (0, True)), ('PD', 'HCP_A3'): Piecewise((0.1*T + GHSERPD + 2000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('PD', 'LIQUID'): Piecewise((-5.112162*T + GHSERPD + 11506.758, (T >= 298.15) & (T < 600.0)), (2.430675e-6*T**3 - 0.027266568*T**2 + 10.8922031*T*log(T) - 116.918419*T + 23405.778 - 1853674/T, (T >= 600.0) & (T < 1828.0)), (-41.17*T*log(T) + 251.416903*T - 12373.637, (T >= 1828.0) & (T < 4000.0)), (0, True)), ('PR', 'BCC_A2'): Piecewise((3.542468e-6*T**3 - 0.02284377*T**2 - 13.7470527*T*log(T) + 28.274853*T - 2863.651 - 87486/T, (T >= 298.15) & (T < 1068.0)), (-38.451*T*log(T) + 188.657121*T - 11985.919, (T >= 1068.0) & (T < 1204.0)), (1.76214e-7*T**3 - 0.004106833*T**2 - 26.6824313*T*log(T) + 100.826281*T + 953.224 - 2473024/T, (T >= 1204.0) & (T < 3800.0)), (0, True)), ('PR', 'DHCP'): Piecewise((GHSERPR, (T >= 298.15) & (T < 3800.0)), (0, True)), ('PR', 'LIQUID'): Piecewise((5.427467e-6*T**3 - 0.035119723*T**2 - 4.7344931*T*log(T) - 29.099465*T + 3848.961 - 207406/T, (T >= 298.15) & (T < 1068.0)), (-42.9697*T*log(T) + 219.508805*T - 10539.574, (T >= 1068.0) & (T < 1204.0)), (-8.17635*T + GHSERPR + 9475.104, (T >= 1204.0) & (T < 3800.0)), (0, True)), ('PT', 'BCC_A2'): Piecewise((-2.4*T + GHSERPT + 15000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('PT', 'FCC_A1'): Piecewise((GHSERPT, (T >= 298.15) & (T < 4000.0)), (0, True)), ('PT', 'HCP_A3'): Piecewise((0.1*T + GHSERPT + 2500, (T >= 298.15) & (T < 4000.0)), (0, True)), ('PT', 'LIQUID'): Piecewise((-9.275183*T + GHSERPT + 20114.016, (T >= 298.15) & (T < 600.0)), (9.31516e-7*T**3 - 0.011551507*T**2 - 12.3403769*T*log(T) + 32.94182*T + 19023.491 - 601426/T, (T >= 600.0) & (T < 2041.5)), (-36.5*T*log(T) + 205.858962*T + 1404.468, (T >= 2041.5) & (T < 4000.0)), (0, True)), ('PU', 'ALPHA_PU'): Piecewise((GHSERPU, (T >= 298.15) & (T < 3000.0)), (0, True)), ('PU', 'BCC_A2'): Piecewise((2.061667e-6*T**3 - 0.009105*T**2 - 27.094*T*log(T) + 116.603882*T - 1358.984 + 20863/T, (T >= 298.15) & (T < 745.0)), (-33.72*T*log(T) + 156.878957*T - 2890.817, (T >= 745.0) & (T < 956.0)), (1.426922e-6*T**3 - 0.02023305*T**2 + 6.921*T*log(T) - 132.788248*T + 29313.619 - 4469245/T, (T >= 956.0) & (T < 2071.0)), (-5.539698*T + GHSERPU - 938.429, (T >= 2071.0) & (T < 3000.0)), (0, True)), ('PU', 'BETA_PU'): Piecewise((-0.00653*T**2 - 27.416*T*log(T) + 123.249151*T - 4873.654, (T >= 298.15) & (T < 679.5)), (1.524942e-6*T**3 - 0.0154772*T**2 - 15.7351*T*log(T) + 43.566585*T + 2435.094 - 864940/T, (T >= 679.5) & (T < 1464.0)), (-4.739938*T + GHSERPU + 503.094, (T >= 1464.0) & (T < 3000.0)), (0, True)), ('PU', 'FCC_A1'): Piecewise((-0.0054035*T**2 - 28.4781*T*log(T) + 127.586536*T - 3920.781, (T >= 298.15) & (T < 990.0)), (1.524942e-6*T**3 - 0.0154772*T**2 - 15.7351*T*log(T) + 41.52572*T + 3528.208 - 864940/T, (T >= 990.0) & (T < 1464.0)), (-6.780803*T + GHSERPU + 1596.208, (T >= 1464.0) & (T < 3000.0)), (0, True)), ('PU', 'GAMMA_PU'): Piecewise((-2.8103833e-5*T**3 + 0.0816415*T**2 - 77.5802*T*log(T) + 419.402655*T - 16766.303 + 574825/T, (T >= 298.15) & (T < 487.9)), (-0.0114795*T**2 - 22.0233*T*log(T) + 88.325069*T - 2942.77, (T >= 487.9) & (T < 593.9)), (6.92887e-7*T**3 - 0.0070383*T**2 - 32.3405*T*log(T) + 160.314641*T - 9336.967 + 630600/T, (T >= 593.9) & (T < 1179.0)), (-6.829936*T + GHSERPU + 2026.406, (T >= 1179.0) & (T < 3000.0)), (0, True)), ('PU', 'LIQUID'): Piecewise((-12.5133*T + GHSERPU + 6608.1, (T >= 298.15) & (T < 3000.0)), (0, True)), ('PU', 'TETRAGONAL_A6'): Piecewise((5.166667e-6*T**3 - 0.024006*T**2 - 16.43*T*log(T) + 54.586547*T - 496.178 - 158470/T, (T >= 298.15) & (T < 736.0)), (-35.56*T*log(T) + 173.35008*T - 6122.307, (T >= 736.0) & (T < 757.0)), (6.59882e-7*T**3 - 0.00937295*T**2 - 19.756*T*log(T) + 63.890352*T + 3982.078 - 1112565/T, (T >= 757.0) & (T < 2157.0)), (-4.905143*T + GHSERPU - 738.383, (T >= 2157.0) & (T < 3000.0)), (0, True)), ('RB', 'BCC_A2'): Piecewise((GHSERRB, (T >= 200.0) & (T < 2100.0)), (0, True)), ('RB', 'FCC_A1'): Piecewise((1.3*T + GHSERRB + 200, (T >= 200.0) & (T < 2100.0)), (0, True)), ('RB', 'HCP_A3'): Piecewise((2*T + GHSERRB + 200, (T >= 200.0) & (T < 2100.0)), (0, True)), ('RB', 'LIQUID'): Piecewise((1.44078e-17*T**7 - 7.110486*T + GHSERRB + 2217.552, (T >= 200.0) & (T < 312.46)), (-6.960316*T + GHSERRB + 2172.865 + 5.55029e+22/T**9, (T >= 312.46) & (T < 900.0)), (-6.960316*T + GHSERRB + 2172.866 + 5.55029e+22/T**9, (T >= 900.0) & (T < 1600.0)), (-6.960315*T + GHSERRB + 2172.865 + 5.55029e+22/T**9, (T >= 1600.0) & (T < 2100.0)), (0, True)), ('RE', 'BCC_A2'): Piecewise((-6*T + GHSERRE + 29200, (T >= 298.15) & (T < 6000.0)), (0, True)), ('RE', 'FCC_A1'): Piecewise((-1.5*T + GHSERRE + 11000, (T >= 298.15) & (T < 6000.0)), (0, True)), ('RE', 'HCP_A3'): Piecewise((GHSERRE, (T >= 298.15) & (T < 6000.0)), (0, True)), ('RE', 'LIQUID'): Piecewise((-6.34538*T + GHSERRE + 23820.883, (T >= 298.15) & (T < 1200.0)), (-6.345379*T + GHSERRE + 23820.883, (T >= 1200.0) & (T < 2000.0)), (3.92854e-6*T**3 - 0.08939817*T**2 + 314.178898*T*log(T) - 2527.83846*T + 568842.665 - 163100987.0/T, (T >= 2000.0) & (T < 3458.0)), (-49.519*T*log(T) + 335.723691*T - 39044.888, (T >= 3458.0) & (T < 5000.0)), (-11.274151*T + GHSERRE + 39519.408, (T >= 5000.0) & (T < 6000.0)), (0, True)), ('RH', 'BCC_A2'): Piecewise((-4.7*T + GHSERRH + 19000, (T >= 298.15) & (T < 2500.0)), (0, True)), ('RH', 'FCC_A1'): Piecewise((GHSERRH, (T >= 298.15) & (T < 2500.0)), (0, True)), ('RH', 'HCP_A3'): Piecewise((-0.5*T + GHSERRH + 3000, (T >= 298.15) & (T < 2500.0)), (0, True)), ('RH', 'LIQUID'): Piecewise((-6.92133*T + GHSERRH + 19092.91, (T >= 298.15) & (T < 700.0)), (2.100572e-6*T**3 - 0.028665357*T**2 + 15.6492377*T*log(T) - 147.926418*T + 35898.508 - 2638940/T, (T >= 700.0) & (T < 2237.0)), (-50.58456*T*log(T) + 332.974832*T - 18208.54, (T >= 2237.0) & (T < 2450.0)), (-11.915063*T + GHSERRH + 26654.949, (T >= 2450.0) & (T < 2500.0)), (0, True)), ('RU', 'BCC_A2'): Piecewise((-6.2*T + GHSERRU + 26500, (T >= 298.15) & (T < 4500.0)), (0, True)), ('RU', 'FCC_A1'): Piecewise((-2.4*T + GHSERRU + 12500, (T >= 298.15) & (T < 4500.0)), (0, True)), ('RU', 'HCP_A3'): Piecewise((GHSERRU, (T >= 298.15) & (T < 4500.0)), (0, True)), ('RU', 'LIQUID'): Piecewise((-8.398748*T + GHSERRU + 27480.616, (T >= 298.15) & (T < 800.0)), (1.667839e-6*T**3 - 0.026524167*T**2 + 19.539341*T*log(T) - 179.818561*T + 50827.232 - 3861125/T, (T >= 800.0) & (T < 2607.0)), (-51.8816*T*log(T) + 349.673561*T - 17161.807, (T >= 2607.0) & (T < 2740.0)), (-14.808753*T + GHSERRU + 38606.497, (T >= 2740.0) & (T < 4500.0)), (0, True)), ('S', 'BCC_A2'): Piecewise((GHSERSS + 105000, (T >= 298.15) & (T < 1300.0)), (0, True)), ('S', 'FCC_A1'): Piecewise((GHSERSS + 105000, (T >= 298.15) & (T < 1300.0)), (0, True)), ('S', 'LIQUID'): Piecewise((-2.4942e-7*T**3 - 0.018629*T**2 - 15.504*T*log(T) + 77.905686*T - 4001.549 - 113945/T, (T >= 298.15) & (T < 388.36)), (-0.0102214167*T**3 + 32.79275*T**2 - 19762.4*T*log(T) + 118449.601*T - 5285183.35 + 264673500.0/T, (T >= 388.36) & (T < 428.15)), (-0.0529973333*T**3 + 135.3045*T**2 - 57607.3*T*log(T) + 319914.094*T - 8174995.23, (T >= 428.15) & (T < 432.25)), (-0.00101380333*T**3 + 2.845035*T**2 - 1371.85*T*log(T) + 7758.85593*T - 219408.801, (T >= 432.25) & (T < 453.15)), (5.18835e-5*T**3 - 0.2531915*T**2 + 202.958*T*log(T) - 1336.35027*T + 92539.872 - 8202200/T, (T >= 453.15) & (T < 717.0)), (-32*T*log(T) + 176.37082*T - 6889.972, (T >= 717.0) & (T < 1300.0)), (0, True)), ('S', 'MONOCLINIC'): Piecewise((-0.0101215*T**2 - 17.318*T*log(T) + 89.000772*T - 5701.485, (T >= 298.15) & (T < 388.36)), (1.118079e-6*T**3 - 0.008604142*T**2 - 21.1094347*T*log(T) + 114.512564*T - 7435.888 + 120740/T, (T >= 388.36) & (T < 1300.0)), (0, True)), ('S', 'ORTHORHOMBIC_S'): Piecewise((GHSERSS, (T >= 298.15) & (T < 1300.0)), (0, True)), ('SB', 'BCC_A2'): Piecewise((-15.1*T + GHSERSB + 19874, (T >= 298.15) & (T < 2000.0)), (0, True)), ('SB', 'BCT_A5'): Piecewise((-8*T + GHSERSB + 13000, (T >= 298.15) & (T < 2000.0)), (0, True)), ('SB', 'FCC_A1'): Piecewise((-13.7*T + GHSERSB + 19874, (T >= 298.15) & (T < 2000.0)), (0, True)), ('SB', 'HCP_A3'): Piecewise((-13*T + GHSERSB + 19874, (T >= 298.15) & (T < 2000.0)), (0, True)), ('SB', 'LIQUID'): Piecewise((-1.74847e-20*T**7 - 21.923164*T + GHSERSB + 19822.328, (T >= 298.15) & (T < 903.78)), (-31.38*T*log(T) + 147.455986*T + 8175.359, (T >= 903.78) & (T < 2000.0)), (0, True)), ('SB', 'RHOMBOHEDRAL_A7'): Piecewise((GHSERSB, (T >= 298.15) & (T < 2000.0)), (0, True)), ('SC', 'BCC_A2'): Piecewise((-1.024135*T + GHSERSC + 1979.728, (T >= 298.15) & (T < 1000.0)), (1.5637371e-5*T**3 - 0.167120107*T**2 + 276.76664*T*log(T) - 2004.05469*T + 230161.408 - 33783257/T, (T >= 1000.0) & (T < 1608.0)), (-44.2249*T*log(T) + 283.642312*T - 25928.011, (T >= 1608.0) & (T < 2000.0)), (-2.832026*T + GHSERSC + 4587.235, (T >= 2000.0) & (T < 3200.0)), (0, True)), ('SC', 'HCP_A3'): Piecewise((GHSERSC, (T >= 298.15) & (T < 3200.0)), (0, True)), ('SC', 'LIQUID'): Piecewise((2.13106e-6*T**3 - 0.020636524*T**2 - 10.7967803*T*log(T) + 45.427539*T + 6478.66 - 158106/T, (T >= 298.15) & (T < 1608.0)), (-44.2249*T*log(T) + 275.871695*T - 11832.111, (T >= 1608.0) & (T < 2000.0)), (-10.602643*T + GHSERSC + 18683.135, (T >= 2000.0) & (T < 3200.0)), (0, True)), ('SE', 'HEXAGONAL_A8'): Piecewise((GHSERSE, (T >= 298.15) & (T < 1000.0)), (0, True)), ('SE', 'LIQUID'): Piecewise((0.000119219297*T**3 - 0.390268991*T**2 + 194.107439*T*log(T) - 1178.28824*T + 50533.347 - 2224398/T, (T >= 298.15) & (T < 494.0)), (-35.1456*T*log(T) + 183.72559*T - 5228.304, (T >= 494.0) & (T < 800.0)), (-14.044576*T + GHSERSE + 6965.166, (T >= 800.0) & (T < 1000.0)), (0, True)), ('SI', 'BCC_A2'): Piecewise((-22.5*T + GHSERSI + 47000, (T >= 298.15) & (T < 3600.0)), (0, True)), ('SI', 'CBCC_A12'): Piecewise((-20.377*T + GHSERSI + 50208, (T >= 298.15) & (T < 3600.0)), (0, True)), ('SI', 'CUB_A13'): Piecewise((-20.377*T + GHSERSI + 47279, (T >= 298.15) & (T < 3600.0)), (0, True)), ('SI', 'DIAMOND_A4'): Piecewise((GHSERSI, (T >= 298.15) & (T < 3600.0)), (0, True)), ('SI', 'FCC_A1'): Piecewise((-21.8*T + GHSERSI + 51000, (T >= 298.15) & (T < 3600.0)), (0, True)), ('SI', 'HCP_A3'): Piecewise((-20.8*T + GHSERSI + 49200, (T >= 298.15) & (T < 3600.0)), (0, True)), ('SI', 'LIQUID'): Piecewise((2.09307e-21*T**7 - 30.099439*T + GHSERSI + 50696.36, (T >= 298.15) & (T < 1687.0)), (-27.196*T*log(T) + 137.722298*T + 40370.523, (T >= 1687.0) & (T < 3600.0)), (0, True)), ('SM', 'BCC_A2'): Piecewise((3.579527e-6*T**3 - 0.025446016*T**2 - 16.9298494*T*log(T) + 55.972523*T - 4368.72 + 94209/T, (T >= 298.15) & (T < 1190.0)), (-46.9445*T*log(T) + 253.121044*T - 15957.862, (T >= 1190.0) & (T < 1345.0)), (3.329865e-6*T**3 - 0.047314968*T**2 + 71.6856914*T*log(T) - 624.680805*T + 111191.653 - 24870276/T, (T >= 1345.0) & (T < 2100.0)), (0, True)), ('SM', 'LIQUID'): Piecewise((4.544272e-6*T**3 - 0.032418177*T**2 - 11.6968284*T*log(T) + 20.117456*T + 3468.783 + 23528/T, (T >= 298.15) & (T < 1190.0)), (-50.208*T*log(T) + 273.487076*T - 11728.229, (T >= 1190.0) & (T < 1345.0)), (-8.707299*T + GHSERSM + 11327.85, (T >= 1345.0) & (T < 2100.0)), (0, True)), ('SM', 'RHOMB'): Piecewise((GHSERSM, (T >= 298.15) & (T < 2100.0)), (0, True)), ('SN', 'BCC_A2'): Piecewise((-6*T + GHSERSN + 4400, (T >= 100.0) & (T < 3000.0)), (0, True)), ('SN', 'BCT_A5'): Piecewise((GHSERSN, (T >= 100.0) & (T < 3000.0)), (0, True)), ('SN', 'DIAMOND_A4'): Piecewise((2.7288e-6*T**3 - 0.00813975*T**2 - 22.972*T*log(T) + 114.007785*T - 9579.608 + 25615/T, (T >= 100.0) & (T < 298.15)), (1.784447e-6*T**3 - 0.008575282*T**2 - 21.5750771*T*log(T) + 104.84654*T - 9063.001 - 2544/T, (T >= 298.15) & (T < 800.0)), (-28.4512*T*log(T) + 147.396535*T - 10909.351, (T >= 800.0) & (T < 3000.0)), (0, True)), ('SN', 'FCC_A1'): Piecewise((3.121167e-6*T**3 - 0.0188702*T**2 - 15.961*T*log(T) + 56.983315*T - 345.135 - 61960/T, (T >= 100.0) & (T < 250.0)), (-8.46*T + GHSERSN + 5510, (T >= 250.0) & (T < 3000.0)), (0, True)), ('SN', 'HCP_A3'): Piecewise((-4.4*T + GHSERSN + 3900, (T >= 100.0) & (T < 3000.0)), (0, True)), ('SN', 'LIQUID'): Piecewise((1.47031e-18*T**7 - 14.087767*T + GHSERSN + 7103.092, (T >= 100.0) & (T < 505.08)), (-13.814383*T + GHSERSN + 6971.586 + 1.2307e+25/T**9, (T >= 505.08) & (T < 800.0)), (-28.4512*T*log(T) + 125.182498*T - 1285.372, (T >= 800.0) & (T < 3000.0)), (0, True)), ('SN', 'RHOMBOHEDRAL_A7'): Piecewise((GHSERSN + 2035, (T >= 100.0) & (T < 3000.0)), (0, True)), ('SR', 'BCC_A2'): Piecewise((2.2965e-7*T**3 - 0.003126762*T**2 - 25.6708365*T*log(T) + 116.583654*T - 6779.234 + 27649/T, (T >= 298.15) & (T < 820.0)), (-1.7895e-8*T**3 - 0.0019493*T**2 - 26.57*T*log(T) + 122.067301*T - 6970.594 + 16495/T, (T >= 820.0) & (T < 1050.0)), (5.20221e-7*T**3 - 0.009539908*T**2 - 9.7788593*T*log(T) + 0.423037*T + 8168.357 - 2414794/T, (T >= 1050.0) & (T < 3000.0)), (0, True)), ('SR', 'FCC_A1'): Piecewise((GHSERSR, (T >= 298.15) & (T < 3000.0)), (0, True)), ('SR', 'HCP_A3'): Piecewise((0.7*T + GHSERSR + 250, (T >= 298.15) & (T < 3000.0)), (0, True)), ('SR', 'LIQUID'): Piecewise((4.981237e-6*T**3 - 0.031840595*T**2 - 5.0668978*T*log(T) - 10.118994*T + 2194.997 - 265559/T, (T >= 298.15) & (T < 1050.0)), (-39.463*T*log(T) + 213.406219*T - 10855.29, (T >= 1050.0) & (T < 3000.0)), (0, True)), ('TA', 'BCC_A2'): Piecewise((GHSERTA, (T >= 298.15) & (T < 6000.0)), (0, True)), ('TA', 'FCC_A1'): Piecewise((1.7*T + GHSERTA + 16000, (T >= 298.15) & (T < 6000.0)), (0, True)), ('TA', 'HCP_A3'): Piecewise((2.4*T + GHSERTA + 12000, (T >= 298.15) & (T < 6000.0)), (0, True)), ('TA', 'LIQUID'): Piecewise((-7.578729*T + GHSERTA + 29160.975, (T >= 298.15) & (T < 1000.0)), (6.14599e-7*T**3 - 0.012330066*T**2 + 0.0279523*T*log(T) - 61.981795*T + 43884.339 - 3523338/T, (T >= 1000.0) & (T < 3290.0)), (-41.84*T*log(T) + 258.110873*T - 6314.543, (T >= 3290.0) & (T < 6000.0)), (0, True)), ('TB', 'BCC_A2'): Piecewise((-2.652707*T + GHSERTB + 4167.835, (T >= 298.15) & (T < 1200.0)), (3.4100235e-5*T**3 - 0.373763517*T**2 + 706.580596*T*log(T) - 5157.77779*T + 633060.245 - 103233571.0/T, (T >= 1200.0) & (T < 1562.0)), (-46.4842*T*log(T) + 257.388486*T - 23398.029, (T >= 1562.0) & (T < 3000.0)), (0, True)), ('TB', 'HCP_A3'): Piecewise((GHSERTB, (T >= 298.15) & (T < 3000.0)), (0, True)), ('TB', 'LIQUID'): Piecewise((2.17475e-6*T**3 - 0.020466105*T**2 - 14.252646*T*log(T) + 29.867521*T + 3945.831 - 160724/T, (T >= 298.15) & (T < 1562.0)), (-46.4842*T*log(T) + 251.16889*T - 13247.649, (T >= 1562.0) & (T < 3000.0)), (0, True)), ('TC', 'BCC_A2'): Piecewise((-4.5*T + GHSERTC + 18000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TC', 'FCC_A1'): Piecewise((-1.5*T + GHSERTC + 10000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TC', 'HCP_A3'): Piecewise((GHSERTC, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TC', 'LIQUID'): Piecewise((-9.62385e-22*T**7 - 12.313*T + GHSERTC + 30402.134, (T >= 298.15) & (T < 2430.0)), (-47*T*log(T) + 303.7538*T - 12221.9, (T >= 2430.0) & (T < 4000.0)), (0, True)), ('TE', 'HEXAGONAL_A8'): Piecewise((GHSERTE, (T >= 298.15) & (T < 1600.0)), (0, True)), ('TE', 'LIQUID'): Piecewise((-9.42075e-5*T**3 + 0.2219435*T**2 - 126.318*T*log(T) + 685.877639*T - 17554.731 + 827930/T, (T >= 298.15) & (T < 626.49)), (-0.00130692833*T**3 + 7.09775*T**2 - 7196.41*T*log(T) + 46756.357*T - 3165763.48 + 258051000.0/T, (T >= 626.49) & (T < 722.66)), (1.6129733e-5*T**3 - 0.142016*T**2 + 202.743*T*log(T) - 1500.57909*T + 180326.959 - 24238450/T, (T >= 722.66) & (T < 1150.0)), (-26.1929273*T + GHSERTE + 19110.036, (T >= 1150.0) & (T < 1600.0)), (0, True)), ('TH', 'BCC_A2'): Piecewise((-5.3048e-7*T**3 + 0.00043775*T**2 - 28.244*T*log(T) + 134.279995*T - 2321.06 + 91190/T, (T >= 298.15) & (T < 1633.0)), (-2.536883e-6*T**3 + 0.03098*T**2 - 116.453*T*log(T) + 801.657849*T - 115978.348 + 27512600/T, (T >= 1633.0) & (T < 2023.0)), (1.66067e-7*T**3 - 0.00346655*T**2 - 35.813*T*log(T) + 209.523509*T - 33602.796 + 11876950/T, (T >= 2023.0) & (T < 3600.0)), (-0.049551*T + GHSERTH - 980.302, (T >= 3600.0) & (T < 4000.0)), (0, True)), ('TH', 'FCC_A1'): Piecewise((GHSERTH, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TH', 'LIQUID'): Piecewise((-9.09067e-7*T**3 - 0.00168345*T**2 - 24.987*T*log(T) + 111.635146*T + 5031.109 + 10865/T, (T >= 298.15) & (T < 1499.8)), (1.210117e-6*T**3 - 0.0136421*T**2 - 24.03*T*log(T) + 128.406516*T - 15602.847 + 7111100/T, (T >= 1499.8) & (T < 2014.5)), (-46.024*T*log(T) + 275.750074*T - 17273.382, (T >= 2014.5) & (T < 2900.0)), (-8.229771*T + GHSERTH + 16079.931, (T >= 2900.0) & (T < 4000.0)), (0, True)), ('TI', 'BCC_A2'): Piecewise((-2.78803e-7*T**3 - 0.000663845*T**2 - 25.5768*T*log(T) + 134.71418*T - 1272.064 + 7208/T, (T >= 298.15) & (T < 1155.0)), (-8.4534e-7*T**3 + 0.00121707*T**2 - 22.3771*T*log(T) + 105.366379*T + 6667.385 - 2002750/T, (T >= 1155.0) & (T < 1941.0)), (1.228863e-6*T**3 - 0.02200832*T**2 + 19.0900905*T*log(T) - 182.426471*T + 26483.26 + 1400501/T, (T >= 1941.0) & (T < 4000.0)), (0, True)), ('TI', 'BCT_A5'): Piecewise((GHSERTI + 4602.2, (T >= 298.15) & (T < 3000.0)), (0, True)), ('TI', 'CBCC_A12'): Piecewise((GHSERTI + 4602.2, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TI', 'CUB_A13'): Piecewise((GHSERTI + 7531.2, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TI', 'DIAMOND_A4'): Piecewise((GHSERTI + 25000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TI', 'FCC_A1'): Piecewise((-0.1*T + GHSERTI + 6000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TI', 'HCP_A3'): Piecewise((GHSERTI, (T >= 298.15) & (T < 4000.0)), (0, True)), ('TI', 'LIQUID'): Piecewise((-6.980938*T + GHSERTI + 12194.415, (T >= 298.15) & (T < 900.0)), (-6.980938*T + GHSERTI + 12194.416, (T >= 900.0) & (T < 1300.0)), (1.2457117e-5*T**3 - 0.163409355*T**2 + 342.059267*T*log(T) - 2554.0225*T + 369519.198 - 67034516/T, (T >= 1300.0) & (T < 1941.0)), (-46.29*T*log(T) + 298.7367*T - 19887.066, (T >= 1941.0) & (T < 4000.0)), (0, True)), ('TL', 'BCC_A2'): Piecewise((-1.0115933e-5*T**3 + 0.0172318*T**2 - 33.0508*T*log(T) + 150.019517*T - 9194.493 + 82153/T, (T >= 200.0) & (T < 577.0)), (-2.359101e-6*T**3 + 0.026042993*T**2 - 79.2926704*T*log(T) + 482.633817*T - 41836.403 + 3507810/T, (T >= 577.0) & (T < 1800.0)), (0, True)), ('TL', 'FCC_A1'): Piecewise((GHSERTL + 310, (T >= 200.0) & (T < 1800.0)), (0, True)), ('TL', 'HCP_A3'): Piecewise((GHSERTL, (T >= 200.0) & (T < 1800.0)), (0, True)), ('TL', 'LIQUID'): Piecewise((1.4248046e-5*T**3 - 0.044350292*T**2 - 7.44455*T*log(T) + 0.755649*T - 946.623 - 54228/T, (T >= 200.0) & (T < 577.0)), (9.0e-12*T**3 - 0.00083662*T**2 - 25.8437*T*log(T) + 98.472609*T - 614.74 - 612570/T, (T >= 577.0) & (T < 1800.0)), (0, True)), ('TM', 'HCP_A3'): Piecewise((GHSERTM, (T >= 298.15) & (T < 2300.0)), (0, True)), ('TM', 'LIQUID'): Piecewise((-6.557671*T + GHSERTM + 13199.249, (T >= 298.15) & (T < 600.0)), (2.288172e-6*T**3 - 0.025487085*T**2 + 6.8744933*T*log(T) - 126.738485*T + 22640.028 - 1585412/T, (T >= 600.0) & (T < 1818.0)), (-41.37976*T*log(T) + 214.184413*T - 10090.305, (T >= 1818.0) & (T < 2300.0)), (0, True)), ('U', 'BCC_A2'): Piecewise((9.67907e-7*T**3 - 0.00835595*T**2 - 27.5152*T*log(T) + 131.5381*T - 752.767 + 204611/T, (T >= 298.15) & (T < 1049.0)), (-38.2836*T*log(T) + 202.685635*T - 4698.365, (T >= 1049.0) & (T < 3000.0)), (0, True)), ('U', 'LIQUID'): Piecewise((-10.3239*T + GHSERUU + 12355.5, (T >= 298.15) & (T < 3000.0)), (0, True)), ('U', 'ORTHORHOMBIC_A20'): Piecewise((GHSERUU, (T >= 298.15) & (T < 3000.0)), (0, True)), ('U', 'TETRAGONAL_U'): Piecewise((2.7889e-8*T**3 - 0.01084475*T**2 - 22.841*T*log(T) + 106.976316*T - 5156.136 + 81944/T, (T >= 298.15) & (T < 941.5)), (-42.9278*T*log(T) + 244.16802*T - 14327.309, (T >= 941.5) & (T < 3000.0)), (0, True)), ('V', 'BCC_A2'): Piecewise((GHSERVV, (T >= 298.15) & (T < 4000.0)), (0, True)), ('V', 'CBCC_A12'): Piecewise((GHSERVV + 9000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('V', 'CUB_A13'): Piecewise((GHSERVV + 10000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('V', 'FCC_A1'): Piecewise((1.7*T + GHSERVV + 7500, (T >= 298.15) & (T < 4000.0)), (0, True)), ('V', 'HCP_A3'): Piecewise((2.4*T + GHSERVV + 4000, (T >= 298.15) & (T < 4000.0)), (0, True)), ('V', 'LIQUID'): Piecewise((-5.19136e-22*T**7 - 9.455552*T + GHSERVV + 20764.117, (T >= 298.15) & (T < 2183.0)), (-47.43*T*log(T) + 311.055983*T - 19617.51, (T >= 2183.0) & (T < 4000.0)), (0, True)), ('W', 'BCC_A2'): Piecewise((GHSERWW, (T >= 298.15) & (T < 6000.0)), (0, True)), ('W', 'FCC_A1'): Piecewise((0.63*T + GHSERWW + 19300, (T >= 298.15) & (T < 6000.0)), (0, True)), ('W', 'HCP_A3'): Piecewise((GHSERWW + 14750, (T >= 298.15) & (T < 6000.0)), (0, True)), ('W', 'LIQUID'): Piecewise((-2.713468e-24*T**7 - 14.10999*T + GHSERWW + 52160.584, (T >= 298.15) & (T < 3695.0)), (-54*T*log(T) + 375.175*T - 30436.051, (T >= 3695.0) & (T < 6000.0)), (0, True)), ('Y', 'BCC_A2'): Piecewise((9.10372497e-9*T**3 - 0.00237175965*T**2 - 25.5832578*T*log(T) + 123.667346*T - 833.658863 + 27340.0687/T, (T >= 100.0) & (T < 1000.0)), (-3.05012175e-7*T**3 - 0.000541757644*T**2 - 27.3038477*T*log(T) + 134.528352*T - 1297.79829, (T >= 1000.0) & (T < 1795.15)), (4.02944768e-7*T**3 - 0.00904576576*T**2 - 8.88296647*T*log(T) + 0.981325399*T + 15389.4975 - 2542575.96/T, (T >= 1795.15) & (T < 3700.0)), (0, True)), ('Y', 'HCP_A3'): Piecewise((GHSERYY, (T >= 100.0) & (T < 3700.0)), (0, True)), ('Y', 'LIQUID'): Piecewise((-8.12981167e-7*T**3 - 0.00347023463*T**2 - 24.6467508*T*log(T) + 119.41873*T + 2098.50738 + 23713.7332/T, (T >= 100.0) & (T < 1000.0)), (1.7595327e-6*T**3 - 0.0189533369*T**2 - 9.0681627*T*log(T) + 19.4520171*T + 7386.44846, (T >= 1000.0) & (T < 1795.15)), (-43.0952*T*log(T) + 257.400783*T - 12976.5957, (T >= 1795.15) & (T < 3700.0)), (0, True)), ('YB', 'BCC_A2'): Piecewise((4.743871e-6*T**3 - 0.030009694*T**2 - 3.8534432*T*log(T) - 21.293677*T - 965.99 - 334650/T, (T >= 298.15) & (T < 1033.0)), (-36.1079*T*log(T) + 188.313864*T - 13368.113, (T >= 1033.0) & (T < 1097.0)), (3.63044e-7*T**3 - 0.004743348*T**2 - 25.7402233*T*log(T) + 113.174165*T - 3911.847 - 1553668/T, (T >= 1097.0) & (T < 2000.0)), (0, True)), ('YB', 'FCC_A1'): Piecewise((GHSERYB, (T >= 298.15) & (T < 2000.0)), (0, True)), ('YB', 'LIQUID'): Piecewise((5.136665e-6*T**3 - 0.03250938*T**2 - 1.8061816*T*log(T) - 40.615571*T + 7030.788 - 370554/T, (T >= 298.15) & (T < 1033.0)), (-36.7774*T*log(T) + 186.690398*T - 6445.835, (T >= 1033.0) & (T < 2000.0)), (0, True)), ('ZN', 'BCC_A2'): Piecewise((-2.5104*T + GHSERZN + 2886.96, (T >= 298.15) & (T < 1700.0)), (0, True)), ('ZN', 'BCT_A5'): Piecewise((-2.5104*T + GHSERZN + 2886.96, (T >= 298.15) & (T < 1700.0)), (0, True)), ('ZN', 'DIAMOND_A4'): Piecewise((30*T + GHSERZN, (T >= 298.15) & (T < 1700.0)), (0, True)), ('ZN', 'FCC_A1'): Piecewise((-1.56968*T + GHSERZN + 2969.82, (T >= 298.15) & (T < 1700.0)), (0, True)), ('ZN', 'HCP_A3'): Piecewise((GHSERZN, (T >= 298.15) & (T < 1700.0)), (0, True)), ('ZN', 'LIQUID'): Piecewise((-3.58958e-19*T**7 - 10.29299*T + GHSERZN + 7157.213, (T >= 298.15) & (T < 692.68)), (-31.38*T*log(T) + 161.608594*T - 3620.391, (T >= 692.68) & (T < 1700.0)), (0, True)), ('ZR', 'BCC_A2'): Piecewise((-7.6143e-11*T**4 - 9.729e-9*T**3 - 0.000340084*T**2 - 25.607406*T*log(T) + 124.9457*T - 525.539 + 25233/T, (T >= 130.0) & (T < 2128.0)), (1.55998*T + GHSERZR - 4620.034 + 1.4103476e+32/T**9, (T >= 2128.0) & (T < 6000.0)), (0, True)), ('ZR', 'FCC_A1'): Piecewise((-0.9*T + GHSERZR + 7600, (T >= 130.0) & (T < 6000.0)), (0, True)), ('ZR', 'HCP_A3'): Piecewise((GHSERZR, (T >= 130.0) & (T < 6000.0)), (0, True)), ('ZR', 'LIQUID'): Piecewise((1.6275e-22*T**7 - 9.080812*T + GHSERZR + 18147.69, (T >= 130.0) & (T < 2128.0)), (-42.144*T*log(T) + 253.812609*T - 8281.26, (T >= 2128.0) & (T < 6000.0)), (0, True)), ('ZR', 'OMEGA'): Piecewise((-0.002799446*T**2 - 26.8556*T*log(T) + 144.432234*T - 8878.082 + 38376/T, (T >= 130.0) & (T < 2128.0)), (2.566675*T + GHSERZR - 3414.603 + 8.517346e+31/T**9, (T >= 2128.0) & (T < 6000.0)), (0, True))}, 'SGTE91SER': {'/-': {'H298': 0.0, 'S298': 0.0, 'mass': 0.0, 'phase': 'ELECTRON_GAS'}, 'AG': {'H298': 5744.6, 'S298': 42.551, 'mass': 107.87, 'phase': 'FCC_A1'}, 'AL': {'H298': 4577.3, 'S298': 28.322, 'mass': 26.982, 'phase': 'FCC_A1'}, 'AM': {'H298': 0.0, 'S298': 0.0, 'mass': 243.06, 'phase': 'DHCP'}, 'AS': {'H298': 0.0, 'S298': 0.0, 'mass': 74.922, 'phase': 'RHOMBOHEDRAL_A7'}, 'AU': {'H298': 6016.6, 'S298': 47.488, 'mass': 196.97, 'phase': 'FCC_A1'}, 'B': {'H298': 1222.0, 'S298': 5.9, 'mass': 10.811, 'phase': 'BETA_RHOMBO_B'}, 'BA': {'H298': 0.0, 'S298': 0.0, 'mass': 137.33, 'phase': 'BCC_A2'}, 'BE': {'H298': 0.0, 'S298': 0.0, 'mass': 9.0122, 'phase': 'HCP_A3'}, 'BI': {'H298': 6426.6, 'S298': 56.735, 'mass': 208.98, 'phase': 'RHOMBOHEDRAL_A7'}, 'C': {'H298': 1054.0, 'S298': 5.74, 'mass': 12.011, 'phase': 'GRAPHITE'}, 'CA': {'H298': 6196.5, 'S298': 41.589, 'mass': 40.078, 'phase': 'FCC_A1'}, 'CD': {'H298': 6250.9, 'S298': 51.798, 'mass': 112.41, 'phase': 'HCP_A3'}, 'CE': {'H298': 0.0, 'S298': 0.0, 'mass': 140.11, 'phase': 'FCC_A1'}, 'CO': {'H298': 0.0, 'S298': 0.0, 'mass': 58.933, 'phase': 'HCP_A3'}, 'CR': {'H298': 4050.0, 'S298': 23.56, 'mass': 51.996, 'phase': 'BCC_A2'}, 'CS': {'H298': 7715.3, 'S298': 85.149, 'mass': 132.91, 'phase': 'BCC_A2'}, 'CU': {'H298': 5004.1, 'S298': 33.15, 'mass': 63.546, 'phase': 'FCC_A1'}, 'DY': {'H298': 0.0, 'S298': 0.0, 'mass': 162.5, 'phase': 'HCP_A3'}, 'ER': {'H298': 7392.3, 'S298': 73.178, 'mass': 167.26, 'phase': 'HCP_A3'}, 'EU': {'H298': 0.0, 'S298': 80.793, 'mass': 151.97, 'phase': 'BCC_A2'}, 'FE': {'H298': 4489.0, 'S298': 27.28, 'mass': 55.847, 'phase': 'BCC_A2'}, 'GA': {'H298': 5573.1, 'S298': 40.828, 'mass': 69.723, 'phase': 'ORTHORHOMBIC_GA'}, 'GD': {'H298': 0.0, 'S298': 0.0, 'mass': 157.25, 'phase': 'HCP_A3'}, 'GE': {'H298': 4627.5, 'S298': 31.087, 'mass': 72.61, 'phase': 'DIAMOND_A4'}, 'HF': {'H298': 0.0, 'S298': 0.0, 'mass': 178.49, 'phase': 'HCP_A3'}, 'HG': {'H298': 0.0, 'S298': 0.0, 'mass': 200.59, 'phase': 'LIQUID'}, 'HO': {'H298': 0.0, 'S298': 0.0, 'mass': 164.93, 'phase': 'HCP_A3'}, 'IN': {'H298': 6610.0, 'S298': 57.65, 'mass': 114.82, 'phase': 'TETRAGONAL_A6'}, 'IR': {'H298': 5267.7, 'S298': 35.505, 'mass': 192.22, 'phase': 'FCC_A1'}, 'K': {'H298': 7083.5, 'S298': 64.672, 'mass': 39.098, 'phase': 'BCC_A2'}, 'LA': {'H298': 0.0, 'S298': 0.0, 'mass': 138.91, 'phase': 'DHCP'}, 'LI': {'H298': 4623.3, 'S298': 29.095, 'mass': 6.941, 'phase': 'BCC_A2'}, 'LU': {'H298': 0.0, 'S298': 0.0, 'mass': 174.97, 'phase': 'HCP_A3'}, 'MG': {'H298': 4998.0, 'S298': 32.671, 'mass': 24.305, 'phase': 'HCP_A3'}, 'MN': {'H298': 4996.0, 'S298': 32.008, 'mass': 54.938, 'phase': 'CBCC_A12'}, 'MO': {'H298': 4589.0, 'S298': 28.56, 'mass': 95.94, 'phase': 'BCC_A2'}, 'N': {'H298': 4335.0, 'S298': 95.751, 'mass': 14.007, 'phase': '1/2_MOLE_N2(G)'}, 'NA': {'H298': 6447.5, 'S298': 51.447, 'mass': 22.99, 'phase': 'BCC_A2'}, 'NB': {'H298': 5220.0, 'S298': 36.27, 'mass': 92.906, 'phase': 'BCC_A2'}, 'ND': {'H298': 0.0, 'S298': 0.0, 'mass': 144.24, 'phase': 'DHCP'}, 'NI': {'H298': 4787.0, 'S298': 29.796, 'mass': 58.69, 'phase': 'FCC_A1'}, 'NP': {'H298': 0.0, 'S298': 0.0, 'mass': 237.05, 'phase': 'ORTHORHOMBIC_AC'}, 'O': {'H298': 4341.0, 'S298': 102.52, 'mass': 15.999, 'phase': '1/2_MOLE_O2(G)'}, 'OS': {'H298': 0.0, 'S298': 32.635, 'mass': 190.2, 'phase': 'HCP_A3'}, 'P': {'H298': 0.0, 'S298': 0.0, 'mass': 30.974, 'phase': 'WHITE_P'}, 'PA': {'H298': 0.0, 'S298': 0.0, 'mass': 231.04, 'phase': 'BCT_AA'}, 'PB': {'H298': 6878.5, 'S298': 64.785, 'mass': 207.2, 'phase': 'FCC_A1'}, 'PD': {'H298': 5468.5, 'S298': 37.823, 'mass': 106.42, 'phase': 'FCC_A1'}, 'PR': {'H298': 0.0, 'S298': 0.0, 'mass': 140.91, 'phase': 'DHCP'}, 'PT': {'H298': 5723.7, 'S298': 41.631, 'mass': 195.08, 'phase': 'FCC_A1'}, 'PU': {'H298': 0.0, 'S298': 0.0, 'mass': 244.06, 'phase': 'ALPHA_PU'}, 'RB': {'H298': 7489.4, 'S298': 76.776, 'mass': 85.468, 'phase': 'BCC_A2'}, 'RE': {'H298': 5355.5, 'S298': 36.526, 'mass': 186.21, 'phase': 'HCP_A3'}, 'RH': {'H298': 4920.4, 'S298': 31.505, 'mass': 102.91, 'phase': 'FCC_A1'}, 'RU': {'H298': 4602.4, 'S298': 28.535, 'mass': 101.07, 'phase': 'HCP_A3'}, 'S': {'H298': 0.0, 'S298': 0.0, 'mass': 32.066, 'phase': 'ORTHORHOMBIC_S'}, 'SB': {'H298': 5870.2, 'S298': 45.522, 'mass': 121.75, 'phase': 'RHOMBOHEDRAL_A7'}, 'SC': {'H298': 0.0, 'S298': 0.0, 'mass': 44.956, 'phase': 'HCP_A3'}, 'SE': {'H298': 5514.5, 'S298': 41.966, 'mass': 78.96, 'phase': 'HEXAGONAL_A8'}, 'SI': {'H298': 3217.5, 'S298': 18.82, 'mass': 28.085, 'phase': 'DIAMOND_A4'}, 'SM': {'H298': 0.0, 'S298': 0.0, 'mass': 150.36, 'phase': 'RHOMBOHEDRAL_SM'}, 'SN': {'H298': 6322.0, 'S298': 51.195, 'mass': 118.71, 'phase': 'BCT_A5'}, 'SR': {'H298': 0.0, 'S298': 0.0, 'mass': 87.62, 'phase': 'FCC_A1'}, 'TA': {'H298': 5681.9, 'S298': 41.472, 'mass': 180.95, 'phase': 'BCC_A2'}, 'TB': {'H298': 0.0, 'S298': 0.0, 'mass': 158.93, 'phase': 'HCP_A3'}, 'TC': {'H298': 0.0, 'S298': 0.0, 'mass': 97.907, 'phase': 'HCP_A3'}, 'TE': {'H298': 6121.2, 'S298': 49.497, 'mass': 127.6, 'phase': 'HEXAGONAL_A8'}, 'TH': {'H298': 0.0, 'S298': 0.0, 'mass': 232.04, 'phase': 'FCC_A1'}, 'TI': {'H298': 4810.0, 'S298': 30.648, 'mass': 47.88, 'phase': 'HCP_A3'}, 'TL': {'H298': 6828.3, 'S298': 64.183, 'mass': 204.38, 'phase': 'HCP_A3'}, 'TM': {'H298': 7397.3, 'S298': 74.015, 'mass': 168.93, 'phase': 'HCP_A3'}, 'U': {'H298': 0.0, 'S298': 0.0, 'mass': 238.03, 'phase': 'ORTHORHOMBIC_A20'}, 'V': {'H298': 4507.0, 'S298': 30.89, 'mass': 50.941, 'phase': 'BCC_A2'}, 'VA': {'H298': 0.0, 'S298': 0.0, 'mass': 0.0, 'phase': 'VACUUM'}, 'W': {'H298': 4970.0, 'S298': 32.62, 'mass': 183.85, 'phase': 'BCC_A2'}, 'Y': {'H298': 0.0, 'S298': 0.0, 'mass': 88.906, 'phase': 'HCP_A3'}, 'YB': {'H298': 0.0, 'S298': 0.0, 'mass': 173.04, 'phase': 'FCC_A1'}, 'ZN': {'H298': 5656.8, 'S298': 41.631, 'mass': 65.39, 'phase': 'HCP_A3'}, 'ZR': {'H298': 5566.3, 'S298': 39.181, 'mass': 91.224, 'phase': 'HCP_A3'}}, 'SGTE91Stable': {'AG': Piecewise((-3.98587e-7*T**3 - 0.001790585*T**2 - 23.8463314*T*log(T) + 118.202013*T - 7209.512 - 12011/T, (T >= 298.15) & (T < 1234.93)), (-33.472*T*log(T) + 190.266404*T - 15095.252 + 1.411773e+29/T**9, (T >= 1234.93) & (T < 3000.0)), (0, True)), 'AL': Piecewise((-8.77664e-7*T**3 - 0.001884662*T**2 - 24.3671976*T*log(T) + 137.093038*T - 7976.15 + 74092/T, (T >= 298.15) & (T < 700.0)), (-5.764227e-6*T**3 + 0.018531982*T**2 - 38.5844296*T*log(T) + 223.048446*T - 11276.24 + 74092/T, (T >= 700.0) & (T < 933.47)), (-31.748192*T*log(T) + 188.684153*T - 11278.378 - 1.230524e+28/T**9, (T >= 933.47) & (T < 2900.0)), (0, True)), 'AM': Piecewise((-5.41038e-7*T**3 - 0.00559955*T**2 - 21.1868*T*log(T) + 89.645685*T - 6639.201 - 30424/T, (T >= 298.15) & (T < 1329.0)), (-41.84*T*log(T) + 241.107269*T - 21702.938, (T >= 1329.0) & (T < 3000.0)), (0, True)), 'AS': Piecewise((-0.00271613*T**2 - 23.3144*T*log(T) + 122.211069*T - 7270.447 + 11600/T, (T >= 298.15) & (T < 1090.0)), (-29.216037*T*log(T) + 163.457433*T - 10454.913, (T >= 1090.0) & (T < 1200.0)), (0, True)), 'AU': Piecewise((3.79625e-7*T**3 - 0.00385924*T**2 - 22.75455*T*log(T) + 106.830098*T - 6938.856 - 25097/T, (T >= 298.15) & (T < 929.4)), (-1.1518713e-5*T**3 + 0.08756015*T**2 - 155.706745*T*log(T) + 1021.69543*T - 93586.481 + 10637210/T, (T >= 929.4) & (T < 1337.33)), (8.923844e-6*T**3 - 0.118216828*T**2 + 263.252259*T*log(T) - 2016.37825*T + 314067.829 - 67999832/T, (T >= 1337.33) & (T < 1735.8)), (-30.9616*T*log(T) + 165.272524*T - 12133.783, (T >= 1735.8) & (T < 3200.0)), (0, True)), 'B': Piecewise((6.18878e-7*T**3 - 0.006864515*T**2 - 15.6641*T*log(T) + 107.111864*T - 7735.284 + 370843/T, (T >= 298.15) & (T < 1100.0)), (-2.556e-8*T**3 - 0.00079809*T**2 - 26.6047*T*log(T) + 184.801744*T - 16649.474 + 1748270/T, (T >= 1100.0) & (T < 2348.0)), (1.34719e-7*T**3 - 0.00159488*T**2 - 31.5957527*T*log(T) + 231.336244*T - 36667.582 + 11205883/T, (T >= 2348.0) & (T < 3000.0)), (-31.4*T*log(T) + 222.396264*T - 21530.653, (T >= 3000.0) & (T < 6000.0)), (0, True)), 'BA': Piecewise((-9.5e-11*T**3 - 0.0018314*T**2 - 42.889*T*log(T) + 233.78606*T - 17685.226 + 705880/T, (T >= 298.15) & (T < 1000.0)), (-1.051353e-6*T**3 + 0.019504772*T**2 - 94.2824199*T*log(T) + 608.188389*T - 64873.614 + 8220192/T, (T >= 1000.0) & (T < 2995.0)), (-32.2*T*log(T) + 136.780042*T + 8083.889, (T >= 2995.0) & (T < 4000.0)), (0, True)), 'BE': Piecewise((-1.60413e-7*T**3 - 0.00284715*T**2 - 21.204*T*log(T) + 137.560219*T - 8553.651 + 293690/T, (T >= 298.15) & (T < 1527.0)), (-1.119065e-6*T**3 + 0.021078651*T**2 - 103.9843*T*log(T) + 772.405844*T - 121305.858 + 27251743/T, (T >= 1527.0) & (T < 3000.0)), (0, True)), 'BI': Piecewise((-8.381598e-6*T**3 + 0.012338888*T**2 - 28.4096529*T*log(T) + 128.418925*T - 7817.776, (T >= 298.15) & (T < 544.55)), (1.3499885e-5*T**3 - 0.075311163*T**2 + 51.8556592*T*log(T) - 393.650351*T + 30208.022 - 3616168/T + 1.66145e+25/T**9, (T >= 544.55) & (T < 800.0)), (-1.046e-6*T**3 + 0.0074266*T**2 - 35.9824*T*log(T) + 182.548971*T - 11045.664 + 1.66145e+25/T**9, (T >= 800.0) & (T < 1200.0)), (-27.196*T*log(T) + 124.77144*T - 7581.312 + 1.66145e+25/T**9, (T >= 1200.0) & (T < 3000.0)), (0, True)), 'C': Piecewise((-0.0004723*T**2 - 24.3*T*log(T) + 170.73*T - 17368.441 + 2562600/T - 264300000.0/T**2 + 12000000000.0/T**3, (T >= 298.15) & (T < 6000.0)), (0, True)), 'CA': Piecewise((-0.01110455*T**2 - 16.3138*T*log(T) + 72.794266*T - 4955.062 - 133574/T, (T >= 298.15) & (T < 1115.0)), (-1.2438e-6*T**3 + 0.023733814*T**2 - 114.292247*T*log(T) + 799.982066*T - 107304.428 + 18245540/T, (T >= 1115.0) & (T < 3000.0)), (0, True)), 'CD': Piecewise((-0.006273908*T**2 - 22.0442408*T*log(T) + 99.506198*T - 7083.469 - 6966/T, (T >= 298.15) & (T < 594.22)), (-8.99604e-7*T**3 + 0.008832011*T**2 - 45.1611543*T*log(T) + 256.812233*T - 20064.971 + 1241290/T, (T >= 594.22) & (T < 1500.0)), (-29.7064*T*log(T) + 148.20548*T - 9027.489, (T >= 1500.0) & (T < 1600.0)), (0, True)), 'CE': Piecewise((-3.20773e-7*T**3 - 0.0067103*T**2 - 22.3664*T*log(T) + 84.23022*T - 7160.519 - 18117/T, (T >= 298.15) & (T < 1000.0)), (-1.930297e-6*T**3 + 0.026046487*T**2 - 101.32248*T*log(T) + 659.4604*T - 79678.506 + 11531707/T, (T >= 1000.0) & (T < 2000.0)), (-37.6978*T*log(T) + 190.370192*T - 14198.639, (T >= 2000.0) & (T < 4000.0)), (0, True)), 'CO': Piecewise((-1.7348e-7*T**3 - 0.002654739*T**2 - 25.0861*T*log(T) + 133.36601*T + 310.241 + 72527/T, (T >= 298.15) & (T < 1768.0)), (-40.5*T*log(T) + 253.28374*T - 17197.666 + 9.3488e+30/T**9, (T >= 1768.0) & (T < 6000.0)), (0, True)), 'CR': Piecewise((-1.47721e-6*T**3 + 0.00189435*T**2 - 26.908*T*log(T) + 157.48*T - 8856.94 + 139250/T, (T >= 298.15) & (T < 2180.0)), (-50*T*log(T) + 344.18*T - 34869.344 - 2.88526e+32/T**9, (T >= 2180.0) & (T < 6000.0)), (0, True)), 'CS': Piecewise((-0.000127907669*T**3 + 0.2029422*T**2 - 90.5212584*T*log(T) + 436.899787*T - 17373.82 + 245245/T, (T >= 200.0) & (T < 301.59)), (-4.074846e-6*T**3 + 0.02043269*T**2 - 46.7273304*T*log(T) + 218.689955*T - 13553.817 + 181528/T + 7.8016e+21/T**9, (T >= 301.59) & (T < 2000.0)), (0, True)), 'CU': Piecewise((1.29223e-7*T**3 - 0.00265684*T**2 - 24.112392*T*log(T) + 130.485235*T - 7770.458 + 52478/T, (T >= 298.15) & (T < 1357.77)), (-31.38*T*log(T) + 183.803828*T - 13542.026 + 3.64167e+29/T**9, (T >= 1357.77) & (T < 3200.0)), (0, True)), 'DY': Piecewise((-5.86914125e-7*T**3 - 0.000761683657*T**2 - 26.3917167*T*log(T) + 102.307412*T - 7937.16586 + 4010.90565/T, (T >= 100.0) & (T < 1000.0)), (-3.49702836e-6*T**3 + 0.0166909801*T**2 - 43.8283359*T*log(T) + 214.012934*T - 13733.328 + 0.0173619874/T, (T >= 1000.0) & (T < 1654.15)), (-2.76169148e-6*T**3 + 0.0578301681*T**2 - 272.123952*T*log(T) + 2032.1415*T - 404681.371 + 109616238.0/T, (T >= 1654.15) & (T < 3000.0)), (0, True)), 'ER': Piecewise((-9.52557e-7*T**3 + 0.000995792*T**2 - 28.3846744*T*log(T) + 116.698964*T - 8489.136 + 9581/T, (T >= 298.15) & (T < 1802.0)), (-3.041405e-6*T**3 + 0.065950553*T**2 - 298.135131*T*log(T) + 2233.10212*T - 445688.206 + 123973199.0/T, (T >= 1802.0) & (T < 3200.0)), (0, True)), 'EU': Piecewise((-4.006564e-6*T**3 + 0.00931735*T**2 - 32.8418896*T*log(T) + 135.836737*T - 9864.965 + 102717/T, (T >= 298.15) & (T < 1095.0)), (-8.809866e-6*T**3 + 0.114530917*T**2 - 309.357101*T*log(T) + 2174.73304*T - 287423.476 + 48455305/T, (T >= 1095.0) & (T < 1900.0)), (0, True)), 'FE': Piecewise((-5.8927e-8*T**3 - 0.00439752*T**2 - 23.5143*T*log(T) + 124.134*T + 1225.7 + 77359/T, (T >= 298.15) & (T < 1811.0)), (-46*T*log(T) + 299.31255*T - 25383.581 + 2.29603e+31/T**9, (T >= 1811.0) & (T < 6000.0)), (0, True)), 'GA': Piecewise((-0.000118575257*T**3 + 0.227155636*T**2 - 108.228783*T*log(T) + 585.263691*T - 21312.331 + 439954/T, (T >= 200.0) & (T < 302.91)), (-4.0173e-8*T**3 + 0.0001506*T**2 - 26.0692906*T*log(T) + 132.73019*T - 7055.643 - 118332/T + 1.64547e+23/T**9, (T >= 302.91) & (T < 4000.0)), (0, True)), 'GD': Piecewise((-3.14674076e-7*T**3 - 0.00285240521*T**2 - 24.7214131*T*log(T) + 97.13101*T - 6834.5855 - 8665.73348/T, (T >= 200.0) & (T < 1000.0)), (-6.61211607e-7*T**3 - 0.00185225011*T**2 - 24.6598297*T*log(T) + 95.6919924*T - 6483.25362, (T >= 1000.0) & (T < 1508.15)), (-6.39165948e-7*T**3 + 0.0150644246*T**2 - 101.800197*T*log(T) + 699.125537*T - 123124.992 + 29356890.3/T, (T >= 1508.15) & (T < 3600.0)), (0, True)), 'GE': Piecewise((-1.513694e-6*T**3 + 0.005568297*T**2 - 29.5337682*T*log(T) + 165.635573*T - 9486.153 + 163298/T, (T >= 298.15) & (T < 900.0)), (-0.003672527*T**2 - 19.8536239*T*log(T) + 102.86087*T - 5689.239, (T >= 900.0) & (T < 1211.4)), (-27.6144*T*log(T) + 156.708024*T - 9548.204 - 8.59809e+28/T**9, (T >= 1211.4) & (T < 3200.0)), (0, True)), 'HF': Piecewise((-4.77e-10*T**3 - 0.004146145*T**2 - 22.7075*T*log(T) + 110.744026*T - 6987.297 - 22590/T, (T >= 298.15) & (T < 2506.0)), (-7.575759e-6*T**3 + 0.1735215*T**2 - 787.536383*T*log(T) + 6193.60999*T - 1446776.33 + 501742495.0/T, (T >= 2506.0) & (T < 3000.0)), (0, True)), 'HG': Piecewise((0.00118398213*T**3 - 2.0282337*T**2 + 618.193308*T*log(T) - 3348.19466*T + 82356.855 - 2366612/T, (T >= 200.0) & (T < 234.32)), (-3.20695e-6*T**3 + 0.0097977*T**2 - 32.257*T*log(T) + 135.232291*T - 8961.207 + 6670/T, (T >= 234.32) & (T < 400.0)), (-1.077802e-6*T**3 + 0.00318535*T**2 - 28.414*T*log(T) + 112.33345*T - 7970.627 - 41095/T, (T >= 400.0) & (T < 700.0)), (8.737e-9*T**3 - 0.00166775*T**2 - 24.87*T*log(T) + 90.797305*T - 7161.338 - 27495/T, (T >= 700.0) & (T < 2000.0)), (0, True)), 'HO': Piecewise((2.375467e-6*T**3 - 0.00827315*T**2 - 23.4879*T*log(T) + 86.593171*T - 7612.429, (T >= 298.15) & (T < 600.0)), (-4.829733e-6*T**3 + 0.01820065*T**2 - 39.6932*T*log(T) + 182.475691*T - 10917.688, (T >= 600.0) & (T < 900.0)), (3.233133e-6*T**3 - 0.0424634*T**2 + 48.0595*T*log(T) - 421.474473*T + 46646.188 - 7185900/T, (T >= 900.0) & (T < 1200.0)), (-1.112352e-6*T**3 - 0.01082725*T**2 + 8.28608*T*log(T) - 156.162846*T + 27786.061 - 6183850/T, (T >= 1200.0) & (T < 1703.0)), (-6.824652e-6*T**3 + 0.139111904*T**2 - 558.950682*T*log(T) + 4248.37906*T - 825364.662 + 219952973.0/T, (T >= 1703.0) & (T < 3000.0)), (0, True)), 'IN': Piecewise((-2.120321e-6*T**3 - 0.00572566*T**2 - 21.8386*T*log(T) + 92.338115*T - 6978.89 - 22906/T, (T >= 298.15) & (T < 429.75)), (-8.367e-8*T**3 + 0.00054607*T**2 - 27.4562*T*log(T) + 124.476588*T - 7033.516 - 211708/T + 3.53116e+22/T**9, (T >= 429.75) & (T < 3800.0)), (0, True)), 'IR': Piecewise((-0.003091976*T**2 - 22.7944*T*log(T) + 118.780119*T - 6936.288 - 20083/T, (T >= 298.15) & (T < 1215.0)), (-4.7969e-7*T**3 - 26.085*T*log(T) + 140.066697*T - 8123.73, (T >= 1215.0) & (T < 2719.0)), (1.844977e-6*T**3 - 0.047176402*T**2 + 152.498874*T*log(T) - 1258.35297*T + 290529.037 - 92987250/T, (T >= 2719.0) & (T < 4000.0)), (0, True)), 'K': Piecewise((-8.4949147e-5*T**3 + 0.146211135*T**2 - 77.0571464*T*log(T) + 389.624197*T - 16112.929 + 243385/T, (T >= 200.0) & (T < 336.53)), (-2.64387e-6*T**3 + 0.012167386*T**2 - 39.2885968*T*log(T) + 192.586544*T - 11122.441 + 43251/T + 1.19223e+22/T**9, (T >= 336.53) & (T < 2200.0)), (0, True)), 'LA': Piecewise((-0.001295165*T**2 - 26.34*T*log(T) + 120.284604*T - 7968.403, (T >= 298.15) & (T < 550.0)), (6.8932e-7*T**3 - 0.008371705*T**2 - 17.1659411*T*log(T) + 59.06113*T - 3381.413 - 399448/T, (T >= 550.0) & (T < 2000.0)), (-34.3088*T*log(T) + 181.390071*T - 15608.882, (T >= 2000.0) & (T < 4000.0)), (0, True)), 'LI': Piecewise((-1.9869816e-5*T**3 + 0.035466931*T**2 - 38.940488*T*log(T) + 217.637482*T - 10583.817 + 159994/T, (T >= 200.0) & (T < 453.6)), (-0.000571066077*T**3 + 2.25832944*T**2 - 1702.88865*T*log(T) + 10547.8799*T - 559579.123 + 33885874/T, (T >= 453.6) & (T < 500.0)), (-4.38058e-7*T**3 + 0.002633221*T**2 - 31.2283718*T*log(T) + 179.278285*T - 9062.994 - 102387/T, (T >= 500.0) & (T < 3000.0)), (0, True)), 'LU': Piecewise((-1.790717e-6*T**3 + 0.00519165*T**2 - 29.812*T*log(T) + 146.536283*T - 8788.329 + 39723/T, (T >= 298.15) & (T < 700.0)), (-1.50147e-6*T**3 + 0.00371416*T**2 - 29.0095*T*log(T) + 142.327643*T - 9043.057 + 141549/T, (T >= 700.0) & (T < 1700.0)), (-0.0119001*T**2 - 1.83986*T*log(T) - 46.91844*T + 6940.092, (T >= 1700.0) & (T < 1936.0)), (-1.661174e-6*T**3 + 0.041800748*T**2 - 239.019502*T*log(T) + 1829.37943*T - 404023.691 + 124825465.0/T, (T >= 1936.0) & (T < 3700.0)), (0, True)), 'MG': Piecewise((-1.393669e-6*T**3 + 0.0004858*T**2 - 26.1849782*T*log(T) + 143.675547*T - 8367.34 + 78950/T, (T >= 298.15) & (T < 923.0)), (-34.3088*T*log(T) + 204.716215*T - 14130.185 + 1.038192e+28/T**9, (T >= 923.0) & (T < 3000.0)), (0, True)), 'MN': Piecewise((-0.00734768*T**2 - 23.4582*T*log(T) + 130.059*T - 8115.28 + 69827/T, (T >= 298.15) & (T < 1519.0)), (-48*T*log(T) + 312.2648*T - 28733.41 + 1.656847e+30/T**9, (T >= 1519.0) & (T < 2000.0)), (0, True)), 'MO': Piecewise((-1.30927e-10*T**4 + 5.66283e-7*T**3 - 0.003443396*T**2 - 23.56414*T*log(T) + 131.9197*T - 7746.302 + 65812/T, (T >= 298.15) & (T < 2896.0)), (-42.63829*T*log(T) + 283.559746*T - 30556.41 - 4.849315e+33/T**9, (T >= 2896.0) & (T < 5000.0)), (0, True)), 'N': Piecewise((2.681e-9*T**3 - 0.00176686*T**2 - 12.7819*T*log(T) - 9.45425*T - 3750.675 - 32374/T, (T >= 298.15) & (T < 950.0)), (3.0097e-8*T**3 - 0.00065107*T**2 - 16.3699*T*log(T) + 17.2003*T - 7358.85 + 563070/T, (T >= 950.0) & (T < 3350.0)), (-8.333e-9*T**3 + 0.000239754*T**2 - 20.4695*T*log(T) + 50.26*T - 16392.8 + 4596375/T, (T >= 3350.0) & (T < 6000.0)), (0, True)), 'NA': Piecewise((-4.3638283e-5*T**3 + 0.072306633*T**2 - 51.0393608*T*log(T) + 260.548732*T - 11989.434 + 132154/T, (T >= 200.0) & (T < 370.87)), (-1.70664e-6*T**3 + 0.009745854*T**2 - 38.1198801*T*log(T) + 199.619999*T - 11009.884 + 34342/T + 1.65071e+23/T**9, (T >= 370.87) & (T < 2300.0)), (0, True)), 'NB': Piecewise((-3.5012e-7*T**3 + 0.000203475*T**2 - 26.4711*T*log(T) + 142.045475*T - 8519.353 + 93399/T, (T >= 298.15) & (T < 2750.0)), (-41.77*T*log(T) + 271.720843*T - 37669.3 + 1.528238e+32/T**9, (T >= 2750.0) & (T < 6000.0)), (0, True)), 'ND': Piecewise((-2.6923e-6*T**3 + 0.000556125*T**2 - 27.0858*T*log(T) + 111.10239*T - 8402.93 + 34887/T, (T >= 298.15) & (T < 900.0)), (-1.802e-6*T**3 - 0.00420402*T**2 - 22.7536*T*log(T) + 83.662617*T - 6984.083, (T >= 900.0) & (T < 1128.0)), (-6.048207e-6*T**3 + 0.078615997*T**2 - 238.182873*T*log(T) + 1673.04075*T - 225610.846 + 38810350/T, (T >= 1128.0) & (T < 1799.0)), (-48.7854*T*log(T) + 276.257088*T - 25742.331, (T >= 1799.0) & (T < 1800.0)), (0, True)), 'NI': Piecewise((-0.0048407*T**2 - 22.096*T*log(T) + 117.854*T - 5179.159, (T >= 298.15) & (T < 1728.0)), (-43.1*T*log(T) + 279.135*T - 27840.655 + 1.12754e+31/T**9, (T >= 1728.0) & (T < 3000.0)), (0, True)), 'NP': Piecewise((-0.04127725*T**2 + 4.0543*T*log(T) - 57.531347*T + 241.888 - 402857/T, (T >= 298.15) & (T < 553.0)), (-2.483917e-6*T**3 + 0.0284592*T**2 - 102.523*T*log(T) + 664.27337*T - 57015.112 + 4796910/T, (T >= 553.0) & (T < 1799.0)), (-45.3964*T*log(T) + 255.780866*T - 12092.736, (T >= 1799.0) & (T < 4000.0)), (0, True)), 'O': Piecewise((6.61845833e-7*T**3 - 0.005098875*T**2 - 11.1355*T*log(T) - 25.503038*T - 3480.87 - 38365/T, (T >= 298.15) & (T < 1000.0)), (6.781e-9*T**3 - 0.0005957975*T**2 - 16.8138*T*log(T) + 12.659879*T - 6568.763 + 262905/T, (T >= 1000.0) & (T < 3300.0)), (1.0721e-8*T**3 - 0.000425243*T**2 - 18.9536*T*log(T) + 31.259624*T - 13986.728 + 4383200/T, (T >= 3300.0) & (T < 6000.0)), (0, True)), 'OS': Piecewise((-0.00190427*T**2 - 23.5710242*T*log(T) + 126.369531*T - 7196.978, (T >= 298.15) & (T < 3306.0)), (1.173861e-6*T**3 - 0.042489827*T**2 + 224.998034*T*log(T) - 1935.2137*T + 644910.07 - 312569031.0/T, (T >= 3306.0) & (T < 5500.0)), (0, True)), 'P': Piecewise((-0.000104022667*T**3 + 0.290708*T**2 - 178.426*T*log(T) + 1026.69389*T - 43821.799 + 1632695/T, (T >= 250.0) & (T < 317.3)), (-2.2829e-7*T**3 + 0.001715669*T**2 - 28.7335301*T*log(T) + 152.341487*T - 9587.448 + 172966/T, (T >= 317.3) & (T < 1000.0)), (-26.326*T*log(T) + 135.876831*T - 8093.075, (T >= 1000.0) & (T < 3000.0)), (0, True)), 'PA': Piecewise((-0.00621325*T**2 - 23.9116*T*log(T) + 111.973215*T - 7681.561, (T >= 298.15) & (T < 1443.0)), (1.884933e-6*T**3 - 0.0263416*T**2 + 16.305*T*log(T) - 177.320253*T + 27955.763 - 5908900/T, (T >= 1443.0) & (T < 2176.0)), (-47.2792*T*log(T) + 288.308639*T - 29949.683, (T >= 2176.0) & (T < 4000.0)), (0, True)), 'PB': Piecewise((-2.4395e-7*T**3 - 0.00365895*T**2 - 24.5242231*T*log(T) + 101.700244*T - 7650.085, (T >= 298.15) & (T < 600.61)), (0.00154613*T**2 - 32.4913959*T*log(T) + 154.243182*T - 10531.095 + 8.05448e+25/T**9, (T >= 600.61) & (T < 1200.0)), (9.8144e-8*T**3 - 0.002882943*T**2 - 18.9640637*T*log(T) + 53.139072*T + 4157.616 - 2696755/T + 8.05448e+25/T**9, (T >= 1200.0) & (T < 2100.0)), (0, True)), 'PD': Piecewise((-1.919875e-6*T**3 + 0.007120975*T**2 - 32.211*T*log(T) + 176.076315*T - 10204.027 + 168687/T, (T >= 298.15) & (T < 900.0)), (1.91115e-7*T**3 - 0.00717522*T**2 - 13.5708*T*log(T) + 49.659892*T + 917.062 - 1112465/T, (T >= 900.0) & (T < 1828.0)), (-6.2811e-8*T**3 + 0.002091396*T**2 - 54.2067086*T*log(T) + 370.102147*T - 67161.018 + 18683526/T, (T >= 1828.0) & (T < 4000.0)), (0, True)), 'PR': Piecewise((-2.5184333e-5*T**3 + 0.072929*T**2 - 68.9176*T*log(T) + 356.587384*T - 18803.379 + 507385/T, (T >= 298.15) & (T < 500.0)), (-1.22951e-6*T**3 - 0.00497126*T**2 - 22.8909*T*log(T) + 82.427384*T - 7246.848, (T >= 500.0) & (T < 800.0)), (1.5592233e-5*T**3 - 0.1288205*T**2 + 146.764*T*log(T) - 1073.55111*T + 95411.023 - 11588800/T, (T >= 800.0) & (T < 1068.0)), (-3.0994702e-5*T**3 + 0.305181506*T**2 - 606.120311*T*log(T) + 4234.33311*T - 481663.131 + 70926840/T, (T >= 1068.0) & (T < 1204.0)), (-42.9697*T*log(T) + 227.685155*T - 20014.678, (T >= 1204.0) & (T < 3800.0)), (0, True)), 'PT': Piecewise((-2.0138e-8*T**3 - 0.00248297*T**2 - 24.5526*T*log(T) + 124.388275*T - 7595.631 + 7974/T, (T >= 298.15) & (T < 1300.0)), (-6.56946e-7*T**3 + 0.002321665*T**2 - 30.2527*T*log(T) + 161.529615*T - 9253.174 - 272106/T, (T >= 1300.0) & (T < 2041.5)), (-7.59259e-7*T**3 + 0.020454938*T**2 - 136.192996*T*log(T) + 1019.35892*T - 222048.216 + 71539020/T, (T >= 2041.5) & (T < 4000.0)), (0, True)), 'PU': Piecewise((-0.02241*T**2 - 18.1258*T*log(T) + 80.301382*T - 7396.309, (T >= 298.15) & (T < 400.0)), (2.63443e-7*T**3 - 0.00134493*T**2 - 42.4187*T*log(T) + 236.786603*T - 16605.962 + 579325/T, (T >= 400.0) & (T < 944.0)), (-42.248*T*log(T) + 232.961553*T - 14462.156, (T >= 944.0) & (T < 3000.0)), (0, True)), 'RB': Piecewise((-0.000152236932*T**3 + 0.26277612*T**2 - 115.282589*T*log(T) + 583.580988*T - 21669.733 + 385754/T, (T >= 200.0) & (T < 312.46)), (-4.6822e-7*T**3 + 0.000412369*T**2 - 29.1775424*T*log(T) + 117.050578*T - 7823.397 - 126310/T - 5.55029e+22/T**9, (T >= 312.46) & (T < 900.0)), (-4.829082e-6*T**3 + 0.033795632*T**2 - 77.7006456*T*log(T) + 450.974149*T - 39488.142 + 3778006/T - 5.55029e+22/T**9, (T >= 900.0) & (T < 1600.0)), (-8.61653e-6*T**3 + 0.08161687*T**2 - 191.262774*T*log(T) + 1287.78947*T - 159742.511 + 27738456/T - 5.55029e+22/T**9, (T >= 1600.0) & (T < 2100.0)), (0, True)), 'RE': Piecewise((1.92818e-7*T**3 - 0.00253505*T**2 - 24.348*T*log(T) + 128.421589*T - 7695.279 + 32915/T, (T >= 298.15) & (T < 1200.0)), (-2.81835e-7*T**3 + 0.00224565*T**2 - 33.586*T*log(T) + 194.667426*T - 15775.998 + 1376270/T, (T >= 1200.0) & (T < 2400.0)), (-7.88955e-7*T**3 + 0.01184945*T**2 - 67.956*T*log(T) + 462.110749*T - 70882.739 + 18075200/T, (T >= 2400.0) & (T < 3458.0)), (1.053726e-6*T**3 - 0.033764567*T**2 + 140.831655*T*log(T) - 1211.37186*T + 346325.888 - 134548866.0/T, (T >= 3458.0) & (T < 5000.0)), (-49.519*T*log(T) + 346.997842*T - 78564.296, (T >= 5000.0) & (T < 6000.0)), (0, True)), 'RH': Piecewise((-1.68032e-7*T**3 - 0.003424186*T**2 - 24.0178336*T*log(T) + 132.020923*T - 7848.828 + 55846/T, (T >= 298.15) & (T < 1200.0)), (-1.512774e-6*T**3 + 0.00966345*T**2 - 48.3766632*T*log(T) + 305.771019*T - 28367.852 + 3348162/T, (T >= 1200.0) & (T < 2237.0)), (-5.3978814e-5*T**3 + 1.04921361*T**2 - 3874.21058*T*log(T) + 30151.6342*T - 6237470.48 + 1880362180.0/T, (T >= 2237.0) & (T < 2450.0)), (-50.58456*T*log(T) + 344.889895*T - 44863.489, (T >= 2450.0) & (T < 2500.0)), (0, True)), 'RU': Piecewise((1.7641e-7*T**3 - 0.004062566*T**2 - 22.9143287*T*log(T) + 127.866233*T - 7561.873 + 56377/T, (T >= 298.15) & (T < 1500.0)), (-1.952433e-6*T**3 + 0.018726245*T**2 - 72.3241219*T*log(T) + 489.516214*T - 59448.103 + 11063885/T, (T >= 1500.0) & (T < 2607.0)), (-0.000240245985*T**3 + 5.221639*T**2 - 21329.705*T*log(T) + 168610.517*T - 38588773 + 13082992600.0/T, (T >= 2607.0) & (T < 2740.0)), (-51.8816*T*log(T) + 364.482314*T - 55768.304, (T >= 2740.0) & (T < 4500.0)), (0, True)), 'S': Piecewise((7.754333e-6*T**3 - 0.026529*T**2 - 11.007*T*log(T) + 55.417762*T - 5228.956, (T >= 298.15) & (T < 368.3)), (1.402558e-6*T**3 - 0.010895125*T**2 - 17.941839*T*log(T) + 94.692922*T - 6513.769 + 39910/T, (T >= 368.3) & (T < 1300.0)), (0, True)), 'SB': Piecewise((-3.003415e-6*T**3 + 0.007748768*T**2 - 30.5130752*T*log(T) + 156.154689*T - 9242.858 + 100625/T, (T >= 298.15) & (T < 903.78)), (-31.38*T*log(T) + 169.485872*T - 11738.83 + 1.616849e+27/T**9, (T >= 903.78) & (T < 2000.0)), (0, True)), 'SC': Piecewise((-1.64531e-6*T**3 + 0.00321892*T**2 - 28.1882*T*log(T) + 153.48097*T - 8689.547 + 72177/T, (T >= 298.15) & (T < 800.0)), (-8.59345e-7*T**3 - 0.000573295*T**2 - 24.9132*T*log(T) + 132.759582*T - 7511.295, (T >= 800.0) & (T < 1608.0)), (8.7398e-6*T**3 - 0.117529396*T**2 + 241.441051*T*log(T) - 1817.92245*T + 261143.04 - 50607159/T, (T >= 1608.0) & (T < 2000.0)), (-44.2249*T*log(T) + 286.474338*T - 30515.246, (T >= 2000.0) & (T < 3200.0)), (0, True)), 'SE': Piecewise((-1.5318461e-5*T**3 + 0.02424314*T**2 - 33.6527*T*log(T) + 174.205877*T - 9376.371 + 102249/T, (T >= 298.15) & (T < 494.0)), (-5.611026e-6*T**3 + 0.037144892*T**2 - 81.2006585*T*log(T) + 507.111538*T - 37546.134 + 2614263/T, (T >= 494.0) & (T < 800.0)), (-35.1456*T*log(T) + 197.770166*T - 12193.47, (T >= 800.0) & (T < 1000.0)), (0, True)), 'SI': Piecewise((-3.552e-9*T**3 - 0.001912904*T**2 - 22.8317533*T*log(T) + 137.236859*T - 8162.609 + 176667/T, (T >= 298.15) & (T < 1687.0)), (-27.196*T*log(T) + 167.281367*T - 9457.642 - 4.20369e+30/T**9, (T >= 1687.0) & (T < 3600.0)), (0, True)), 'SM': Piecewise((1.010345e-5*T**3 - 0.050254*T**2 - 1.6485*T*log(T) - 32.10748*T - 3872.013 - 82168/T, (T >= 298.15) & (T < 700.0)), (-7.538383e-6*T**3 + 0.0474522*T**2 - 102.665*T*log(T) + 627.869894*T - 50078.215 + 3861770/T, (T >= 700.0) & (T < 1190.0)), (2.7512152e-5*T**3 - 0.254986338*T**2 + 381.41982*T*log(T) - 2744.50976*T + 289719.819 - 40102102/T, (T >= 1190.0) & (T < 1345.0)), (-50.208*T*log(T) + 282.194375*T - 23056.079, (T >= 1345.0) & (T < 2100.0)), (0, True)), 'SN': Piecewise((-3.192767e-6*T**3 + 0.00051185*T**2 - 25.858*T*log(T) + 122.765451*T - 7958.517 + 18440/T, (T >= 100.0) & (T < 250.0)), (3.121167e-6*T**3 - 0.0188702*T**2 - 15.961*T*log(T) + 65.443315*T - 5855.135 - 61960/T, (T >= 250.0) & (T < 505.08)), (2.623131e-6*T**3 - 0.016814429*T**2 - 8.2590486*T*log(T) + 4.005269*T + 2524.724 - 1081244/T - 1.2307e+25/T**9, (T >= 505.08) & (T < 800.0)), (-28.4512*T*log(T) + 138.99688*T - 8256.959 - 1.2307e+25/T**9, (T >= 800.0) & (T < 3000.0)), (0, True)), 'SR': Piecewise((-1.67477e-7*T**3 - 0.00461225*T**2 - 23.905*T*log(T) + 107.183879*T - 7532.367 - 2055/T, (T >= 298.15) & (T < 820.0)), (1.84189e-7*T**3 - 0.003251266*T**2 - 30.0905432*T*log(T) + 153.196104*T - 13380.102 + 850134/T, (T >= 820.0) & (T < 3000.0)), (0, True)), 'TA': Piecewise((1.70109e-7*T**3 - 0.002623033*T**2 - 23.7592624*T*log(T) + 119.139857*T - 7285.889 - 3293/T, (T >= 298.15) & (T < 1300.0)), (-6.55136e-7*T**3 + 0.006167572*T**2 - 41.137088*T*log(T) + 243.88676*T - 22389.955 + 2429586/T, (T >= 1300.0) & (T < 2500.0)), (1.95033e-7*T**3 - 0.017983376*T**2 + 78.5244752*T*log(T) - 722.59722*T + 229382.886 - 93813648/T, (T >= 2500.0) & (T < 3290.0)), (-1.055148e-6*T**3 + 0.043117795*T**2 - 362.159132*T*log(T) + 2985.49125*T - 1042384.01 + 554714342.0/T, (T >= 3290.0) & (T < 6000.0)), (0, True)), 'TB': Piecewise((-2.5672833e-5*T**3 + 0.0832265*T**2 - 77.5006*T*log(T) + 409.309555*T - 20842.158 + 562430/T, (T >= 298.15) & (T < 600.0)), (-8.05838e-7*T**3 - 0.002757005*T**2 - 25.8659*T*log(T) + 102.61162*T - 8772.606 + 172355/T, (T >= 600.0) & (T < 1200.0)), (-1.067632e-6*T**3 - 0.001676335*T**2 - 25.9584*T*log(T) + 101.7776*T - 7944.942, (T >= 1200.0) & (T < 1562.0)), (-2.044697e-6*T**3 + 0.041615159*T**2 - 200.215695*T*log(T) + 1456.04268*T - 265240.309 + 65043790/T, (T >= 1562.0) & (T < 3000.0)), (0, True)), 'TC': Piecewise((-0.002954747*T**2 - 24.3394*T*log(T) + 132.5101*T - 7947.794 + 63855/T, (T >= 298.15) & (T < 2430.0)), (-47*T*log(T) + 318.286*T - 47759.99 + 6.63829e+32/T**9, (T >= 2430.0) & (T < 4000.0)), (0, True)), 'TE': Piecewise((-5.240417e-6*T**3 + 0.01583435*T**2 - 35.6687*T*log(T) + 183.372894*T - 10544.679 + 155015/T, (T >= 298.15) & (T < 722.66)), (5.006367e-6*T**3 - 0.0362361*T**2 + 13.004*T*log(T) - 129.265373*T + 9160.595 - 1286810/T, (T >= 722.66) & (T < 1150.0)), (-32.5596*T*log(T) + 174.901226*T - 12781.349, (T >= 1150.0) & (T < 1600.0)), (0, True)), 'TH': Piecewise((-5.2883e-7*T**3 - 0.00236725*T**2 - 24.841*T*log(T) + 117.022775*T - 7732.08 + 13010/T, (T >= 298.15) & (T < 1633.0)), (2.36893e-7*T**3 - 0.00358025*T**2 - 39.107*T*log(T) + 237.654918*T - 37352.871 + 7981000/T, (T >= 1633.0) & (T < 2900.0)), (-46.024*T*log(T) + 283.979845*T - 33353.313, (T >= 2900.0) & (T < 4000.0)), (0, True)), 'TI': Piecewise((1.06716e-7*T**3 - 0.004777975*T**2 - 23.9933*T*log(T) + 133.615208*T - 8059.921 + 72636/T, (T >= 298.15) & (T < 900.0)), (-9.0876e-8*T**3 - 0.0042033*T**2 - 23.9887*T*log(T) + 132.988068*T - 7811.815 + 42680/T, (T >= 900.0) & (T < 1155.0)), (2.02715e-7*T**3 - 0.0081465*T**2 - 14.9466*T*log(T) + 66.976538*T + 908.837 - 1477660/T, (T >= 1155.0) & (T < 1941.0)), (-3.04747e-7*T**3 + 0.008204849*T**2 - 87.2182461*T*log(T) + 638.806871*T - 124526.786 + 36699805/T, (T >= 1941.0) & (T < 4000.0)), (0, True)), 'TL': Piecewise((-1.21807e-7*T**3 - 0.0033063*T**2 - 25.2274*T*log(T) + 107.140405*T - 8104.038 + 42058/T, (T >= 200.0) & (T < 577.0)), (-5.19136e-7*T**3 + 0.005228106*T**2 - 38.4130658*T*log(T) + 196.771926*T - 15406.859 + 729665/T, (T >= 577.0) & (T < 1800.0)), (0, True)), 'TM': Piecewise((-3.831156e-6*T**3 + 0.012110965*T**2 - 34.3664974*T*log(T) + 151.037648*T - 10016.715 + 95982/T, (T >= 298.15) & (T < 700.0)), (-3.96694e-7*T**3 + 0.000444753*T**2 - 32.1951269*T*log(T) + 147.957496*T - 14701.965 + 1091664/T, (T >= 700.0) & (T < 1600.0)), (-0.003384563*T**2 - 25.1816969*T*log(T) + 97.98144*T - 8669.227, (T >= 1600.0) & (T < 1818.0)), (1.1689185e-5*T**3 - 0.19093039*T**2 + 534.082763*T*log(T) - 4147.40063*T + 727125.608 - 180382220.0/T, (T >= 1818.0) & (T < 2300.0)), (0, True)), 'U': Piecewise((-4.42605e-6*T**3 + 0.00125156*T**2 - 26.9182*T*log(T) + 130.955151*T - 8407.734 + 38568/T, (T >= 298.15) & (T < 955.0)), (-48.66*T*log(T) + 292.121093*T - 22521.8, (T >= 955.0) & (T < 3000.0)), (0, True)), 'V': Piecewise((1.2175e-7*T**3 - 0.003098*T**2 - 24.134*T*log(T) + 133.346053*T - 7930.43 + 69460/T, (T >= 298.15) & (T < 790.0)), (-6.8e-7*T**3 + 6.25e-5*T**2 - 25.9*T*log(T) + 143.291093*T - 7967.842, (T >= 790.0) & (T < 2183.0)), (-47.43*T*log(T) + 321.140783*T - 41689.864 + 6.44389e+31/T**9, (T >= 2183.0) & (T < 4000.0)), (0, True)), 'W': Piecewise((-5.33e-11*T**4 + 2.07e-7*T**3 - 0.001936*T**2 - 24.1*T*log(T) + 130.4*T - 7646.311 + 44500/T, (T >= 298.15) & (T < 3695.0)), (-54*T*log(T) + 389.362335*T - 82868.801 + 1.528621e+33/T**9, (T >= 3695.0) & (T < 6000.0)), (0, True)), 'Y': Piecewise((-4.17561786e-7*T**3 - 0.00175716414*T**2 - 25.6656992*T*log(T) + 128.572856*T - 8011.09379 + 26911.509/T, (T >= 100.0) & (T < 1000.0)), (-8.2534534e-8*T**3 - 0.0038211802*T**2 - 23.4941827*T*log(T) + 114.497104*T - 7179.74574, (T >= 1000.0) & (T < 1795.15)), (-7.22513088e-8*T**3 + 0.00231774379*T**2 - 56.9527111*T*log(T) + 382.124727*T - 67480.7761 + 18077162.6/T, (T >= 1795.15) & (T < 3700.0)), (0, True)), 'YB': Piecewise((-2.2242e-5*T**3 + 0.04227115*T**2 - 40.0791*T*log(T) + 189.327664*T - 9370.941, (T >= 298.15) & (T < 553.0)), (-0.00256065*T**2 - 26.7591*T*log(T) + 121.065655*T - 8192.154, (T >= 553.0) & (T < 1033.0)), (1.421719e-6*T**3 - 0.017961331*T**2 + 2.7623966*T*log(T) - 89.478241*T + 16034.89 - 3631462/T, (T >= 1033.0) & (T < 2000.0)), (0, True)), 'ZN': Piecewise((-1.264963e-6*T**3 - 0.001712034*T**2 - 23.701314*T*log(T) + 118.470069*T - 7285.787, (T >= 298.15) & (T < 692.68)), (-31.38*T*log(T) + 172.34566*T - 11070.559 + 4.70514e+26/T**9, (T >= 692.68) & (T < 1700.0)), (0, True)), 'ZR': Piecewise((-0.00437791*T**2 - 24.1618*T*log(T) + 125.64905*T - 7827.595 + 34971/T, (T >= 130.0) & (T < 2128.0)), (-42.144*T*log(T) + 262.724183*T - 26085.921 - 1.342896e+31/T**9, (T >= 2128.0) & (T < 6000.0)))}, 'SR2016': {('CU', 'FCC_A1'): Piecewise((GHSERCU, (T >= 1.0) & (T < 10000.0)), (0, True)), ('CU', 'HCP_A3'): Piecewise((-3.38438862938597e-7*T**3 - 0.00121182291077191*T**2 + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 0.321147237334052*T - 10441.4393392344, (T >= 0.01) & (T < 298.15)), (1.29223e-7*T**3 - 0.00265684*T**2 - 24.112392*T*log(T) + 130.685235*T - 7170.458 + 52478/T, (T >= 298.15) & (T < 1357.77)), (-31.38*T*log(T) + 184.003828*T - 12942.0252504739 + 3.64167e+29/T**9, (T >= 1357.77) & (T < 3200.0)), (0, True)), ('CU', 'LIQUID'): Piecewise((-3.40056501515466e-7*T**3 - 0.00121066539331185*T**2 + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 10.033338832193*T + 2379.36422209194, (T >= 0.01) & (T < 298.15)), (-5.8489e-21*T**7 + 1.29223e-7*T**3 - 0.00265684*T**2 - 24.112392*T*log(T) + 120.973331*T + 5650.32106235287 + 52478/T, (T >= 298.15) & (T < 1357.77)), (-31.38*T*log(T) + 173.881484*T + 409.498458129716, (T >= 1357.77) & (T < 3200.0)), (0, True)), ('MG', 'FCC_A1'): Piecewise((-2.18283562784578e-6*T**3 - 6.21802726222479e-5*T**2 + 3.2404446864*T*log(exp(95.82831/T) - 1.0) + 21.6535319868*T*log(exp(247.8675/T) - 1.0) + 0.246565697987779*T - 8158.16393259455, (T >= 0.01) & (T < 298.15)), (-1.393669e-6*T**3 + 0.0004858*T**2 - 26.1849782*T*log(T) + 142.775547*T - 5767.34 + 78950/T, (T >= 298.15) & (T < 922.205302616508)), (-34.3088*T*log(T) + 203.816215*T - 11530.1836392866 + 1.038192e+28/T**9, (T >= 922.205302616508) & (T < 3000.0)), (0, True)), ('MG', 'HCP_A3'): Piecewise((GHSERMG, (T >= 1.0) & (T < 10000.0)), (0, True)), ('MG', 'LIQUID'): Piecewise((-2.2050100179942e-6*T**3 - 4.63131660076452e-5*T**2 + 3.2404446864*T*log(exp(95.82831/T) - 1.0) + 21.6535319868*T*log(exp(247.8675/T) - 1.0) - 7.6943066168765*T - 2555.58510336379, (T >= 0.01) & (T < 298.15)), (-8.0176e-20*T**7 - 1.393669e-6*T**3 + 0.0004858*T**2 - 26.1849782*T*log(T) + 134.838617*T - 165.096999676889 + 78950/T, (T >= 298.15) & (T < 922.205302616508)), (-34.3088*T*log(T) + 195.324057*T - 5439.86911093575, (T >= 922.205302616508) & (T < 10000.0)), (0, True))}, 'SR2016Stable': {'CU': Piecewise((-0.0010514335*T**2 + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 11038.0904080745, (T >= 0.01) & (T < 103.57591)), (-2.15621953171362e-6*T**3 + 0.000288560900942072*T**2 - 0.13879113947248*T*log(T) + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) + 0.574637617323048*T - 11042.8822142647, (T >= 103.57591) & (T < 210.33309)), (-0.002432585*T**2 + 0.4335558862135*T*log(T) + 8.7685671186*T*log(exp(155.1404/T) - 1.0) + 16.1968683846*T*log(exp(290.9421/T) - 1.0) - 2.20049706600083*T - 11002.7543747764, (T >= 210.33309) & (T < 1357.77)), (-31.38*T*log(T) + 183.555483717662*T - 12730.2995781851 + 7.42232714807953e+28/T**9, (T >= 1357.77) & (T < 3200.0)), (0, True)), 'MG': Piecewise((0.0047195465*T**2 + 3.2404446864*T*log(exp(95.82831/T) - 1.0) + 21.6535319868*T*log(exp(247.8675/T) - 1.0) - 10652.1012810789, (T >= 0.01) & (T < 36.71926)), (-1.53643054262276e-5*T**3 + 0.00810454205399037*T**2 - 0.124294531845816*T*log(T) + 3.2404446864*T*log(exp(95.82831/T) - 1.0) + 21.6535319868*T*log(exp(247.8675/T) - 1.0) + 0.385723396310737*T - 10653.6226154894, (T >= 36.71926) & (T < 143.18844)), (-0.0050954035*T**2 + 1.765785080115*T*log(T) + 3.2404446864*T*log(exp(95.82831/T) - 1.0) + 21.6535319868*T*log(exp(247.8675/T) - 1.0) - 8.0518972866125*T - 10563.4100984519, (T >= 143.18844) & (T < 922.205302616508)), (-34.3088*T*log(T) + 204.341485347575*T - 13775.4156328263 + 9.4687256586798e+27/T**9, (T >= 922.205302616508) & (T < 10000.0)), (0, True))}, 'Symbol': <class 'sympy.core.symbol.Symbol'>, 'T': T, '__builtins__': {'ArithmeticError': <class 'ArithmeticError'>, 'AssertionError': <class 'AssertionError'>, 'AttributeError': <class 'AttributeError'>, 'BaseException': <class 'BaseException'>, 'BlockingIOError': <class 'BlockingIOError'>, 'BrokenPipeError': <class 'BrokenPipeError'>, 'BufferError': <class 'BufferError'>, 'BytesWarning': <class 'BytesWarning'>, 'ChildProcessError': <class 'ChildProcessError'>, 'ConnectionAbortedError': <class 'ConnectionAbortedError'>, 'ConnectionError': <class 'ConnectionError'>, 'ConnectionRefusedError': <class 'ConnectionRefusedError'>, 'ConnectionResetError': <class 'ConnectionResetError'>, 'DeprecationWarning': <class 'DeprecationWarning'>, 'EOFError': <class 'EOFError'>, 'Ellipsis': Ellipsis, 'EnvironmentError': <class 'OSError'>, 'Exception': <class 'Exception'>, 'False': False, 'FileExistsError': <class 'FileExistsError'>, 'FileNotFoundError': <class 'FileNotFoundError'>, 'FloatingPointError': <class 'FloatingPointError'>, 'FutureWarning': <class 'FutureWarning'>, 'GeneratorExit': <class 'GeneratorExit'>, 'IOError': <class 'OSError'>, 'ImportError': <class 'ImportError'>, 'ImportWarning': <class 'ImportWarning'>, 'IndentationError': <class 'IndentationError'>, 'IndexError': <class 'IndexError'>, 'InterruptedError': <class 'InterruptedError'>, 'IsADirectoryError': <class 'IsADirectoryError'>, 'KeyError': <class 'KeyError'>, 'KeyboardInterrupt': <class 'KeyboardInterrupt'>, 'LookupError': <class 'LookupError'>, 'MemoryError': <class 'MemoryError'>, 'ModuleNotFoundError': <class 'ModuleNotFoundError'>, 'NameError': <class 'NameError'>, 'None': None, 'NotADirectoryError': <class 'NotADirectoryError'>, 'NotImplemented': NotImplemented, 'NotImplementedError': <class 'NotImplementedError'>, 'OSError': <class 'OSError'>, 'OverflowError': <class 'OverflowError'>, 'PendingDeprecationWarning': <class 'PendingDeprecationWarning'>, 'PermissionError': <class 'PermissionError'>, 'ProcessLookupError': <class 'ProcessLookupError'>, 'RecursionError': <class 'RecursionError'>, 'ReferenceError': <class 'ReferenceError'>, 'ResourceWarning': <class 'ResourceWarning'>, 'RuntimeError': <class 'RuntimeError'>, 'RuntimeWarning': <class 'RuntimeWarning'>, 'StopAsyncIteration': <class 'StopAsyncIteration'>, 'StopIteration': <class 'StopIteration'>, 'SyntaxError': <class 'SyntaxError'>, 'SyntaxWarning': <class 'SyntaxWarning'>, 'SystemError': <class 'SystemError'>, 'SystemExit': <class 'SystemExit'>, 'TabError': <class 'TabError'>, 'TimeoutError': <class 'TimeoutError'>, 'True': True, 'TypeError': <class 'TypeError'>, 'UnboundLocalError': <class 'UnboundLocalError'>, 'UnicodeDecodeError': <class 'UnicodeDecodeError'>, 'UnicodeEncodeError': <class 'UnicodeEncodeError'>, 'UnicodeError': <class 'UnicodeError'>, 'UnicodeTranslateError': <class 'UnicodeTranslateError'>, 'UnicodeWarning': <class 'UnicodeWarning'>, 'UserWarning': <class 'UserWarning'>, 'ValueError': <class 'ValueError'>, 'Warning': <class 'Warning'>, 'ZeroDivisionError': <class 'ZeroDivisionError'>, '__build_class__': <built-in function __build_class__>, '__debug__': True, '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__import__': <built-in function __import__>, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__name__': 'builtins', '__package__': '', '__pybind11_internals_v4_gcc_libstdcpp_cxxabi1013__': <capsule object NULL>, '__spec__': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>), 'abs': <built-in function abs>, 'all': <built-in function all>, 'any': <built-in function any>, 'ascii': <built-in function ascii>, 'bin': <built-in function bin>, 'bool': <class 'bool'>, 'breakpoint': <built-in function breakpoint>, 'bytearray': <class 'bytearray'>, 'bytes': <class 'bytes'>, 'callable': <built-in function callable>, 'chr': <built-in function chr>, 'classmethod': <class 'classmethod'>, 'compile': <built-in function compile>, 'complex': <class 'complex'>, 'copyright': Copyright (c) 2001-2021 Python Software Foundation. All Rights Reserved. Copyright (c) 2000 BeOpen.com. All Rights Reserved. Copyright (c) 1995-2001 Corporation for National Research Initiatives. All Rights Reserved. Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands for supporting Python development. See www.python.org for more information., 'delattr': <built-in function delattr>, 'dict': <class 'dict'>, 'dir': <built-in function dir>, 'divmod': <built-in function divmod>, 'enumerate': <class 'enumerate'>, 'eval': <built-in function eval>, 'exec': <built-in function exec>, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'filter': <class 'filter'>, 'float': <class 'float'>, 'format': <built-in function format>, 'frozenset': <class 'frozenset'>, 'getattr': <built-in function getattr>, 'globals': <built-in function globals>, 'hasattr': <built-in function hasattr>, 'hash': <built-in function hash>, 'help': Type help() for interactive help, or help(object) for help about object., 'hex': <built-in function hex>, 'id': <built-in function id>, 'input': <built-in function input>, 'int': <class 'int'>, 'isinstance': <built-in function isinstance>, 'issubclass': <built-in function issubclass>, 'iter': <built-in function iter>, 'len': <built-in function len>, 'license': Type license() to see the full license text, 'list': <class 'list'>, 'locals': <built-in function locals>, 'map': <class 'map'>, 'max': <built-in function max>, 'memoryview': <class 'memoryview'>, 'min': <built-in function min>, 'next': <built-in function next>, 'object': <class 'object'>, 'oct': <built-in function oct>, 'open': <built-in function open>, 'ord': <built-in function ord>, 'pow': <built-in function pow>, 'print': <built-in function print>, 'property': <class 'property'>, 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'range': <class 'range'>, 'repr': <built-in function repr>, 'reversed': <class 'reversed'>, 'round': <built-in function round>, 'set': <class 'set'>, 'setattr': <built-in function setattr>, 'slice': <class 'slice'>, 'sorted': <built-in function sorted>, 'staticmethod': <class 'staticmethod'>, 'str': <class 'str'>, 'sum': <built-in function sum>, 'super': <class 'super'>, 'tuple': <class 'tuple'>, 'type': <class 'type'>, 'vars': <built-in function vars>, 'zip': <class 'zip'>}, '__cached__': '/home/docs/checkouts/readthedocs.org/user_builds/espei/checkouts/0.8.2/espei/__pycache__/refdata.cpython-38.pyc', '__doc__': '\nThe refdata module contains pure-element reference state data.\n', '__file__': '/home/docs/checkouts/readthedocs.org/user_builds/espei/checkouts/0.8.2/espei/refdata.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object>, '__name__': 'espei.refdata', '__package__': 'espei', '__spec__': ModuleSpec(name='espei.refdata', loader=<_frozen_importlib_external.SourceFileLoader object>, origin='/home/docs/checkouts/readthedocs.org/user_builds/espei/checkouts/0.8.2/espei/refdata.py'), 'exp': exp, 'find_and_insert_user_refstate': <function find_and_insert_user_refstate>, 'log': log})¶ Discover user reference states entered as a setuptools entry_point
- Parameters
entry_point_plugin_name (str) – Name of the key in the setuptools.setup entry_points dictionary.
namespace (dict) – A dictionary that the stable reference state and lattice stabilities will be added to. Defaults to
globals()
, which is this module’s namespace.
Notes
By default, it will enter the data into the
globals()
namespace, meaning this module’s namespace. Since ESPEI looks up reference states by something likegetattr(espei.refdata, 'SGTE91Stable')
, this is usually the desired behavior.- Some helpful links on how this works:
using package metadata entry_points: https://packaging.python.org/guides/creating-and-discovering-plugins/#using-package-metadata
entry_points specification https://packaging.python.org/specifications/entry-points/
how to find plugins with setuptools: https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins
Packages wanting to hook into this should add the following keyword argument to their setuptools.setup function call in their setup.py file:
entry_points={'espei.reference_states': 'BOCK2015 = refstate'}
, whereBOCK2015
is the name of the reference state andrefstate
is the name of the module containing the dictionaries forBOCK2015Stable
,BOCK2015
andBOCK2015SER
, which define the reference states.
espei.rstate module¶
espei.shadow_functions module¶
Fast versions of equilibrium and calculate that “override” the equivalent pycalphad functions for very fast performance.
-
espei.shadow_functions.
calculate_
(dbf: pycalphad.io.database.Database, species: Sequence[pycalphad.variables.Species], phases: Sequence[str], str_statevar_dict: Dict[str, numpy.ndarray], models: Dict[str, pycalphad.model.Model], phase_records: Dict[str, pycalphad.core.phase_rec.PhaseRecord], output: Optional[str] = 'GM', points: Optional[Dict[str, numpy.ndarray]] = None, pdens: Optional[int] = 2000, broadcast: Optional[bool] = True, fake_points: Optional[bool] = False) → pycalphad.core.light_dataset.LightDataset¶ Quickly sample phase internal degree of freedom with virtually no overhead.
-
espei.shadow_functions.
equilibrium_
(species: Sequence[pycalphad.variables.Species], phase_records: Dict[str, pycalphad.core.phase_rec.PhaseRecord], conditions: Dict[pycalphad.variables.StateVariable, numpy.ndarray], grid: pycalphad.core.light_dataset.LightDataset) → pycalphad.core.light_dataset.LightDataset¶ Perform a fast equilibrium calculation with virtually no overhead.
-
espei.shadow_functions.
no_op_equilibrium_
(_, phase_records: Dict[str, pycalphad.core.phase_rec.PhaseRecord], conditions: Dict[pycalphad.variables.StateVariable, numpy.ndarray], grid: pycalphad.core.light_dataset.LightDataset) → pycalphad.core.light_dataset.LightDataset¶ Perform a fast “equilibrium” calculation with virtually no overhead that doesn’t refine the solution or do global minimization, but just returns the starting point.
Notes
Uses a placeholder first argument for the same signature as
_equilibrium
, butspecies
are not needed.
-
espei.shadow_functions.
update_phase_record_parameters
(phase_records: Dict[str, pycalphad.core.phase_rec.PhaseRecord], parameters: numpy.ndarray) → None¶
espei.sublattice_tools module¶
Utilities for manipulating sublattice models.
-
espei.sublattice_tools.
canonical_sort_key
(x)¶ Wrap strings in tuples so they’ll sort.
- Parameters
x (list) – List of strings to sort
- Returns
tuple of strings that can be sorted
- Return type
tuple
-
espei.sublattice_tools.
canonicalize
(configuration, equivalent_sublattices)¶ Sort a sequence with symmetry. This routine gives the sequence a deterministic ordering while respecting symmetry.
- Parameters
configuration ([str]) – Sublattice configuration to sort.
equivalent_sublattices ({{int}}) – Indices of ‘configuration’ which should be equivalent by symmetry, i.e., [[0, 4], [1, 2, 3]] means permuting elements 0 and 4, or 1, 2 and 3, respectively, has no effect on the equivalence of the sequence.
- Returns
sorted tuple that has been canonicalized.
- Return type
str
-
espei.sublattice_tools.
endmembers_from_interaction
(configuration)¶ For a given configuration with possible interactions, return all the endmembers
-
espei.sublattice_tools.
generate_endmembers
(sublattice_model, symmetry=None)¶ Return all the unique endmembers by symmetry for a given sublattice model.
- Parameters
sublattice_model (list of lists) – General sublattice model, with each sublattice as a sublist.
symmetry (list of lists, optional) – List of lists containing symmetrically equivalent sublattice indices. If None (default), all endmembers will be returned.
- Returns
List of endmember tuples
- Return type
list
Examples
>>> subl_model = [['A', 'B'], ['A','B']] >>> generate_endmembers(subl_model) # four endmembers [('A', 'A'), ('A', 'B'), ('B', 'A'), ('B', 'B')] >>> # three endmembers, ('A', 'B') is equivalent to ('B', 'A') by symmetry. >>> generate_endmembers(subl_model, [[0, 1]]) # the first and second sublattices are symmetrically equivalent. [('A', 'A'), ('A', 'B'), ('B', 'B')]
-
espei.sublattice_tools.
generate_interactions
(endmembers, order, symmetry)¶ Returns a list of sorted interactions of a certain order
- Parameters
endmembers (list) – List of tuples/strings of all endmembers (including symmetrically equivalent)
order (int) – Highest expected interaction order, e.g. ternary interactions should be 3
symmetry (list of lists) – List of lists containing symmetrically equivalent sublattice indices, e.g. [[0, 1], [2, 3]] means that sublattices 0 and 1 are equivalent and sublattices 2 and 3 are also equivalent.
- Returns
List of interaction tuples, e.g. [(‘A’, (‘A’, ‘B’))]
- Return type
list
-
espei.sublattice_tools.
generate_symmetric_group
(configuration, symmetry)¶ For a particular configuration and list of sublattices with symmetry, generate all the symmetrically equivalent configurations.
- Parameters
configuration (tuple) – Tuple of a sublattice configuration.
symmetry (list of lists) – List of lists containing symmetrically equivalent sublattice indices, e.g. [[0, 1], [2, 3]] means that sublattices 0 and 1 are equivalent and sublattices 2 and 3 are also equivalent.
- Returns
Tuple of configuration tuples that are all symmetrically equivalent.
- Return type
tuple
-
espei.sublattice_tools.
interaction_test
(configuration, order=None)¶ Returns True if the configuration has an interaction
- Parameters
order (int, optional) – Specific order to check for. E.g. a value of 3 checks for ternary interactions
- Returns
True if there is an interaction.
- Return type
bool
Examples
>>> configuration = [['A'], ['A','B']] >>> interaction_test(configuration) True >>> interaction_test(configuration, order=2) True >>> interaction_test(configuration, order=3) False
-
espei.sublattice_tools.
recursive_tuplify
(x)¶ Recursively convert a nested list to a tuple
-
espei.sublattice_tools.
sorted_interactions
(interactions, max_interaction_order, symmetry)¶ Return interactions sorted by interaction order
- Parameters
interactions (list) – List of tuples/strings of potential interactions
max_interaction_order (int) – Highest expected interaction order, e.g. ternary interactions should be 3
symmetry (list of lists) – List of lists containing symmetrically equivalent sublattice indices, e.g. [[0, 1], [2, 3]] means that sublattices 0 and 1 are equivalent and sublattices 2 and 3 are also equivalent.
- Returns
Sorted list of interactions
- Return type
list
Notes
Sort by number of full interactions, e.g. (A:A,B) is before (A,B:A,B) The goal is to return a sort key that can sort through multiple interaction orders, e.g. (A:A,B,C), which should be before (A,B:A,B,C), which should be before (A,B,C:A,B,C).
-
espei.sublattice_tools.
tuplify
(x)¶ Convert a list to a tuple, or wrap an object in a tuple if it’s not a list or tuple.
espei.utils module¶
Utilities for ESPEI
Classes and functions defined here should have some reuse potential.
-
class
espei.utils.
ImmediateClient
(address=None, loop=None, timeout='__no_default__', set_as_default=True, scheduler_file=None, security=None, asynchronous=False, name=None, heartbeat_interval=None, serializers=None, deserializers=None, extensions=[<class 'distributed.pubsub.PubSubClientExtension'>], direct_to_workers=None, connection_limit=512, **kwargs)¶ Bases:
distributed.client.Client
A subclass of distributed.Client that automatically unwraps the Futures returned by map.
-
map
(f, *iterators, **kwargs)¶ Map a function on a sequence of arguments.
Any keyword arguments are passed to distributed.Client.map
-
-
class
espei.utils.
PickleableTinyDB
(*args, **kwargs)¶ Bases:
tinydb.database.TinyDB
A pickleable version of TinyDB that uses MemoryStorage as a default.
-
espei.utils.
bib_marker_map
(bib_keys, markers=None)¶ Return a dict with reference keys and marker dicts
- Parameters
bib_keys –
markers (list) – List of 2-tuples of (‘fillstyle’, ‘marker’) e.g. [(‘top’, ‘o’), (‘full’, ‘s’)]. Defaults to cycling through the filled markers, the different fill styles.
- Returns
Dictionary with bib_keys as keys, dict values of formatted strings and marker dicts
- Return type
dict
Examples
>>> mm = bib_marker_map(['otis2016', 'bocklund2018']) >>> mm == {'bocklund2018': {'formatted': 'bocklund2018', 'markers': {'fillstyle': 'none', 'marker': 'o'}}, 'otis2016': {'formatted': 'otis2016', 'markers': {'fillstyle': 'none', 'marker': 'v'}}} True
-
espei.utils.
build_sitefractions
(phase_name, sublattice_configurations, sublattice_occupancies)¶ Convert nested lists of sublattice configurations and occupancies to a list of dictionaries. The dictionaries map SiteFraction symbols to occupancy values. Note that zero occupancy site fractions will need to be added separately since the total degrees of freedom aren’t known in this function.
- Parameters
phase_name (str) – Name of the phase
sublattice_configurations ([[str]]) – sublattice configuration
sublattice_occupancies ([[float]]) – occupancy of each sublattice
- Returns
a list of site fractions over sublattices
- Return type
[[float]]
-
espei.utils.
database_symbols_to_fit
(dbf, symbol_regex='^V[V]?([0-9]+)$')¶ Return names of the symbols to fit that match the regular expression
- Parameters
dbf (Database) – pycalphad Database
symbol_regex (str) – Regular expression of the fitting symbols. Defaults to V or VV followed by one or more numbers.
- Returns
Context dictionary for different methods of calculation the error.
- Return type
dict
-
espei.utils.
extract_aliases
(phase_models)¶ Map possible phase name aliases to the desired phase model phase name.
This function enforces that each alias is only claimed by one phase. Each phase name in the phase models is added as an alias for itself to support an “identity” operation.
- Parameters
phase_models – Phase models ESPEI uses to initialize databases. Must contain a mapping of phase names to phase data (sublattices, site ratios, aliases)
- Returns
- Return type
Dict[str, str]
-
espei.utils.
formatted_constituent_array
(constituent_array)¶ Given a constituent array of Species, return the classic CALPHAD-style interaction.
- Parameters
constituent_array (list) – List of sublattices, which are lists of Species in that sublattice
- Returns
String of the constituent array formatted in the classic CALPHAD style
- Return type
str
Examples
>>> from pycalphad import variables as v >>> const_array = [[v.Species('CU'), v.Species('MG')], [v.Species('MG')]] >>> formatted_constituent_array(const_array) 'CU,MG:MG'
-
espei.utils.
formatted_parameter
(dbf, symbol, unique=True)¶ Get the deconstructed pretty parts of the parameter/term a symbol belongs to in a Database.
- Parameters
dbf (pycalphad.Database) –
symbol (string or sympy.Symbol) – Symbol in the Database to get the parameter for.
unique (bool) – If True, will raise if more than one parameter containing the symbol is found.
- Returns
A named tuple with the following attributes:
phase_name
,interaction
,symbol
,term
,parameter_type
orterm_symbol
(which is just the Symbol * temperature term)- Return type
FormattedParameter
-
espei.utils.
optimal_parameters
(trace_array, lnprob_array, kth=0)¶ Return the optimal parameters in the trace based on the highest likelihood. If kth is specified, return the kth set of unique optimal parameters.
- Parameters
trace_array (ndarray) – Array of shape (number of chains, iterations, number of parameters)
lnprob_array (ndarray) – Array of shape (number of chains, iterations)
kth (int) – Zero-indexed optimum. 0 (the default) is the most optimal solution. 1 is the second most optimal, etc.. Only unique solutions will be returned.
- Returns
- Return type
Array of optimal parameters
Notes
It is ok if the calculation did not finish and the arrays are padded with zeros. The number of chains and iterations in the trace and lnprob arrays must match.
Examples
>>> from espei.utils import optimal_parameters >>> trace = np.array([[[1, 0], [2, 0], [3, 0], [0, 0]], [[0, 2], [0, 4], [0, 6], [0, 0]]]) # 3 iterations of 4 allocated >>> lnprob = np.array([[-6, -4, -2, 0], [-3, -1, -2, 0]]) >>> np.all(np.isclose(optimal_parameters(trace, lnprob), np.array([0, 4]))) True
-
espei.utils.
parameter_term
(expression, symbol)¶ Determine the term, e.g. T*log(T) that belongs to the symbol in expression
- Parameters
expression –
symbol –
-
espei.utils.
sigfigs
(x, n)¶ Round x to n significant digits
-
espei.utils.
unpack_piecewise
(x)¶
espei.validation module¶
Module contents¶
ESPEI
Contributing to ESPEI¶
This is the place to start as a new ESPEI contributor. This guide assumes you have installed a development version of ESPEI.
The next sections lay out the basics of getting an ESPEI development set up and the development standards. Then the Software design sections walk through the key parts of the codebase.
Tests¶
Even though much of ESPEI is devoted to being a multi-core, stochastic user tool, we strive to test all logic and functionality. We are continuously maintaining tests and writing tests for previously untested code. As a general rule, any time you write a new function or modify an existing function you should write or maintain a test for that function.
Some tips for testing:
Ideally you would practicing test driven development by writing tests of your intended results before you write the function.
If possible, keep the tests small and fast.
See the NumPy/SciPy testing guidelines for more tips.
Style¶
Code style¶
For most naming and style, follow PEP8. One exception to PEP8 is regarding the line length, which we suggest a 120 character maximum, but may be longer within reason.
Code documentation¶
ESPEI uses the NumPy documentation style. All functions and classes should be documented with at least a description, parameters, and return values, if applicable.
Using Examples
in the documentation is especially encouraged for utilities that are likely to be run by users.
See espei.analysis.truncate_arrays()
for an example.
Web documention¶
Documentation on ESPEI is split into user tutorials, reference and developer documentation.
Tutorials are resources for users new to ESPEI or new to certain features of ESPEI to be guided through typical actions.
Reference pages should be concise articles that explain how to complete specific goals for users who know what they want to accomplish.
Developer documentation should describe what should be considered when contributing source code back to ESPEI.
You can check changes you make to the documentation by going to the documentation folder in the root repository cd docs/
.
Running the command make html && cd build/html && python3 -m http.server && cd ../.. && make clean
from that folder will build the docs and run them on a local HTTP server.
You can see the documentation when the server is running by
visting the URL at the end of the output, usually localhost port 8000 <http://0.0.0.0:8000>``_.
When you are finished, type ``Ctrl-C
to stop the server and the command will clean up the build for you.
Make sure to fix any warnings that come up if you are adding documentation.
Building Documentation¶
The docs can be built by running the docs/Makefile (or docs/make.bat on
Windows). Then Python can be used to serve the html files in the _build
directory and you can visit http://localhost:8000
in your broswer to
see the built documentation.
For Unix systems:
cd docs
make html
cd _build/html
python -m http.server
Windows:
cd docs
make.bat html
cd _build\html
python -m http.server
Logging¶
Since ESPEI is intended to be run by users, we must provide useful feedback on how their runs are progressing. ESPEI uses the logging module to allow control over verbosity of the output.
There are 5 different logging levels provided by Python. They should be used as follows:
- Critical or Error (
logging.critical
orlogging.error
) Never use these. These log levels would only be used when there is an unrecoverable error that requires the run to be stopped. In that case, it is better to
raise
an appropriate error instead.- Warning (
logging.warning
) Warnings are best used when we are able to recover from something bad that has happened. The warning should inform the user about potentially incorrect results or let them know about something they have the potential to fix. Again, anything unrecoverable should not be logged and should instead be raised with a good error message.
- Info (
logging.info
) Info logging should report on the progress of the program. Usually info should give feedback on milestones of a run or on actions that were taken as a result of a user setting. An example of a milestone is starting and finishing parameter generation. An example of an action taken as a result of a user setting is the logging of the number of chains in an mcmc run.
- Debug (
logging.debug
) Debugging is the lowest level of logging we provide in ESPEI. Debug messages should consist of possibly useful information that is beyond the user’s direct control. Examples are the values of initial parameters, progress of checking datasets and building phase models, and the acceptance ratios of MCMC iterations.
Software design¶
The following sections elaborate on the design principles on the software side. The goal is to make it clear how different modules in ESPEI fit together and where to find specific functionality to override or improve.
ESPEI provides tools to
Parameterize CALPHAD models by optimizing the compromise between model accuracy and complexity. We typically call this parameter generation or model selection.
Fit parameterized CALPHAD models to thermochemical and phase boundary data or other custom data with uncertainty quantification via Markov chain Monte Carlo
API¶
ESPEI has two levels of API that users should expect to interact with:
Input from YAML files on the command line (via
espei --input <input_file>
or by Python via theespei.espei_script.run_espei
functionWork directly with the Python functions for parameter selection
espei.paramselect.generate_parameters
and MCMCespei.mcmc.mcmc_fit
YAML files are the recommended way to use ESPEI and should have a way to express most if not all of the options that
the Python functions support. The schema for YAML files is located in the root of the ESPEI directory as input-schema.yaml
and is validated in the espei_script.py
module by the Cerberus package.
Module Hierarchy¶
espei_script.py
is the main entry point for the YAML input API.optimzers
is a package that defines anOptimizerBase
class for writing optimizers.EmceeOptimzer
andScipyOptimizer
subclasses this.error_functions
is a package with modules for each type of likelihood function.priors.py
defines priors to be used in MCMC, see Specifying Priors.paramselect.py
is where parameter generation happens.mcmc.py
creates the likelihood function and runs MCMC. Deprecated. In the future, users should useEmceeOptimizer
.parameter_selection
is a package with core pieces of parameter selection.utils.py
are utilities with reuse potential across several parts of ESPEI.plot.py
holds plotting functions.datasets.py
manages validating and loading datasets into a TinyDB in memory database.core_utils.py
are legacy utility functions that should be refactored out to be closer to individual modules and packages where they are used.shadow_functions.py
are core internals that are designed to be fast, minimal versions of pycalphad’scalculate
andequilibrium
functions.
Parameter selection¶
Parameter selection goes through the generate_parameters
function in the espei.paramselect
module.
The goal of parameter selection is go through each phase (one at a time) and fit a CALPHAD model to the data.
For each phase, the endmembers are fit first, followed by binary and ternary interactions. For each individual endmember or interaction to fit, a series of candidate models are generated that have increasing complexity in both temperature and interaction order (an L0 excess parameter, L0 and L1, …).
Each model is then fit by espei.parameter_selection.selection.fit_model
, which currently uses a simple
pseudo-inverse linear model from scikit-learn. Then the tradeoff between the goodness of fit and the model complexity
is scored by the AICc in espei.parameter_selection.selection.score_model
.
The optimal scoring model is accepted as the model with the fit model parameters set as degrees of freedom for the MCMC step.
The main principle is that ESPEI transforms the data and candidate models to vectors and matricies that fit a typical machine learning type problem of \(Ax = b\). Extending ESPEI to use different or custom models in the current scheme basically comes down to formulating candidate models in terms of this type of problem. The main ways to improve on the fitting or scoring methods used in parameter selection is to override the fit and score functions.
Currently the capabilities for providing custom models or contributions (e.g. magnetic data) in the form of generic pycalphad Model objects are limited. This is also true for custom types of data that one would use in fitting a custom model.
MCMC optimization and uncertainty quantification¶
Most of the Markov chain Monte Carlo optimization and uncertainty quantification happen in the espei.optimizers.opt_mcmc.py
module through the EmceeOptimizer
class.
EmceeOptimizer
is a subclass of OptimizerBase
, which defines an interface for performing opitmizations of parameters. It defines several methods:
fit
takes a list of symbol names and datasets to fit to. It calls an _fit
method that returns an OptNode
representing the parameters that result from the fit to the datasets.
fit
evaluates the parameters by calling the objective function on some parameters (an array of values) and a context in the predict
method, which is overridden by OptimizerBase
subclasses.
There is also an interface for storing a history of successive fits to different parameter sets, using the commit
method, which will store the history of the calls to fit
in a graph of fitting steps.
The idea is that users can generate a graph of fitting results and go back to specific points on the graph and test fitting different sets of parameters or different datasets, creating a unique history of committed parameter sets and optimization paths, similar to a history in version control software like git.
The main reason ESPEI’s parameter selection and MCMC routines are split up is that custom Models or existing TDB files can be provided and fit. In other words, if you are using a model that doesn’t need parameter selection or is for a property that is not Gibbs energy, MCMC can fit it with uncertainty quantification.
The general process is
Take a database with degrees of freedom as database symbols named
VV####
, where####
is a number, e.g.0001
. The symbols correspond toFUNCTION
in the TDB files.Initialize those degrees of freedom to a starting distribution for ensemble MCMC. The starting distribution is controlled by the
EmceeOptimizer.initialize_new_chains
function, which currently supports initializing the parameters to a Gaussian ball.Use the emcee package to run ensemble MCMC
ESPEI’s MCMC is quite flexible for customization. To fit a custom model, it just needs to be read by pycalphad and
have correctly named degrees of freedom (VV####
).
To fit an existing or custom model to new types of data, just write a function that takes in datasets and the parameters
that are required to calculate the values (e.g. pycalphad Database, components, phases, …) and returns the error.
Then override the EmceeOptimizer.predict
function to include your custom error contribution.
There are examples of these functions espei.error_functions
that ESPEI uses by default.
Modifications to how parameters are initialized can be made by subclassing EmceeOptimizer.initialize_new_chains
.
Many other modifications can be made by subclassing EmceeOptimizer
.
Releasing ESPEI¶
Use this checklist to create a new release of ESPEI and distribute the package
to PyPI and conda-forge. All steps are intended to be run from the root directory of the repository (i.e.
the one containing docs/
, espei/
, setup.py
, …).
Creating a new release¶
These steps will create a new tagged version in the GitHub repository.
git pull
to make sure you haven’t missed any last-minute commits. After this point, nothing else is making it into this version.pytest
to ensure that all tests pass locally.sphinx-apidoc -f -o docs/api/ espei/ -H 'API Documentation'
to regenerate API documentation.Commit the updated API documentation.
git push
and verify all tests pass on all CI services.Generate a list of commits since the last version with
git --no-pager log --oneline --no-decorate 0.1^..origin/master
. Replace0.1
with the tag of the last public version.Condense the change list into something user-readable. Update and commit
CHANGES.rst
with the release date.git tag 0.2 master -m "0.2"
Replace0.2
with the new version.git show 0.2
to ensure the correct commit was tagged.git push origin master --tags
to push the tag to GitHub.
Now the public package must be built and distributed.
Uploading to PyPI¶
All tagged GitHub commits should be uploaded to PyPI automatically by the
deploy.yaml
GitHub Action. If ESPEI needs to be released to PyPI manually,
follow the steps below.
Manually uploading to PyPI¶
rm -R dist/*
on Linux/OSX ordel dist/*
on Windows.python setup.py sdist
to create a source distribution.Make sure that the script correctly detected the new version exactly and not a dirty or revised state of the repository.
twine upload -r pypi -u bocklund dist/*
to upload to PyPI.
Updating the conda-forge feedstock¶
conda-forge is a community-developed platform for distributing packages to the conda-forge channel on Anaconda Cloud. Metadata for the packages are hosted in feedstocks and built using conda-build in a continuous integration pipeline.
conda-build is driven by a recipe/meta.yaml
configuration file, which
specifies the package metadata and dependencies. The meta.yaml
file is
updated via pull requests to the conda-forge/espei-feedstock. A pull request
is usually opened automatically by the conda-forge autotick bot, but pull
requests can be opened manually as well. Both methods are detailed below.
After updating the meta.yaml
file and merging the pull request, the
conda-forge continuous integration pipeline will run from the master branch and
upload build artifacts to the conda-forge channel on Anaconda Cloud. Uploaded
build artifacts are usually available to download and install in about 1 hour
after the continuous integration pipeline completes on the master branch.
The availability of a particular ESPEI package on conda-forge can be verified by
running conda search -c conda-forge --override-channels espei
.
conda-forge autotick bot (preferred)¶
The conda-forge autotick bot will automatically open a pull request in the conda-forge/espei-feedstock repository after the package has been uploaded to PyPI. This usually happens in less than 10 minutes after the PyPI release.
Verify that the
recipe/meta.yaml
requirements match the dependencies inenvironment-dev.yml
.Once all the checks pass, merge the pull request.
Manually updating¶
If the conda-forge autotick bot does not open a pull request automatically,
the conda-forge/espei-feedstock can still be updated manually with a pull
request that updates the recipe/meta.yaml
file.
Get the sha-256 hash of the tarball via
openssl sha256 dist/espei-0.3.1.tar.gz
or by viewing the hashes for the release at https://pypi.org/project/espei/#files.Fork the conda-forge/espei-feedstock repository.
Update the version number and hash in the
recipe/meta.yaml
file and set the build number to zero if the version number changed.Verify that the
recipe/meta.yaml
requirements match the dependencies inenvironment-dev.yml
.Open a PR against the conda-forge/espei-feedstock repository
Once all the checks pass, merge the pull request.
Getting Help¶
For help on installing and using ESPEI, please join the PhasesResearchLab/ESPEI Gitter room.
Bugs and software issues should be reported on GitHub.
License¶
ESPEI is MIT licensed.
The MIT License (MIT)
Copyright (c) 2015-2018 Richard Otis
Copyright (c) 2017-2018 Brandon Bocklund
Copyright (c) 2018-2019 Materials Genome Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Citing ESPEI¶
If you use ESPEI for work presented in a publication, we ask that you cite the following publication:
Bocklund, R. Otis, A. Egorov, A. Obaied, I. Roslyakova, Z.-K. Liu, ESPEI for efficient thermodynamic database development, modification, and uncertainty quantification: application to Cu–Mg, MRS Commun. (2019) 1–10. doi:10.1557/mrc.2019.59.
@article{Bocklund2019ESPEI,
archivePrefix = {arXiv},
arxivId = {1902.01269},
author = {Bocklund, Brandon and Otis, Richard and Egorov, Aleksei and Obaied, Abdulmonem and Roslyakova, Irina and Liu, Zi-Kui},
doi = {10.1557/mrc.2019.59},
eprint = {1902.01269},
issn = {2159-6859},
journal = {MRS Communications},
month = {jun},
pages = {1--10},
title = {{ESPEI for efficient thermodynamic database development, modification, and uncertainty quantification: application to Cu–Mg}},
year = {2019}
}