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

  1. Kozeschnik, Ernst et al. Precipitation Modeling, Momentum Press, 2012
  2. P. J. Clemm and J. C. Fisher, “The Influence of Grain Boundaries on the Nucleation of Secondary Phases” Acta Metallurgica 3 (1955) p. 70
  3. 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
  4. K. Wu, Q. Chen and P. Mason, “Simulation of Precipitation Kinetics with Non-Spherical Particles” J. Phase Equilib. Diffus. 39 (2018) p. 571
  5. 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