Source code for qha.fitting
#!/usr/bin/env python3
"""
.. module fitting
:platform: Unix, Windows, Mac, Linux
:synopsis: This module is one of the most important part of this package since it implements a robust
finite strain EoS fitting for ``grid_interpolation`` module's use.
.. moduleauthor:: Tian Qin <qinxx197@umn.edu>
"""
from typing import Optional
import numpy as np
from numpy.linalg import inv
from qha.type_aliases import Matrix, Vector
# ===================== What can be exported? =====================
__all__ = ['polynomial_least_square_fitting', 'apply_finite_strain_fitting']
[docs]def polynomial_least_square_fitting(xs, ys, new_xs, order: Optional[int] = 3):
"""
The algorithm is referenced from the
`Wolfram MathWorld <http://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html>`_.
:param xs: A vector of existing x-coordinates.
:param ys: A vector of y-coordinates correspond to the *xs*.
:param new_xs: A new vector of x-coordinates to be applied with the polynomial-fitting result.
:param order: The order chose to fit the finite strain EoS, the default value is ``3``,
which is, the third-order Birch--Murnaghan EoS.
:return: A tuple, the polynomial-fitting coefficients and the new vector of y-coordinates.
"""
order += 1 # The definition of order in ``numpy.vander`` is different from the order in finite strain by one.
xx = np.vander(xs, order, increasing=True) # This will make a Vandermonde matrix that will be used in EoS fitting.
xx_t = xx.T # Transpose the matrix.
a = inv(xx_t @ xx) @ xx_t @ ys # a = (X^T . X)^{-1} . X^T . ys
new_y = np.vander(new_xs, order, increasing=True) @ a
return a, new_y
[docs]def apply_finite_strain_fitting(strains_sparse: Vector, free_energies: Matrix, strains_dense: Vector,
order: Optional[int] = 3):
"""
Calculate the free energies :math:`F(T, V)` for some strains (*strains_dense*), with the
free energies (*free_energies*) on some other strains (*strains_sparse*) known already.
Do a polynomial curve-fitting the apply the fitted function
to the *strains_dense*.
:param strains_sparse: A vector of the Eulerian strains for a sparse set of volumes.
:param free_energies: The free energies correspond to *strains_sparse* at several temperature.
:param strains_dense: A vector of the Eulerian strains at a denser set of volumes.
:param order: The order chose to fit the finite strain EoS, the default value is ``3``,
which is, the third-order Birch--Murnaghan EoS.
:return: The free energies correspond to *strains_dense* at different temperature.
"""
temperature_amount, _ = free_energies.shape
dense_volume_amount = len(strains_dense)
f_v_t = np.empty((temperature_amount, dense_volume_amount)) # Initialize the F(T,V) array
for i in range(temperature_amount):
_, f_i = polynomial_least_square_fitting(strains_sparse, free_energies[i], strains_dense, order)
f_v_t[i] = f_i
return f_v_t