Multicomponent Precipitation

This example will use a ternary system (Ni-Cr-Al); however, the setup for any multicomponent system is mostly the same.

Example - The Ni-Cr-Al system

In the Ni-Cr-Al system, $Ni_3(Al,Cr)$ can precipitate into an $\gamma$-Ni (FCC) matrix. As with binary precipitatation, the Thermodynamics module provides some functions to interface with pyCalphad in defining the driving force, growth rate and interfacial composition. Similarly, it is also possible to use user-defined functions for the driving force and nucleation as long as the function parameters and return values are consistent with the ones provides by the Thermodynamics module. Calphad models for the Ni-Cr-Al system was obtained from the STGE database and Dupin et al [1,2]. Mobility data for the Ni-Cr-Al system was obtained from Engstrom and Agren [3].

1  from kawin.thermo import MulticomponentThermodynamics
2  
3  elements = ['NI', 'AL', 'CR', 'VA']
4  phases = ['FCC_A1', 'FCC_L12']
5  therm = MulticomponentThermodynamics('NiCrAl.tdb', elements, phases)

Model Inputs

Setting up model parameters is the same as for binary systems. The only difference is that the initial composition needs to be set as an array where the elements in the array will correspond to the same order of elements when the model was defined. In this case, [0.10, 0.085] corresponds to Ni-10Al-8.5Cr (at.%).

 6  from kawin.precipitation import MatrixParameters, PrecipitateParameters, TemperatureParameters
 7  
 8  a = 0.352e-9        #Lattice parameter
 9  Va = a**3           #Atomic volume of FCC-Ni
10  Vb = Va             #Assume Ni3Al has same unit volume as FCC-Ni
11  atomsPerCell = 4    #Atoms in an FCC unit cell
12  
13  matrix = MatrixParameters(['AL', 'CR'])
14  matrix.initComposition = [0.098, 0.083]
15  matrix.volume.setVolume(Va, 'VA', 4)
16  matrix.nucleationSites.setBulkDensity(1e30)
17  
18  precipitate = PrecipitateParameters('FCC_L12')
19  precipitate.gamma = 0.023
20  precipitate.volume.setVolume(Va, 'VA', 4)
21  precipitate.nucleation.setNucleationType('bulk')
22  
23  T = 1073

Surrogate Modeling

For efficiency, a surrogate model can be made on the driving force and interfacial composition. The surrogate models uses radial-basis function (RBF) interpolation and the scale and basis function can be defined (using RBF interpolation from Scipy).

For multicomponent systems, a surrogate on the driving force and the various terms derived from the curvature of the free energy surface to calculate growth rate and interfacial composition (which will be referred to as “curvature factors”) can be made. Both surrogates will need a set of compositions and temperatures to be trained on. When defining the range to train the surrogate model on, it is recommended to extend the range beyond what is expected to occur during the precipitate simulation.

24  import numpy as np
25  from kawin.thermo import MulticomponentSurrogate, generateTrainingPoints
26  
27  surr = MulticomponentSurrogate(therm)
28  
29  #Train driving force surrogate
30  xAl = np.linspace(0.02, 0.12, 8)
31  xCr = np.linspace(0.02, 0.12, 8)
32  xTrain = generateTrainingPoints(xAl, xCr)
33  surr.trainDrivingForce(xTrain, T)
34  
35  #Train curvature factors surrogate
36  xAl = np.linspace(0.05, 0.23, 16)
37  xCr = np.linspace(0, 0.12, 16)
38  xTrain = generateTrainingPoints(xAl, xCr)
39  surr.trainCurvature(xTrain, T)

Solving the Model

Solving the model is the same as for binary precipitation.

