Non-Ideal Contributions
The default options in the KWN model assumes bulk nucleation and a spherical precipitate. However, in real-life systems, these assumptions may not be true. Several options are present to model heterogenous nucleation and non-spherical precipitate shapes.
Nucleation
The options for the nucleation site density includes the following: ‘bulk’, ‘dislocations’, ‘grain_boundaries’, ‘grain_edges’, ‘grain_corners’
The nucleation site density ($N_0$) for bulk nucleation is determined by the number of solutes in the bulk lattice. For dislocation, $N_0$ depends on the dislocation density. $N_0$ for grain boundaries, edges and corners depends on the grain size [1]. For grain boundary nucleation, the change in surface energy accounts for both the creation of the precipitate/matrix interface and removal of grain boundary, for which the grain boundary energy must be defined [2]. By default, the grain boundary energy is set to 0.3 $J/m^2$.
While the KWNModel will automatically calculate the nucleation site densities for each site type, these values can be manually set.
1 import numpy as np
2 import matplotlib.pyplot as plt
3 from kawin.precipitation import PrecipitateParameters, MatrixParameters
4
5 matrix = MatrixParameters(['A'])
6 matrix.volume.setVolume(1e-5, 'VM', 4)
7 matrix.nucleationSites.setDislocationDensity(5e12)
8 print(f'Dislocation N0: {matrix.nucleationSites.dislocationN0}')
9
10 matrix.nucleationSites.setGrainSize(grainSize=10, aspectRatio=1)
11 print(f'Grain boundary N0: {matrix.nucleationSites.GBareaN0}')
12 print(f'Grain edge N0: {matrix.nucleationSites.GBedgeN0}')
13 print(f'Grain corner N0: {matrix.nucleationSites.GBcornerN0}')
14
15 matrix.nucleationSites.setBulkDensityFromComposition(0.05)
16 print(f'Bulk N0: {matrix.nucleationSites.bulkN0}')
17
18 fig, ax = plt.subplots(1, 3, figsize=(10,3))
19
20
21 params = PrecipitateParameters('beta')
22 boundaryTypes = ['bulk', 'dislocations', 'grain boundaries', 'grain edges', 'grain corners']
23 gbEnergy = 0.3
24 gamma = np.linspace(0, 0.5, 100)
25 for b in boundaryTypes:
26 params.nucleation.setNucleationType(b)
27 gbk = params.nucleation.description.gbRatio(gbEnergy, gamma)
28 gbRemoval = params.nucleation.description.gbRemoval(gbk)
29 areaFactor = params.nucleation.description.areaFactor(gbk)
30 volumeFactor = params.nucleation.description.volumeFactor(gbk)
31 ax[0].plot(gamma, gbRemoval, label=b)
32 ax[1].plot(gamma, areaFactor)
33 ax[2].plot(gamma, volumeFactor)
34 ax[0].legend()
35 ylabels = ['Grain Boundary Removal', 'Area Factor', 'Volume Factor']
36 for i in range(len(ax)):
37 ax[i].set_xlim([0, 0.4])
38 ax[i].set_ylim(bottom=0)
39 ax[i].set_xlabel('Interfacial Energy')
40 ax[i].set_ylabel(ylabels[i])
41 fig.tight_layout()
42 plt.show()
Dislocation N0: 1.959823321572584e+22
Grain boundary N0: 5.143860347725449e+24
Grain edge N0: 3.325930465467644e+20
Grain corner N0: 1.2000000000000004e+16
Bulk N0: 3.011e+27

