kawin.thermo (Calphad)

kawin.kawin.thermo.Mobility

def expand_x_frac(x_frac):

Converts x_frac (N,e-1) to x_full (N,e)
Assumes the first element is dependent
    Where x[0] = 1-sum(x[1:])

def expand_u_frac(u_frac, elements, interstitial_list):

Converts u_frac (N,e-1) to u_full (N,e)
Assumes first element is dependent
    Where u[0] = 1-sum(u[1:]_j) where j is substitutional
This also assumes the first element is substitutional

def x_to_u_frac(x_frac, elements, interstitial_list, return_usum = False):

Converts mole fraction to u-fraction
U-fraction - defined as U_a = X_a / sum(substitutionals)

U-fraction is used for diffusivity in a volume-fixed frame, where interstitials do
not contribute to the overall volume

def u_to_x_frac(u_frac, elements, interstitial_list):

MobilityModel(Model)

class MobilityModel(self, dbe, comps, phase_name, parameters=None):

Handles mobility and diffusivity data from .tdb files

Parameters
----------
dbe : Database
comps : list
    List of elements to consider
phase_name : str
parameters : dict or list (optional)
    Dictionary of parameters to be kept symbolic

Attributes
----------
mobility_variables : dict
    Dictionary of symbols in mobility functions for each element
diffusivity_variables : dict
    Dictionary of symbols in diffusivity functions for each element

def MobilityModel.mobility_variables(self):

List of variables in the mobility functions

Returns
-------
dictionary {component name (str) : variables (list)}

def MobilityModel.diffusivity_variables(self):

List of variables in the diffusivity functions

Returns
-------
dictionary {component name (str) : variables (list)}

def MobilityModel.build_phase(self, dbe):

Builds free energy and mobility/diffusivity models as abstract syntax tree

Parameters
----------
dbe : Database

def MobilityModel._mobility_validity(self, constituent_array):

Returns true if constituent_array contains only active species of current model
Ignores vacancies - if a sublattice is only vacancies, then it should be ignored
    For now, phases where this occurs will have the parameters listed for n-1 sublattices

def MobilityModel.build_mobility(self, dbe):

Builds mobility/diffusivity models as abstract syntax tree

Parameters
----------
dbe : Database

def MobilityModel.checkOrderingContribution(self, dbe):

Checks if phase is an ordered part of a order-disorder model

The ordered part of the phase double counts the disordered contribution, so the model is
G = G_dis + G_ord(y) - G_ord(y=x)

This is straight up copied from Model.atomic_ordering_energy in pycalphad with
  the minor difference that we replace the symbols in mob and diff

def _get_mobility_arguments(composition_set, parameters):

def mobility_from_composition_set(composition_set, mobility_callables = None, mobility_correction = None, parameters = {}):

Computes mobility from equilibrium results

Parameters
----------
composition_set : pycalphad.core.composition_set.CompositionSet
mobility_callables : dict
    Pre-computed mobility callables for each element
mobility_correction : dict (optional)
    Factor to multiply mobility by for each given element (defaults to 1)
parameters : dict {str : float}
    List of parameters to override free symbols in the model

Returns
-------
Array for floats for mobility of each element (alphabetical order)

def tracer_diffusivity(composition_set, mobility_callables = None, mobility_correction = None, parameters = {}):

Computes tracer diffusivity for given equilibrium results
D = MRT

Parameters
----------
composition_set : pycalphad.core.composition_set.CompositionSet
mobility_callables : dict
    Pre-computed mobility callables for each element
mobility_correction : dict (optional)
    Factor to multiply mobility by for each given element (defaults to 1)

Returns
-------
Array of floats of diffusivity for each element (alphabetical order)

def mobility_matrix(composition_set, mobility_callables = None, mobility_correction = None, vacancy_poor_interstitial_sublattice = False, parameters = {}):

Mobility matrix
Used to obtain diffusivity when multipled with free energy hessian

Parameters
----------
composition_set : pycalphad.core.composition_set.CompositionSet
mobility_callables : dict (optional)
    Pre-computed mobility callables for each element
mobility_correction : dict (optional)
    Factor to multiply mobility by for each given element (defaults to 1)
vacancy_poor_interstitial_sublattice : bool (optional)
    Denotes whether the interstitial sublattice is to be modeled assuming that vacancy fraction is near 0 (see notes below)
    Defaults to False
parameters : dict (optional)
    Maps free parameters names to parameter values

Notes
-----
- Substitutional and interstitial components are modeled differently based off the following assumptions:
    1. Substitutional components contribute to the volume of the alloy while interstitials have zero volume
    2. Vacancy fraction in substitutional sublattice is near 0 while vacancy fraction in interstitial sublattice is near 1

