Line data Source code
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 : 10 : #include "KKSCHBulk.h" 11 : 12 : registerMooseObject("PhaseFieldApp", KKSCHBulk); 13 : 14 : InputParameters 15 11 : KKSCHBulk::validParams() 16 : { 17 11 : InputParameters params = CHBulk<Real>::validParams(); 18 11 : params.addClassDescription("KKS model kernel for the Bulk Cahn-Hilliard term. This operates on " 19 : "the concentration 'c' as the non-linear variable"); 20 22 : params.addRequiredParam<MaterialPropertyName>("fa_name", 21 : "Base name of the free energy function " 22 : "F (f_name in the corresponding " 23 : "derivative function material)"); 24 22 : params.addRequiredParam<MaterialPropertyName>("fb_name", 25 : "Base name of the free energy function " 26 : "F (f_name in the corresponding " 27 : "derivative function material)"); 28 22 : params.addRequiredCoupledVar( 29 : "ca", "phase concentration corresponding to the non-linear variable of this kernel"); 30 22 : params.addRequiredCoupledVar( 31 : "cb", "phase concentration corresponding to the non-linear variable of this kernel"); 32 22 : params.addCoupledVar("args_a", "Vector of additional arguments to Fa"); 33 22 : params.addParam<MaterialPropertyName>( 34 : "h_name", "h", "Base name for the switching function h(eta)"); // TODO: everywhere else this 35 : // is called just "h" 36 11 : return params; 37 0 : } 38 : 39 6 : KKSCHBulk::KKSCHBulk(const InputParameters & parameters) 40 : : CHBulk<Real>(parameters), 41 6 : _ca_var(coupled("ca")), 42 6 : _ca_name(coupledName("ca", 0)), 43 6 : _cb_var(coupled("cb")), 44 12 : _cb_name(coupledName("cb", 0)), 45 12 : _prop_h(getMaterialProperty<Real>("h_name")), 46 6 : _second_derivative_Fa(getMaterialPropertyDerivative<Real>("fa_name", _ca_name, _ca_name)), 47 12 : _second_derivative_Fb(getMaterialPropertyDerivative<Real>("fb_name", _cb_name, _cb_name)) 48 : { 49 : // reserve space for derivatives 50 6 : _second_derivatives.resize(_n_args); 51 6 : _third_derivatives.resize(_n_args); 52 6 : _third_derivatives_ca.resize(_n_args); 53 6 : _grad_args.resize(_n_args); 54 : 55 : // Iterate over all coupled variables 56 18 : for (unsigned int i = 0; i < _n_args; ++i) 57 : { 58 : 59 : // get the second derivative material property (TODO:warn) 60 12 : _second_derivatives[i] = &getMaterialPropertyDerivative<Real>("fa_name", _ca_name, i); 61 : 62 : // get the third derivative material properties 63 12 : _third_derivatives[i].resize(_n_args); 64 36 : for (unsigned int j = 0; j < _n_args; ++j) 65 24 : _third_derivatives[i][j] = &getMaterialPropertyDerivative<Real>("fa_name", _ca_name, i, j); 66 : 67 12 : MooseVariable * cvar = _coupled_standard_moose_vars[i]; 68 : 69 : // third derivative for the on-diagonal jacobian 70 12 : _third_derivatives_ca[i] = 71 12 : &getMaterialPropertyDerivative<Real>("fa_name", _ca_name, _ca_name, cvar->name()); 72 : 73 : // get the gradient 74 12 : _grad_args[i] = &(cvar->gradSln()); 75 : } 76 6 : } 77 : 78 : /** 79 : * Note that per product and chain rules: 80 : * \f$ \frac{d}{du_j}\left(F(u)\nabla u\right) = \nabla u \frac {dF(u)}{du}\frac{du}{du_j} + 81 : * F(u)\frac{d\nabla u}{du_j} \f$ 82 : * which is: 83 : * \f$ \nabla u \frac {dF(u)}{du} \phi_j + F(u) \nabla \phi_j \f$ 84 : */ 85 : RealGradient 86 185200 : KKSCHBulk::computeGradDFDCons(PFFunctionType type) 87 : { 88 : RealGradient res = 0.0; 89 : 90 185200 : switch (type) 91 : { 92 : case Residual: 93 363600 : for (unsigned int i = 0; i < _n_args; ++i) 94 242400 : res += (*_second_derivatives[i])[_qp] * (*_grad_args[i])[_qp]; 95 : 96 121200 : return res; 97 : 98 : case Jacobian: 99 : // the nonlinear variable is c, but the free energy only contains the 100 : // phase concentrations. Equation (23) in the KKS paper gives the chain- 101 : // rule derivative dca/dc 102 : /* Real dcadc = _second_derivative_Fb[_qp] 103 : / ( (1.0 - _prop_h[_qp]) * _second_derivative_Fb[_qp] 104 : + _prop_h[_qp] * _second_derivative_Fa[_qp]); */ 105 : // The (1-h)*X_b, h*X_a pairing is opposite to what the KKSPhaseConcentration kernel does! 106 : 107 : res = _second_derivative_Fa[_qp] * _grad_phi[_j][_qp]; 108 : 109 192000 : for (unsigned int i = 0; i < _n_args; ++i) 110 : res += (*_third_derivatives_ca[i])[_qp] * (*_grad_args[i])[_qp] * _phi[_j][_qp]; 111 : 112 : // convergence improves if we return 0.0 here 113 : return 0.0; // res * dcadc; 114 : } 115 : 116 0 : mooseError("Invalid type passed in"); 117 : } 118 : 119 : Real 120 2048000 : KKSCHBulk::computeQpOffDiagJacobian(unsigned int jvar) 121 : { 122 : // get the coupled variable jvar is referring to 123 : const unsigned int cvar = mapJvarToCvar(jvar); 124 : 125 2048000 : RealGradient res = (*_second_derivatives[cvar])[_qp] * _grad_phi[_j][_qp]; 126 : 127 6144000 : for (unsigned int i = 0; i < _n_args; ++i) 128 4096000 : res += (*_third_derivatives[i][cvar])[_qp] * (*_grad_args[i])[_qp] * _phi[_j][_qp]; 129 : 130 : // keeping this term seems to improve the solution. 131 2048000 : return res * _grad_test[_i][_qp]; 132 : }