Shape factors
Currently, the KWN model has support for ellipsoidal (prolate/needle and oblate/plate) and cuboidal precipitates. For cuboidal precipitates the cubic factor currently set constant at $\sqrt{2}$ [3,4]. These shapes are defined in the KWN model by their equivalent spherical radius ($R_{sph}$) and an aspect ratio ($\alpha$), where the $\alpha$ can either be constant or as a function of $R_{sph}$.
The aspect ratio is defined as the ratio of the long axis over the short axis. Conversion between the radius along the short axis ($r$) and the equivalent spherical radius ($R_{sph}$) is given by:
Needle: $ R_{sph} = \sqrt[3]{\alpha} r $
Plate: $ R_{sph} = \sqrt[3]{\alpha^2} r $
Cuboidal: $ R_{sph} = \sqrt[3]{\frac{3 \alpha}{4 \pi}} r $
Deviation from a spherical precipitate changes both the thermodynamics (Gibbs-Thomson effect) and kinetics (growth rate). The free energy contribution from the Gibbs-Thomson effect is given by:
$$ \Delta G_{TH} = g(\alpha) \frac{2 \gamma V_M^\beta}{R_{sph}} $$
The changes in the growth rate is given by:
$$ \frac{dR}{dt} = f(\alpha) \frac{dR_{sph}}{dt} $$
The functions of $g(\alpha)$ and $f(\alpha)$ are taken from Ref. 3 and 4.
43 from kawin.precipitation import PrecipitateParameters
44
45 fig, ax = plt.subplots(1, 2, figsize=(6,3))
46
47 params = PrecipitateParameters('beta')
48
49 arFunc = lambda r: 2.3 * (r/1e-9)**1.1
50 r = np.linspace(1e-10, 1e-8, 100)
51 shapes = ['sphere', 'cubic', 'needle', 'plate']
52 for s in shapes:
53 params.shapeFactor.setPrecipitateShape(s, arFunc)
54 kineticFactor = params.shapeFactor.kineticFactor(r)
55 thermoFactor = params.shapeFactor.thermoFactor(r)
56 ax[0].plot(r, kineticFactor, label=s)
57 ax[1].plot(r, thermoFactor)
58
59 ylabels = [r'f($\alpha$)', r'g($\alpha$)']
60 for i in range(len(ax)):
61 ax[i].set_xlim([0, 1e-8])
62 ax[i].set_ylim(bottom=0.9)
63 ax[i].set_xlabel('Radius (nm)')
64 ax[i].set_ylabel(ylabels[i])
65
66 ax[0].legend()
67 fig.tight_layout()
68 plt.show()

Strain Energy
Molar volume differences between the matrix and precipitate phase can induce strains, which reduces the driving force for nucleation. For spherical and cuboidal precipitates, the strain energy can be calculated by Khachaturyan’s approximation. For ellipsoidal precipitates, the strain energy can be calculated using Eshelby’s tensor [4,5].
Similar to the Thermodynamics and Surrogate modules, the strain energy is calculated using a module separated from KWNBase. Inserting the strain energy parameters requires creating and setting up a StrainEnergy object, then inserting it into the KWN model for a specified phase.
The StrainEnergy object requires the elastic constants and eigenstrains to be defined. External stresses can also be defined if applicable. The eigenstrains and external stress can be defined as a tensor (3x3), values along the three axes (array of length 3), or a single value to be applied on all 3 axes. The elastic constants can be defined using its 6x6 tensor, the three elastic constants ($c_{11}$, $c_{12}$ and $c_{44}$), or by at least two moduli (e.g. elastic modulus, poission ratio, shear modulus, bulk modulus, etc.)
69 from kawin.precipitation import PrecipitateParameters
70
71 params = PrecipitateParameters('beta')
72 params.strainEnergy.setModuli(E=100e9, nu=0.3)
73
74 #Set eigenstrains
75 # [[0.01, 0.00, 0.00]
76 # [0.00, 0.01, 0.00]
77 # [0.00, 0.00, 0.02]]
78 params.strainEnergy.setEigenstrain([0.01, 0.01, 0.02])
79 params.shapeFactor.setPrecipitateShape('needle')
80 params.calculateAspectRatio = True
Strain Energy Example (Cu-Ti system)
In the Cu-Ti system (dilute Ti), the needle-like $Cu_4Ti$ precipitate creates lattice strains in the Cu-matrix. The following parameters are applicable to this system (from K. Wu et al (2018)):
Eigenstrains of the $Cu_4Ti$ precipitate:
$ \epsilon_{11} = 0.022 $
$ \epsilon_{22} = 0.022 $
$ \epsilon_{33} = 0.003 $
Elastic constants for the Cu matrix
$ c_{11} = 168.4 \quad GPa $
$ c_{12} = 121.4 \quad GPa $
$ c_{44} = 75.4 \quad GPa $
We can use these values to determine the strain energy of the $Cu_4Ti$ precipitate for any given aspect ratio. In this example, we’ll vary the aspect ratio from 1 to 2 and calculate the strain energy. The volume of the precipitate will be set constant to the volume of a sphere with a radius of 4 nm.
81 %matplotlib inline
82 import matplotlib.pyplot as plt
83 import numpy as np
84
85 from kawin.precipitation import StrainEnergy
86
87 se = StrainEnergy()
88
89 #By default, StrainEnergy outputs 0
90 #This is changed within the KWN model before the model is solved for
91 #However, we can manually change it. For this example, we need to set it to the calculate for ellipsoidal shapes
92 se.setEllipsoidal()
93
94 #Set elastic tensor by c11, c12 and c44 values
95 se.setElasticConstants(168.4e9, 121.4e9, 75.4e9)
96
97 #Set eigenstrains
98 se.setEigenstrain([0.022, 0.022, 0.003])
99
100 #Aspect ratio
101 aspect = np.linspace(1, 2, 100)
102
103 #Equivalent spherical radius of 4 nm
104 rSph = 4e-9 / np.cbrt(aspect)
105 r = np.array([rSph, rSph, aspect*rSph]).T
106
107 E = se.compute(r)
108
109 plt.plot(aspect, E)
110 plt.xlim([1, 2])
111 plt.ylim([1.0e-17, 1.5e-17])
112 plt.xlabel('Aspect Ratio')
113 plt.ylabel('Strain Energy (J)')
114 plt.show()