40  from kawin.precipitation import PrecipitateModel
41  
42  model = PrecipitateModel(matrix, precipitate, thermodynamics=surr, temperature=T)
43  model.solve(1e6, verbose=True, vIt = 5000)
N	Time (s)	Sim Time (s)	Temperature (K)	AL	CR	
0	0.0e+00		0.0		1073		9.8000	8.3000	

	Phase	Prec Density (#/m3)	Volume Frac	Avg Radius (m)	Driving Force (J/mol)
	FCC_L12	0.000e+00		0.0000		0.0000e+00	2.4244e+02

N	Time (s)	Sim Time (s)	Temperature (K)	AL	CR	
5000	1.3e+04		16.0		1073		8.8453	8.5602	

	Phase	Prec Density (#/m3)	Volume Frac	Avg Radius (m)	Driving Force (J/mol)
	FCC_L12	6.195e+20		11.2809		3.2945e-08	9.0477e+00

N	Time (s)	Sim Time (s)	Temperature (K)	AL	CR	
7690	1.0e+06		24.7		1073		8.8170	8.5673	

	Phase	Prec Density (#/m3)	Volume Frac	Avg Radius (m)	Driving Force (J/mol)
	FCC_L12	8.595e+18		11.6264		1.3858e-07	2.1507e+00


Plotting

Plotting is also the same as with binary precipitation. Note that plotting composition will plot all components.

44  %matplotlib inline
45  import matplotlib.pyplot as plt
46  from kawin.precipitation.Plot import plotPrecipitateDensity, plotVolumeFraction, plotAverageRadius, plotCriticalRadius, plotComposition, plotEqMatrixComposition
47  
48  fig, axes = plt.subplots(2, 2, figsize=(10, 8))
49  
50  plotPrecipitateDensity(model, ax=axes[0,0])
51  plotVolumeFraction(model, ax=axes[0,1])
52  plotAverageRadius(model, ax=axes[1,0], label=r'$R_{avg}$')
53  plotCriticalRadius(model, ax=axes[1,0], label=r'$R_{crit}$')
54  plotComposition(model, ax=axes[1,1])
55  plotEqMatrixComposition(model, ax=axes[1,1], linestyle='--', color={'AL': 'C0', 'CR': 'C1'}, label={'AL': r'AL$_{eq}$', 'CR': r'CR$_{eq}$'})
56  
57  axes[0,0].set_xlim([1e-1, 1e6])
58  axes[0,1].set_xlim([1e-1, 1e6])
59  axes[1,0].set_xlim([1e-1, 1e6])
60  axes[1,1].set_xlim([1e-1, 1e6])
61  axes[1,1].set_ylim([0.08, 0.1])
62  
63  fig.tight_layout()

Since the $Ni_3(Al,Cr)$ precipiates are non-stoichiometric, there are two ways to compute the composition in the matrix. The first way (done above) is to assume infinitely fast diffusion in the precipitates where the composition throughout a particle is the same as the surface composition, which is computed from equilibrium.

The other way is to account for the time-dependent history of the surface composition. So as the precipitate grows, only the volume that is added to the precipitate has the surface composition. We can simulate this by the setInfinitePrecipitateDiffusivity function, which can be applied to all precipitates or a specified one.

64  precipitate.infinitePrecipitateDiffusion = False
65  
66  model_nodiff = PrecipitateModel(matrix, precipitate, thermodynamics=surr, temperature=T)
67  model_nodiff.solve(1e6, verbose=True, vIt = 5000)
N	Time (s)	Sim Time (s)	Temperature (K)	AL	CR	
0	0.0e+00		0.0		1073		9.8000	8.3000	

	Phase	Prec Density (#/m3)	Volume Frac	Avg Radius (m)	Driving Force (J/mol)
	FCC_L12	0.000e+00		0.0000		0.0000e+00	2.4244e+02

N	Time (s)	Sim Time (s)	Temperature (K)	AL	CR	
5000	1.3e+04		16.3		1073		8.8605	8.5201	

	Phase	Prec Density (#/m3)	Volume Frac	Avg Radius (m)	Driving Force (J/mol)
	FCC_L12	6.242e+20		11.4620		3.3041e-08	9.0234e+00

N	Time (s)	Sim Time (s)	Temperature (K)	AL	CR	
7688	1.0e+06		24.6		1073		8.8334	8.5245	

	Phase	Prec Density (#/m3)	Volume Frac	Avg Radius (m)	Driving Force (J/mol)
	FCC_L12	8.687e+18		11.8163		1.3895e-07	2.1485e+00


When plotting the matrix composition under these two assumptions shows that the matrix composition under the no diffusion assumption will never reach the equilibrium matrix composition. This is due to how the precipitates will never homogenize to the equilibrium precipitate composition.

68  fig, axes = plt.subplots(figsize=(5, 4))
69  
70  plotEqMatrixComposition(model, ax=axes, color='k', linewidth=0.5, label={'AL': r'AL$_{eq}$', 'CR': r'CR$_{eq}$'})
71  plotComposition(model, ax=axes, color={'AL': 'C0', 'CR': 'C1'}, label={'AL': r'AL$_{inf}$', 'CR': r'CR$_{inf}$'})
72  plotComposition(model_nodiff, ax=axes, linestyle='--', color={'AL': 'C0', 'CR': 'C1'}, label={'AL': r'AL$_{nodiff}$', 'CR': r'CR$_{nodiff}$'})
73  
74  axes.legend(loc='upper right')
75  axes.set_xlim([1e-1, 1e6])
76  axes.set_ylim([0.0825, 0.1])
77  
78  fig.tight_layout()

References

  1. A. T. Dinsdale, “SGTE Data for Pure Elements” Calphad 15 (1991) p. 317
  2. N. Dupin, I. Ansara and B. Sundman, “Thermodynamic Re-assessment of the Ternary System Al-Cr-Ni” Calphad 25 (2001) p. 279
  3. A. Engstrom and J. Agren, “Assessment of Diffusional Mobilities in Face-centered Cubic Ni-Cr-Al Alloys” Z. Metallkd. 87 (1996) p. 92