kawin.thermo (Surrogate)

kawin.kawin.thermo.Surrogate

def generateTrainingPoints(*arrays):

Creates all combinations of inputted arrays
Used for creating training points in composition space for
MulticomponentSurrogate

Parameters
----------
arrays - arrays along each dimension
    Order of arrays should correspond to the order of elements when defining thermodynamic functions

def _filter_points(inputs, outputs, tol = 1e-3):

Filter set of input points such that the closest distance is above tolerance
This is to avoid non-positive definite training matrices when creating surrogate models

Parameters
----------
inputs : m x n matrix of floats
    Input points of m observations in n-dimensional space
outputs : list of array of floats
    Output points, each array must be m x n where
        m is number of observations and n is dimensions of output
tol : float
    Tolerance for distance between two input points

Outputs
-------
(filtered inputs, filtered outputs)
filtered inputs - array of input points
filtered outputs - array of output points

NumpyEncoder(json.JSONEncoder)

Converts all numpy arrays to list, to be used when serializing surrogate data
We don't need custom decoding, since the surrogate model should convert lists to numpy arrays if needed

def NumpyEncoder.default(self, data):

SurrogateKernel(ABC)

class SurrogateKernel(self, x, y, *args, **kwargs):

Abstract class for kernel

Attributes
  __init__ - builds the surrogate model from x and y, and may use *args and **kwargs for hyperparameters
  predict - returns a y-like output from an x-like input

def SurrogateKernel.predict(self, x):

RBFKernel(SurrogateKernel)

class RBFKernel(self, x, y, *args, **kwargs):

Surrogate kernel using scipy radial basis function (RBFInterpolator)
An additional parameter, 'normalize', can be used to normalize all dimensions of x from [0,1]

def RBFKernel.predict(self, x):

GeneralSurrogate

class GeneralSurrogate(self, thermodynamics: GeneralThermodynamics, kernel:SurrogateKernel=RBFKernel, kernelKwargs={‘kernel’:‘cubic’, ‘normalize’:True}):

By default, the untrained surrogate will use the thermodynamic functions

As we train a model, it will be added to the model and replace the underlying thermodynamics
Then any untrained model will still go back to the thermodynamic functions

The intent of this is that the surrogate models API will be similar to the
underlying thermodynamic modules
    Driving force
    Tracer diffusivity
    Interdiffusivity
    Interfacial composition - binary only
    Curvature factor - multicomponent only
    Impingement rate - multicomponent only

Parameters
----------
thermodynamics: GeneralThermodynamics, BinaryThermodynamics, MulticomponentThermodynamics
kernel: SurrogateKernel (optional)
    Defaults to RBFKernel
kernelKwargs: dict (optional)
    arguments for kernel
    Defaults to {'kernel': 'cubic', 'normalize': True}

def GeneralSurrogate._processCompositionInput(self, x, T, broadcast = True):

Makes sure x and T are np arrays
If broadcasting, then x and T will be computed as a grid

Parameters
x : float, np.array
T : float, np.array
broadcast : bool (optional)
    Defaults to True
    If True, will create a grid over x and T
    If False, x and T represents all points and must have the same length

def GeneralSurrogate._createInput(self, xs, singleXs):

Create input data for the surrogate model by validating number of unique points in each dimension

def GeneralSurrogate.trainDrivingForce(self, x, T, precPhase=None, logX = False, broadcast=True):

Creates surrogate model for driving force
Model will be in the form of (dg, x) = f(x, T) or (dg, x) = f(ln(x), T)

If only single x or T, then surrogate model will only be trained on
non-scalar axis

Parameters
----------
x : float, np.array
    If binary, shape of x must be () or (N,)
    If multicomponent, shape of x must be (e,) or (N,e)
T : float, np.array
precPhase : str (optional)
    Defaults to None
    If None, defaults to first precipitate phase
logX : bool (optional)
    Defaults to False
    If True, fits composition on a log scale
broadcast : bool (optional)
    Defaults to True
    If True, will create grid of points over x and T

def GeneralSurrogate._fitDrivingForce(self, phase):

Fits driving force data for phase

def GeneralSurrogate.getDrivingForce(self, x, T, precPhase=None, *args, **kwargs):

Computes driving force

If surrogate model for driving force has not been trained, this will use the underlying thermodynamics function

Parameters
----------
x : float, np.array
    If binary, shape of x must be () or (N,)
    If multicomponent, shape of x must be (e,) or (N,e)
T : float, np.array
precPhase : str (optional)
    Defaults to None
    If None, defaults to first precipitate phase

def GeneralSurrogate.trainDiffusivity(self, x, T, phase=None, logX=False, broadcast=True):

Creates surrogate model for diffusivity
Model will be in the form of (Dnkj^1/3, D*^1/3) = f(x, 1/T) or (Dnkj^1/3, D*^1/3) = f(ln(x), 1/T)
The cubic transformation is used since Dnkj may be negative due to chemical potential gradients

If only single x or T, then surrogate model will only be trained on
non-scalar axis

Parameters
----------
x : float, np.array
    If binary, shape of x must be () or (N,)
    If multicomponent, shape of x must be (e,) or (N,e)
T : float, np.array
precPhase : str (optional)
    Defaults to None
    If None, defaults to first precipitate phase
logX : bool (optional)
    Defaults to False
    If True, fits composition on a log scale
broadcast : bool (optional)
    Defaults to True
    If True, will create grid of points over x and T

def GeneralSurrogate._fitDiffusivity(self, phase):

Fits driving force data for phase

def GeneralSurrogate._getDiffusivity(self, x, T, phase):

Evaluates diffusivity from surrogate model