Calculating Aspect Ratio from Strain Energy
The aspect ratio for plate- and needle-like precipitates can be determined by minimizing the energy contributions from the strain and interfacial energy contributions.
$$ \alpha = argmin\left( \frac{4}{3}\pi R_{sph}^{3} \Delta G_{el}(\alpha) + 4 \pi R_{sph}^{2} g(\alpha) \gamma \right) $$
Where $R_{sph}$ is the equivalent spherical radius. The strain energy module has two options for calculating the equilibrium aspect ratio: iterative or searching. The iterative method (StrainEnergy.eqAR_byGR) performs a Golden Section search to find the minimum. The search method (StrainEnergy.eqAR_bySearch) will calculate the net energy contribution for a number of aspect ratios and will return the aspect ratio that gives the minimum. By default, this method is accurate up to 2 significant digits. In addition, due to caching, this method is also faster than the iterative method for large number of calculations.
Example ($\gamma''$ in IN718)
The $\gamma''$ precipitate in IN718 are plate shape where the aspect ratio depends on the size of the precipitate. Using the elastic properties of IN718 (shear modulus of 57.1 GPa and Poisson’s ratio of 0.33) and the eigenstrain of the $\gamma''$ precipitate, the relationship between the aspect ratio and precipitate diameter (long axis) can be found.
115 from kawin.precipitation import ShapeFactor
116
117 #Strain energy parameters
118 se = StrainEnergy()
119 se.setEigenstrain([6.67e-3, 6.67e-3, 2.86e-2])
120 se.setModuli(G=57.1e9, nu=0.33)
121 se.setEllipsoidal()
122
123 #Shape factor parameters (only the shape needs to be defined)
124 sf = ShapeFactor('plate')
125
126 #Calculate equilibrium aspect ratio
127 gamma = 0.02375
128 Rsph = np.linspace(1e-10, 40e-9, 100)
129 eqAR = se.eqAR_bySearch(Rsph, gamma, sf)
130
131 #Convert spherical radius to diameter of the plate
132 R = 2*Rsph*eqAR / np.cbrt(eqAR**2)
133
134 #Plot diameter vs. aspect ratio
135 plt.plot(R, eqAR)
136 plt.xlim([0, 40e-9])
137 plt.ylim([1, 9])
138 plt.xlabel('Diameter (m)')
139 plt.ylabel('Aspect Ratio')
140 plt.show()

References
- Kozeschnik, Ernst et al. Precipitation Modeling, Momentum Press, 2012
- P. J. Clemm and J. C. Fisher, “The Influence of Grain Boundaries on the Nucleation of Secondary Phases” Acta Metallurgica 3 (1955) p. 70
- B. Holmedal, E. Osmundsen, Q. Du, “Precipitation of Non-Spherical Particles in Aluminum Alloys Part I: Generalization of the Kampmann-Wagner Numerical Model” Metallurgical and Materials Transactions A 47 (2016) p. 581
- K. Wu, Q. Chen and P. Mason, “Simulation of Precipitation Kinetics with Non-Spherical Particles” J. Phase Equilib. Diffus. 39 (2018) p. 571
- C. Weinberger, W. Cai and D. Barnett, ME340B Lecture Notes - Elasticity of Microscopic Structures, Standford University 2005. http://micro.standford.edu/~caiwei/me340b/content/me340b-notes_v01.pdf