Source code for pycalphad.mapping.utils
from typing import Union
import numpy as np
from pycalphad import variables as v
from pycalphad.core.composition_set import CompositionSet
from pycalphad.mapping.primitives import Point, Node
[docs]
def degrees_of_freedom(point: Union[Point, Node], components: list[str], num_potential_conditions: int):
"""
Degrees of freedom of point defined by Gibbs phase rule
Components + 2 = Phases + DOF
2 is offsetted by the number of potential conditions
Parameters
----------
point : Point or Node
components : [str]
List of components, VA will be ignored
num_potential_conditions : number of variable potential conditions
Returns
-------
int - degrees of freedom, 0 represents an invariant point/node
"""
non_va_comps = len(set(components) - {"VA"})
return non_va_comps + 2 - len(point.stable_composition_sets) - (2 - num_potential_conditions)
[docs]
def is_state_variable(var: v.StateVariable):
"""
Returns whether var is a state variable or not
"""
return isinstance(var, (v.IndependentPotential, v.SystemMolesType))
[docs]
def update_cs_phase_frac(comp_set: CompositionSet, phase_frac: float):
"""
Wrapper to update the phase fraction of a composition set
This just helps with splitting the cs.dof to state variables and constituents when updating
Parameters
----------
comp_set : CompositionSet
phase_frac : float
"""
num_sv = comp_set.phase_record.num_statevars
comp_set.update(comp_set.dof[num_sv:], phase_frac, comp_set.dof[:num_sv])
[docs]
def get_statevars_array(conditions: dict[v.StateVariable, float], state_variables: list[v.StateVariable] = None):
"""
Creates numpy array of state variables in conditions
Parameters
----------
conditions : dict[v.StateVariable, float]
Returns
-------
numpy array of len(state variables)
"""
# If no state variables is given, then grab them from conditions
if state_variables is None:
state_variables = sorted([key for key in conditions if is_state_variable(key)], key=str)
return np.asarray([conditions[sv] for sv in state_variables], dtype=np.float64)
def _sort_axis_by_state_vars(axis_vars: list[v.StateVariable]):
"""
Sorts list of axis variables by [state variables (N, P, T)] + [non-state variables]
Parameters
----------
axis_vars : [v.StateVariable]
Returns
-------
sorted axis vars : [v.StateVariable]
"""
state_vars = [av for av in axis_vars if is_state_variable(av)]
non_state_vars = [av for av in axis_vars if not is_state_variable(av)]
return state_vars + non_state_vars
def _generate_point_with_fixed_cs(point: Point, cs_to_fix: CompositionSet, cs_to_free: CompositionSet):
"""
Generates point with two cs, one fixed and one free
Parameters
----------
point : Point
Point to generate new point from
cs_to_fix : CompositionSet
cs_to_free : CompositionSet
Returns
-------
new_point : Point
Retains same equilibria as previous point
Conditions will be updated with the updated phase fractions of the composition sets
"""
new_point = Point.with_copy(point.global_conditions, point.chemical_potentials, [cs_to_fix], [cs_to_free])
new_point._fixed_composition_sets[0].fixed = True
update_cs_phase_frac(new_point._fixed_composition_sets[0], 0.0)
new_point._free_composition_sets[0].fixed = False
update_cs_phase_frac(new_point._free_composition_sets[0], 1.0)
for key in new_point.global_conditions:
new_point.global_conditions[key] = new_point.get_property(key)
return new_point
def _generate_point_with_free_cs(point: Point, bias_towards_free : bool = False):
"""
Frees all composition sets in point and sets NP to 1/n for all CS
If bias_towards_free, then all free cs in point will have a weight of 2 when normalizing phase fractions
Parameters
----------
point : Point
Point to generate new point from
bias_towards_free : bool
Whether to bias composition towards free phases of previous point
Returns
-------
new_point : Point
Point will all composition sets free
"""
phase_sum = 0
for cs in point.stable_composition_sets:
if bias_towards_free:
phase_sum += 1 if cs.fixed else 2
else:
phase_sum += 1
new_point = Point.with_copy(point.global_conditions, point.chemical_potentials, [], point.stable_composition_sets)
for cs in new_point._free_composition_sets:
if bias_towards_free:
new_amt = 1 if cs.fixed else 2
update_cs_phase_frac(cs, new_amt/phase_sum)
else:
update_cs_phase_frac(cs, 1/phase_sum)
cs.fixed = False
for key in new_point.global_conditions:
new_point.global_conditions[key] = new_point.get_property(key)
return new_point