https://mooseframework.inl.gov
KKSPhaseConcentrationMaterial.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
11 #include "MatrixTools.h"
12 
14 
17 {
19  params.addClassDescription("Computes the KKS phase concentrations by using nested Newton "
20  "iteration to solve the equal chemical "
21  "potential and concentration conservation equations. This class is "
22  "intended to be used with KKSPhaseConcentrationDerivatives.");
23  params.addRequiredCoupledVar("global_cs", "The interpolated concentrations c, b, etc.");
24  params.addRequiredParam<MaterialPropertyName>("h_name", "Switching function h(eta).");
25  params.addRequiredParam<std::vector<MaterialPropertyName>>(
26  "ci_names",
27  "Phase concentrations. The order must match Fa, Fb, and global_cs, for example, c1, c2, b1, "
28  "b2, etc.");
29  params.addRequiredParam<std::vector<Real>>("ci_IC",
30  "Initial values of ci in the same order as ci_names.");
31  params.addRequiredParam<MaterialName>("fa_name", "Fa material object.");
32  params.addRequiredParam<MaterialName>("fb_name", "Fb material object.");
33  params.addParam<MaterialPropertyName>(
34  "nested_iterations",
35  "The output number of nested Newton iterations at each quadrature point.");
36  params.addCoupledVar("args", "The coupled variables of Fa and Fb.");
37  params.addParam<bool>(
38  "damped_Newton", false, "Whether or not to use the damped Newton's method.");
39  params.addParam<MaterialName>("conditions",
40  "C",
41  "Material property that checks bounds and conditions on the "
42  "material properties being solved for.");
43  params += NestedSolve::validParams();
44  return params;
45 }
46 
49  _prop_c(coupledValues("global_cs")),
50  _num_c(coupledComponents("global_cs")),
51  _prop_h(getMaterialProperty<Real>("h_name")),
52  _ci_names(getParam<std::vector<MaterialPropertyName>>("ci_names")),
53  _prop_ci(_num_c * 2),
54  _ci_old(_num_c * 2),
55  _ci_IC(getParam<std::vector<Real>>("ci_IC")),
56  _Fa_name(getParam<MaterialName>("fa_name")),
57  _Fb_name(getParam<MaterialName>("fb_name")),
58  _prop_Fi(2),
59  _Fi_copy(2),
60  _dFidci(_num_c * 2),
61  _dFidci_copy(_num_c * 2),
62  _d2Fidcidbi(2),
63  _d2Fadc1db1_copy(_num_c),
64  _args_names(coupledNames("args")),
65  _n_args(coupledComponents("args")),
66  _dFadarg(_n_args),
67  _dFadarg_copy(_n_args),
68  _dFbdarg(_n_args),
69  _dFbdarg_copy(_n_args),
70  _d2Fadcadarg(_n_args),
71  _d2Fadcadarg_copy(_n_args),
72  _iter(declareProperty<Real>("nested_iterations")),
73  _abs_tol(getParam<Real>("absolute_tolerance")),
74  _rel_tol(getParam<Real>("relative_tolerance")),
75  _damped_newton(getParam<bool>("damped_Newton")),
76  _condition_name(getParam<MaterialName>("conditions")),
77  _nested_solve(NestedSolve(parameters))
78 
79 {
80  // phase concentrations
81  for (const auto m : make_range(_num_c * 2))
82  {
83  _prop_ci[m] = &declareProperty<Real>(_ci_names[m]);
84  _ci_old[m] = &getMaterialPropertyOld<Real>(_ci_names[m]);
85  }
86 
87  // free energies
88  _prop_Fi[0] = &getMaterialPropertyByName<Real>(_Fa_name);
89  _prop_Fi[1] = &getMaterialPropertyByName<Real>(_Fb_name);
90 
91  // declare _fi_copy to be passed to the kernels
92  _Fi_copy[0] = &declareProperty<Real>("cp" + _Fa_name);
93  _Fi_copy[1] = &declareProperty<Real>("cp" + _Fb_name);
94 
95  // derivative of free energy wrt phase concentrations
96  for (const auto m : make_range(_num_c))
97  {
98  _dFidci[m * 2] = &getMaterialPropertyDerivative<Real>(_Fa_name, _ci_names[m * 2]);
99  _dFidci[m * 2 + 1] = &getMaterialPropertyDerivative<Real>(_Fb_name, _ci_names[m * 2 + 1]);
100 
101  // declare _dFidci_copy to be passed to the kernels
102  _dFidci_copy[m * 2] = &declarePropertyDerivative<Real>("cp" + _Fa_name, _ci_names[m * 2]);
103  _dFidci_copy[m * 2 + 1] =
104  &declarePropertyDerivative<Real>("cp" + _Fb_name, _ci_names[m * 2 + 1]);
105  }
106 
107  // Second derivative of free energy wrt phase concentrations for use in this material. In
108  // _d2Fidcidbi[m][n][l], m is phase index of Fi, n is the species index of ci, l is the species
109  // index of bi.
110  for (const auto m : make_range(2))
111  {
112  _d2Fidcidbi[m].resize(_num_c);
113  for (const auto n : make_range(_num_c))
114  {
115  _d2Fidcidbi[m][n].resize(_num_c);
116  for (const auto l : make_range(_num_c))
117  {
118  if (m == 0)
119  _d2Fidcidbi[0][n][l] =
120  &getMaterialPropertyDerivative<Real>(_Fa_name, _ci_names[n * 2], _ci_names[l * 2]);
121 
122  else
123  _d2Fidcidbi[1][n][l] = &getMaterialPropertyDerivative<Real>(
124  _Fb_name, _ci_names[n * 2 + 1], _ci_names[l * 2 + 1]);
125  }
126  }
127  }
128 
129  // _d2Fadc1db1_copy (2D symmetric matrix), to be passed to kernels
130  for (const auto m : make_range(_num_c))
131  {
132  _d2Fadc1db1_copy[m].resize(_num_c);
133  for (const auto n : make_range(_num_c))
134  _d2Fadc1db1_copy[m][n] =
135  &declarePropertyDerivative<Real>("cp" + _Fa_name, _ci_names[m * 2], _ci_names[n * 2]);
136  }
137 
138  // partial derivative of Fa and Fb wrt coupled variables, to be passed to kernels
139  for (const auto m : make_range(_n_args))
140  {
141  _dFadarg[m] = &getMaterialPropertyDerivative<Real>(_Fa_name, _args_names[m]);
142  _dFadarg_copy[m] = &declarePropertyDerivative<Real>("cp" + _Fa_name, _args_names[m]);
143  _dFbdarg[m] = &getMaterialPropertyDerivative<Real>(_Fb_name, _args_names[m]);
144  _dFbdarg_copy[m] = &declarePropertyDerivative<Real>("cp" + _Fb_name, _args_names[m]);
145  }
146 
147  // second partial derivatives of Fa wrt ca and another coupled variable, to be passed to
148  // kernels
149  for (const auto m : make_range(_n_args))
150  {
151  _d2Fadcadarg[m].resize(_num_c);
152  _d2Fadcadarg_copy[m].resize(_num_c);
153  for (const auto n : make_range(_num_c))
154  {
155  _d2Fadcadarg[m][n] =
156  &getMaterialPropertyDerivative<Real>(_Fa_name, _ci_names[n * 2], _args_names[m]);
157  _d2Fadcadarg_copy[m][n] =
158  &declarePropertyDerivative<Real>("cp" + _Fa_name, _ci_names[n * 2], _args_names[m]);
159  }
160  }
161 
162  if (_damped_newton)
163  _C = &getMaterialPropertyByName<Real>(_condition_name);
164  else
165  _C = nullptr;
166 }
167 
168 void
170 {
171  for (const auto m : make_range(_num_c * 2))
172  (*_prop_ci[m])[_qp] = _ci_IC[m];
173 }
174 
175 void
177 {
178  _Fa = &getMaterial("fa_name");
179  _Fb = &getMaterial("fb_name");
180  if (_damped_newton)
182 }
183 
184 void
186 {
187  // parameters for nested Newton iteration
188  NestedSolve::Value<> solution(_num_c * 2);
189 
190  for (unsigned int m = 0; m < _num_c * 2; ++m)
191  solution(m) = (*_ci_old[m])[_qp];
192 
195 
196  auto compute = [&](const NestedSolve::Value<> & guess,
197  NestedSolve::Value<> & residual,
198  NestedSolve::Jacobian<> & jacobian)
199  {
200  for (const auto m : make_range(_num_c * 2))
201  (*_prop_ci[m])[_qp] = guess(m);
202 
205 
206  // assign residual functions
207  for (const auto m : make_range(_num_c))
208  {
209  residual(m * 2) = (*_dFidci[m * 2])[_qp] - (*_dFidci[m * 2 + 1])[_qp];
210  residual(m * 2 + 1) = (1 - _prop_h[_qp]) * (*_prop_ci[m * 2])[_qp] +
211  _prop_h[_qp] * (*_prop_ci[m * 2 + 1])[_qp] - (*_prop_c[m])[_qp];
212  }
213 
214  jacobian.setZero();
215 
216  // fill in the non-zero elements in jacobian
217  for (const auto m : make_range(_num_c))
218  {
219  for (const auto n : make_range(_num_c))
220  {
221  // equal chemical potential derivative equations
222  jacobian(m * 2, n * 2) = (*_d2Fidcidbi[0][m][n])[_qp];
223  jacobian(m * 2, n * 2 + 1) = -(*_d2Fidcidbi[1][m][n])[_qp];
224  }
225  // concentration conservation derivative equations
226  jacobian(m * 2 + 1, m * 2) = 1 - _prop_h[_qp];
227  jacobian(m * 2 + 1, m * 2 + 1) = _prop_h[_qp];
228  }
229  };
230  auto computeCondition = [&](const NestedSolve::Value<> & guess) -> Real
231  {
232  for (const auto m : make_range(_num_c * 2))
233  (*_prop_ci[m])[_qp] = guess(m);
235  return ((*_C)[_qp]);
236  };
237  // choose between Newton or damped Newton's method
238  if (!_damped_newton)
239  _nested_solve.nonlinear(solution, compute);
240  else
241  _nested_solve.nonlinearDamped(solution, compute, computeCondition);
243 
244  if (_nested_solve.getState() == NestedSolve::State::NOT_CONVERGED)
245  mooseException("Nested Newton iteration did not converge.");
246 
247  // assign solution to ci
248  for (const auto m : make_range(_num_c * 2))
249  (*_prop_ci[m])[_qp] = solution[m];
250 
251  // assign to the copied parameters to be used in kernels
252  for (const auto m : make_range(2))
253  (*_Fi_copy[m])[_qp] = (*_prop_Fi[m])[_qp];
254 
255  for (const auto m : make_range(_num_c * 2))
256  (*_dFidci_copy[m])[_qp] = (*_dFidci[m])[_qp];
257 
258  for (const auto m : make_range(_num_c))
259  {
260  for (const auto n : make_range(_num_c))
261  (*_d2Fadc1db1_copy[m][n])[_qp] = (*_d2Fidcidbi[0][m][n])[_qp];
262  }
263 
264  for (const auto m : make_range(_n_args))
265  {
266  (*_dFadarg_copy[m])[_qp] = (*_dFadarg[m])[_qp];
267  (*_dFbdarg_copy[m])[_qp] = (*_dFbdarg[m])[_qp];
268  }
269 
270  for (const auto m : make_range(_n_args))
271  {
272  for (const auto n : make_range(_num_c))
273  (*_d2Fadcadarg_copy[m][n])[_qp] = (*_d2Fadcadarg[m][n])[_qp];
274  }
275 }
const std::size_t & getIterations()
virtual void initQpStatefulProperties() override
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
static InputParameters validParams()
std::vector< std::vector< MaterialProperty< Real > * > > _d2Fadcadarg_copy
std::vector< MaterialProperty< Real > * > _dFidci_copy
KKSPhaseConcentrationMaterial(const InputParameters &parameters)
const Real _abs_tol
Absolute and relative tolerance of nested Newton iteration.
std::vector< const MaterialProperty< Real > * > _prop_Fi
const unsigned int _n_args
Number of coupled variables of free energies.
const MaterialName _Fa_name
Free energies.
const std::vector< const VariableValue * > _prop_c
Global concentrations.
void addRequiredParam(const std::string &name, const std::string &doc_string)
MaterialBase * _Fa
Free energy instantiation of the MaterialBase class.
typename std::conditional< N==1, NSReal, typename std::conditional< N==0, NestedSolveTempl< false >::DynamicVector, Eigen::Matrix< NSReal, N, 1 > >::type >::type Value
std::vector< const MaterialProperty< Real > * > _ci_old
const unsigned int _num_c
Number of global concentrations.
std::vector< const MaterialProperty< Real > * > _dFadarg
Derivative of free energies wrt coupled variables .
void nonlinear(V &guess, T &&compute)
const bool _damped_newton
Add damping functionality to nested Newton solve.
InputParameters validParams()
MaterialBase & getMaterial(const std::string &name)
NestedSolve _nested_solve
Instantiation of the NestedSolve class.
std::vector< std::vector< const MaterialProperty< Real > * > > _d2Fadcadarg
registerMooseObject("PhaseFieldApp", KKSPhaseConcentrationMaterial)
std::vector< MaterialProperty< Real > * > _dFadarg_copy
typename std::conditional< N==1, NSReal, typename std::conditional< N==0, NestedSolveTempl< false >::DynamicMatrix, Eigen::Matrix< NSReal, N, N > >::type >::type Jacobian
std::vector< std::vector< MaterialProperty< Real > * > > _d2Fadc1db1_copy
void setRelativeTolerance(Real rel)
MaterialProperty< Real > & _iter
Number of nested Newton iteration.
std::vector< MaterialProperty< Real > * > _Fi_copy
const MaterialProperty< Real > & _prop_h
Switching functions.
MaterialBase & getMaterialByName(const std::string &name, bool no_warn=false, bool no_dep=false)
void addCoupledVar(const std::string &name, const std::string &doc_string)
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
MaterialName _condition_name
Material property that defines the confidence bounds for the newton solve.
std::vector< MaterialProperty< Real > * > _prop_ci
std::vector< std::vector< std::vector< const MaterialProperty< Real > * > > > _d2Fidcidbi
const std::vector< MaterialPropertyName > _ci_names
Phase concentrations.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void setAbsoluteTolerance(Real abs)
IntRange< T > make_range(T beg, T end)
void addClassDescription(const std::string &doc_string)
virtual void computePropertiesAtQp(unsigned int qp)
const std::vector< VariableName > _args_names
Coupled variables of free energies.
std::vector< const MaterialProperty< Real > * > _dFidci
Derivative of free energies wrt phase concentrations .
void nonlinearDamped(V &guess, T &&compute, C &&computeCondition)
const MaterialProperty< Real > * _C
std::vector< MaterialProperty< Real > * > _dFbdarg_copy
std::vector< const MaterialProperty< Real > * > _dFbdarg
Derivative of free energies wrt coupled variables .
const State & getState() const