- Assumption 1 is accounted by considering u-fraction of other components for substitutional and accounting for reference element
  when computing interdiffusivity. Interstitials do not account for this since they do not contribute to the volume

- Assumption 2 is accounted for by multiplying the vacancy site fraction on interstitial mobility
    - Mobility is defined in terms of a kinetic parameter (\Omega) that describes the rate of exchange for a component given that
      it is near a vacancy
        - For substitutionals, we define mobility M = y_VA * \Omega, so the mobility term itself includes the vacancy fraction
          since in practice, the vacancy fraction is near 0
        - For interstitials, we define mobility M = \Omega, so it does not factor in the vacancy fraction. Thus we have to
          include the vacancy fraction to represent the probability that the component is near a vacancy
    - We can override this assumption for interstitials using the vacancy_poor_interstitial_sublattice parameter. This can
      be useful for compounds like carbides, where the interstitial sublattice is mostly carbon and the vacancy fraction is near 0

Returns
-------
Matrix of floats
    Each index along an axis correspond to elements in alphabetical order

def chemical_diffusivity(chemical_potentials, composition_set, mobility_callables, mobility_correction = None, returnHessian = False, vacancy_poor_interstitial_sublattice = False, parameters = {}):

Chemical diffusivity (D_kj)
    D_kj = sum((delta_ik - U_k) * U_i * M_i) * dmu_i/dU_j
    D_ab = mobility matrix * free energy hessian

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet
mobility_callables : dict
    Pre-computed mobility callables for each element
mobility_correction : dict (optional)
    Factor to multiply mobility by for each given element (defaults to 1)
returnHessian : bool (optional)
    Whether to return chemical potential derivative (defaults to False)

Returns
-------
(matrix of floats, free energy hessian)
    Each index along an axis correspond to elements in alphabetical order
    free energy hessian will be None if returnHessian is False

def interdiffusivity(chemical_potentials, composition_set, refElement, mobility_callables = None, mobility_correction = None, returnHessian = False, vacancy_poor_interstitial_sublattice = False, parameters = {}):

Interdiffusivity (D^n_ab)

D^n_ab = D_ab - D_an (for substitutional element)
D^n_ab = D_ab (for interstitial element)

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet
refElement : str
    Reference element n
mobility_callables : dict (optional)
    Pre-computed mobility callables for each element
mobility_correction : dict (optional)
    Factor to multiply mobility by for each given element (defaults to 1)
returnHessian : bool (optional)
    Whether to return chemical potential derivative (defaults to False)

Returns
-------
(matrix of floats, free energy hessian)
    Each index along an axis correspond to elements in 
        alphabetical order excluding reference element
    free energy hessian will be None if returnHessian is False

def inverseMobility(chemical_potentials, composition_set, refElement, mobility_callables, mobility_correction = None, returnOther = True, vacancy_poor_interstitial_sublattice = False, parameters = {}):

Inverse mobility matrix for determining interfacial composition from 
    Philippe and P. W. Voorhees, Acta Materialia 61 (2013) p. 4237

M^-1 = (free energy hessian) * Dnkj^-1

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet
refElement : str
    Reference element n
mobility_callables : dict
    Pre-computed mobility callables for each element
mobility_correction : dict (optional)
    Factor to multiply mobility by for each given element (defaults to 1)
returnOther : bool (optional)
    Whether to return interdiffusivity and hessian (defaults to False)

Returns
-------
(interdiffusivity, hessian, inverse mobility)
    Interdiffusivity and hessian will be None if returnOther is False

def tracer_diffusivity_from_diff(composition_set, diffusivity_callables = None, diffusivity_correction = None, parameters = {}):

Tracer diffusivity from diffusivity callables

This will just return the Da as an array

Parameters
----------
composition_set : pycalphad.core.composition_set.CompositionSet
diffusivity_callables : dict
    Pre-computed diffusivity callables for each element
diffusivity_correction : dict (optional)
    Factor to multiply diffusivity by for each given element (defaults to 1)

Returns
-------
Array of floats of diffusivity for each element (alphabetical order)

def interdiffusivity_from_diff(composition_set, refElement, diffusivity_callables, diffusivity_correction = None, parameters = {}):

Interdiffusivity (D^n_ab) calculated from diffusivity callables
    This is if the TDB database only has diffusivity data and no mobility data

D^n_ab = D_ab - D_an (for substitutional element)
D^n_ab = D_ab (for interstitial element)

Parameters
----------
composition_set : pycalphad.core.composition_set.CompositionSet
refElement : str
    Reference element n
diffusivity_callables : dict
    Pre-computed callables for diffusivity for each element
diffusivity_correction : dict
    Factor to multiply diffusivity by for each element (defaults to 1)