def GeneralSurrogate.getInterdiffusivity(self, x, T, phase=None, *args, **kwargs):

Computes interdiffusivity

If surrogate model for driving force has not been trained, this will use the underlying thermodynamics function

Parameters
----------
x : float, np.array
    If binary, shape of x must be () or (N,)
    If multicomponent, shape of x must be (e,) or (N,e)
T : float, np.array
precPhase : str (optional)
    Defaults to None
    If None, defaults to first precipitate phase

def GeneralSurrogate.getTracerDiffusivity(self, x, T, phase=None, *args, **kwargs):

Computes tracer diffusivity

If surrogate model for driving force has not been trained, this will use the underlying thermodynamics function

Parameters
----------
x : float, np.array
    If binary, shape of x must be () or (N,)
    If multicomponent, shape of x must be (e,) or (N,e)
T : float, np.array
precPhase : str (optional)
    Defaults to None
    If None, defaults to first precipitate phase

def GeneralSurrogate._collectSurrogateData(self):

Creates dictionary of surrogate training data

def GeneralSurrogate._processSurrogateData(self, data):

Stores surrogate training data from dict and trains models

def GeneralSurrogate.toJson(self, filename: str | Path):

Saves surrogate data to json

def GeneralSurrogate.fromJson(self, filename: str | Path):

Loads surrogate data from json

BinarySurrogate(GeneralSurrogate)

class BinarySurrogate(self, thermodynamics: BinaryThermodynamics, kernel:SurrogateKernel=RBFKernel, kernelKwargs={‘kernel’:‘cubic’, ‘normalize’:True}):

Same as GeneralSurrogate but implements models for interfacial composition

def BinarySurrogate._processGibbsThompsonInput(self, T, gExtra, broadcast = False):

Makes sure T and gExtra are np arrays
If broadcasting, then T and gExtra will be computed as a grid

def BinarySurrogate.trainInterfacialComposition(self, T, gExtra, precPhase=None, logY = False, broadcast=True):

Creates surrogate model for interfacial composition
Model will be in the form of (xa, xb) = f(T, 1/gExtra) or (ln(xa), xb) = f(T, 1/gExtra)

If only single T or gExtra, then surrogate model will only be trained on
non-scalar axis

Parameters
----------
T : float, np.array
gExtra : float, np.array
precPhase : str (optional)
    Defaults to None
    If None, defaults to first precipitate phase
logY : bool (optional)
    If True, will fit interfacial composition on a log scale
broadcast : bool (optional)
    If True, will create grid of points from T and gExtra

def BinarySurrogate._fitInterfacialComposition(self, phase):

Fits driving force data for phase

def BinarySurrogate.getInterfacialComposition(self, T, gExtra=0, precPhase=None):

Computes interfacial composition

Parameters
----------
T : float, np.array
gExtra : float, np.array (optional)
    Defaults to 0
precPhase : str (optional)
    Defaults to None
    If None, defaults to first precipitate phase

def BinarySurrogate._collectSurrogateData(self):

Adds interfacial composition data to GeneralSurrogate surrogate data

def BinarySurrogate._processSurrogateData(self, data):

Stores interfacial composition data and fits models along with models from GeneralSurrogate

MulticomponentSurrogate(GeneralSurrogate)

class MulticomponentSurrogate(self, thermodynamics: MulticomponentThermodynamics, kernel:SurrogateKernel=RBFKernel, kernelKwargs={‘kernel’:‘cubic’, ‘normalize’:True}):

Same as GeneralSurrogate but implements models for curvature factors
    Curvature factor can then be used for growth rate, interfacial composition and impingement rate

def MulticomponentSurrogate.trainCurvature(self, x, T, precPhase=None, logX = False, broadcast=True):

Trains curvature factors

Parameters
----------
x : np.array
    Shape of (e,) of (N,e)
T : float, np.array
precPhase : str (optional)
    Defaults to None, which is first precipitate phase
logX : bool (optional)
    Defaults to False
    If True, then x and matrix interfacial composition will be fitted on a log scale
broadcast : bool (optional)
    Defaults to True
    If True, then a grid a points will be generated over x and T

def MulticomponentSurrogate._fitCurvature(self, phase):

Fits cuvature data for phase

def MulticomponentSurrogate._surrogateOutputToCurvature(self, output, numEle, logX):

Converts surrogate output to CurvatureOutput

def MulticomponentSurrogate.curvatureFactor(self, x, T, precPhase = None, *args, **kwargs):

Computes curvature factors

Parameters
----------
x : np.array
    Shape of (e,)
T : float
precPhase : str (optional)
    Defaults to None, which is first precipitate phase

def MulticomponentSurrogate.getGrowthAndInterfacialComposition(self, x, T, dG, R, gExtra, precPhase = None, *args, **kwargs):

Computes growth rate and interfacial composition

Parameters
----------
x : np.array
    Shape of (e,)
T : float
dG : float
    Driving force at x,T
R : float, np.array
    Precipitate radius
gExtra : float, np.array
    Gibbs-Thomson contribution corresponding to R
precPhase : str (optional)
    Defaults to None, which is first precipitate phase

def MulticomponentSurrogate.impingementFactor(self, x, T, precPhase = None, *args, **kwargs):

Computes impingement factor

Parameters
----------
x : np.array
    Shape of (e,)
T : float
precPhase : str (optional)
    Defaults to None, which is first precipitate phase

def MulticomponentSurrogate._collectSurrogateData(self):

Adds interfacial composition data to GeneralSurrogate surrogate data

def MulticomponentSurrogate._processSurrogateData(self, data):

Stores interfacial composition data and fits models along with models from GeneralSurrogate