Returns
-------
matrix of floats
    Each index along an axis correspond to elements in 
        alphabetical order excluding reference element

def inverseMobility_from_diffusivity(chemical_potentials, composition_set, refElement, diffusivity_callables, diffusivity_correction = None, returnOther = True, parameters = {}):

Inverse mobility matrix for determining interfacial composition

M^-1 = (free energy hessian) * Dnkj^-1

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet
refElement : str
    Reference element n
diffusivity_callables : dict
    Pre-computed callables for diffusivity for each element
diffusivity_correction : dict
    Factor to multiply diffusivity by for each element (defaults to 1)
returnOther : bool (optional)
    Whether to return interdiffusivity and hessian (defaults to False)

Returns
-------
(interdiffusivity, hessian, inverse mobility)
    Interdiffusivity and hessian will be None if returnOther is False

kawin.kawin.thermo.FreeEnergyHessian

def hessian(chemical_potentials, composition_set):

Returns the hessian of the objective function for a single phase

For the Lagrangian function
    L = N * G + sum(mu_A * (N_A - N * dM_A/dy_i)) + sum(lambda_s * (1 - sum(y_i)))
We have 5 derivatives
d2L/dyi2 = N * d2G/dyi2
d2L/dyidlambda_s = -1 if y_i in s else 0
d2L/dyidN = dG/dy - sum(mu_A * dM_A/dy_i)
d2L/dyidmu_A = -N dM_A/dy_i
d2L/dmu_AdN = -M_A

Everything is per mole of formula unit, so N has to be corrected for phases where the 
total moles of atoms could be off from 1

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet

Returns
-------
Matrix of floats for each second derivative
Derivatives along each axis will be in order of:
    site fractions, phase amount, lagrangian multipliers, chemical potential

def totalddx(chemical_potentials, composition_set, refElement):

Total derivative of site fractions, phase amount, lagrangian multipliers 
and chemical potential with respect to system composition
d/dx = partial d/dxA - partial d/dxR where R is reference

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet
refElement : str
    Reference element

Returns
-------
Array of floats for each derivative
Derivatives will be in order of:
    site fractions, phase amount, lagrangian multipliers, chemical potential

def partialddx(chemical_potentials, composition_set):

Partial derivative of site fractions, phase amount, lagrangian multipliers 
and chemical potential with respect to system composition

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet

Returns
-------
Array of floats for each derivative
Derivatives will be in order of:
    site fractions, phase amount, lagrangian multipliers, chemical potential

def dMudX(chemical_potentials, composition_set, refElement):

Total derivative of chemical potential with respect to system composition
dmuA/dxB = (partial dmuA/dxB - partial dmuA/dxR) - (partial dmuR/dxB - partial dmuR/dxR) 
where R is reference

This more or less represents the curvature of the free energy surface with reference element R

Rows correspond to mu_A and columns correspond to X_A so for ternary system with (A,B,R), its
|   dmu_A/dX_A   dmu_A/dX_B   |
|   dmu_B/dX_A   dmu_B/dX_B   |

Parameters
----------
chemical_potentials : 1-D ndarray
composition_set : pycalphad.core.composition_set.CompositionSet
refElement : str
    Reference element

Returns
-------
Array of floats for each derivative, (n-1 x n-1) matrix
Derivatives will be in alphabetical order of elements

def partialdMudX(chemical_potentials, composition_set):

Partial derivative of chemical potential with respect to system composition

Rows correspond to mu_A and columns correspond to X_A so for binary system, its
|   dmu_A/dX_A   dmu_A/dX_B   |
|   dmu_B/dX_A   dmu_B/dX_B   |

Parameters
----------
composition_set : pycalphad.core.composition_set.CompositionSet

Returns
-------
Array of floats for each derivative, (n x n) matrix
Derivatives will be in alphabetical order of elements

kawin.kawin.thermo.LocalEquilibrium

def local_equilibrium(dbf, comps, phases, conds, models, phase_records, composition_sets=None, pDens=10):

Local equilibrium calculation

Chemical potential in a miscibility gap will be constant
This method allows the user to get the free energy at the specified composition
ignoring possible miscibility gaps

Parameters
----------
dbf: Database
comps: list[str]
    List of elements to consider
phases: list[str]
    List of phases to consider
conds: dict[v.StateVariable, float]
    Dictionary of conditions (v.N needs to be included)
models: dict[str, Model]
phase_records : PhaseRecordFactory
composition_sets: list[CompositionSet] (optional)
    If None, then composition sets will be determined through sampling
pDens: int (optional)
    Sampling density when composition sets are not supplied

Returns
-------
Dataset containing free energy and chemical potential