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 "MultiSpeciesDiffusionCG.h" 11 : #include "MooseVariableBase.h" 12 : 13 : // Register the actions for the objects actually used 14 : registerMooseAction("ScalarTransportApp", MultiSpeciesDiffusionCG, "add_kernel"); 15 : registerMooseAction("ScalarTransportApp", MultiSpeciesDiffusionCG, "add_bc"); 16 : registerMooseAction("ScalarTransportApp", MultiSpeciesDiffusionCG, "add_variable"); 17 : registerMultiSpeciesDiffusionPhysicsBaseTasks("ScalarTransportApp", MultiSpeciesDiffusionCG); 18 : 19 : InputParameters 20 114 : MultiSpeciesDiffusionCG::validParams() 21 : { 22 114 : InputParameters params = MultiSpeciesDiffusionPhysicsBase::validParams(); 23 114 : params.addClassDescription("Discretizes diffusion equations for several species with the " 24 : "continuous Galerkin finite element method"); 25 114 : params.transferParam<MooseEnum>(MooseVariableBase::validParams(), "order", "variable_order"); 26 : 27 114 : return params; 28 0 : } 29 : 30 114 : MultiSpeciesDiffusionCG::MultiSpeciesDiffusionCG(const InputParameters & parameters) 31 114 : : MultiSpeciesDiffusionPhysicsBase(parameters) 32 : { 33 114 : } 34 : 35 : void 36 114 : MultiSpeciesDiffusionCG::addFEKernels() 37 : { 38 456 : for (const auto s : index_range(_species_names)) 39 : { 40 342 : const auto & var_name = _species_names[s]; 41 : // Diffusion term 42 798 : if (isParamValid("diffusivity_matprops") || isParamValid("diffusivity_functors")) 43 : { 44 : // Select the kernel type based on the user parameters 45 : std::string kernel_type; 46 684 : if (isParamValid("diffusivity_matprops")) 47 285 : kernel_type = _use_ad ? "ADMatDiffusion" : "MatDiffusion"; 48 114 : else if (isParamValid("diffusivity_functors")) 49 : { 50 57 : const auto & d = getParam<std::vector<MooseFunctorName>>("diffusivity_functors")[s]; 51 57 : if (getProblem().hasFunction(d)) 52 : kernel_type = "FunctionDiffusion"; 53 : else 54 0 : paramError( 55 : "diffusivity_functors", "No diffusion kernel implemented for the source type of", d); 56 : } 57 : 58 342 : InputParameters params = getFactory().getValidParams(kernel_type); 59 684 : params.set<NonlinearVariableName>("variable") = var_name; 60 342 : assignBlocks(params, _blocks); 61 : 62 : // Transfer the diffusivity parameter from the Physics to the kernel 63 684 : if (isParamValid("diffusivity_matprops")) 64 570 : params.set<MaterialPropertyName>("diffusivity") = 65 570 : getParam<std::vector<MaterialPropertyName>>("diffusivity_matprops")[s]; 66 114 : else if (isParamValid("diffusivity_functors")) 67 114 : params.set<FunctionName>("function") = 68 171 : getParam<std::vector<MooseFunctorName>>("diffusivity_functors")[s]; 69 : 70 684 : getProblem().addKernel(kernel_type, prefix() + var_name + "_diffusion", params); 71 342 : } 72 : 73 : // Source term 74 684 : if (isParamValid("source_functors")) 75 : { 76 : // Select the kernel type based on the user parameters 77 : std::string kernel_type; 78 684 : const auto & sources = getParam<std::vector<MooseFunctorName>>("source_functors"); 79 : const auto & source = sources[s]; 80 342 : if (MooseUtils::parsesToReal(source) || getProblem().hasFunction(source) || 81 418 : getProblem().hasPostprocessorValueByName(source)) 82 323 : kernel_type = _use_ad ? "ADBodyForce" : "BodyForce"; 83 19 : else if (getProblem().hasVariable(source)) 84 19 : kernel_type = _use_ad ? "ADCoupledForce" : "CoupledForce"; 85 : else 86 0 : paramError("source_functors", 87 : "No kernel defined for a source term in CG for the type of '", 88 : source, 89 : "'"); 90 : 91 342 : InputParameters params = getFactory().getValidParams(kernel_type); 92 684 : params.set<NonlinearVariableName>("variable") = var_name; 93 342 : assignBlocks(params, _blocks); 94 : 95 : // Transfer the source and coefficient parameter from the Physics to the kernel 96 1026 : const auto coefs = getParam<std::vector<Real>>("source_coefs"); 97 342 : const auto coef = coefs[s]; 98 342 : if (MooseUtils::parsesToReal(source)) 99 285 : params.set<Real>("value") = MooseUtils::convert<Real>(source) * coef; 100 57 : else if (getProblem().hasFunction(source)) 101 : { 102 19 : params.set<Real>("value") = coef; 103 38 : params.set<FunctionName>("function") = source; 104 : } 105 114 : else if (getProblem().hasPostprocessorValueByName(source)) 106 : { 107 19 : params.set<Real>("value") = coef; 108 38 : params.set<PostprocessorName>("postprocessor") = source; 109 : } 110 : else 111 : { 112 19 : params.set<Real>("coef") = coef; 113 57 : params.set<std::vector<VariableName>>("v") = {source}; 114 : } 115 : 116 684 : getProblem().addKernel(kernel_type, prefix() + var_name + "_source", params); 117 342 : } 118 : 119 : // Time derivative term 120 342 : if (shouldCreateTimeDerivative(var_name, _blocks, false)) 121 : { 122 399 : const std::string kernel_type = _use_ad ? "ADTimeDerivative" : "TimeDerivative"; 123 342 : InputParameters params = getFactory().getValidParams(kernel_type); 124 684 : params.set<NonlinearVariableName>("variable") = var_name; 125 342 : assignBlocks(params, _blocks); 126 684 : getProblem().addKernel(kernel_type, prefix() + var_name + "_time", params); 127 342 : } 128 : } 129 114 : } 130 : 131 : void 132 114 : MultiSpeciesDiffusionCG::addFEBCs() 133 : { 134 228 : if (isParamSetByUser("neumann_boundaries")) 135 : { 136 : const auto & boundary_fluxes = 137 57 : getParam<std::vector<std::vector<MooseFunctorName>>>("boundary_fluxes"); 138 : 139 228 : for (const auto s : index_range(_species_names)) 140 : { 141 171 : const auto & var_name = _species_names[s]; 142 : 143 741 : for (const auto i : index_range(_neumann_boundaries[s])) 144 : { 145 : const auto & bc_flux = boundary_fluxes[s][i]; 146 : // Select the boundary type based on the user parameters and what we know to be most 147 : // efficient We could actually just use the very last option for everything but the 148 : // performance is better if one uses the specialized objects 149 570 : std::string bc_type = ""; 150 570 : if (MooseUtils::parsesToReal(bc_flux)) 151 171 : bc_type = _use_ad ? "ADNeumannBC" : "NeumannBC"; 152 399 : else if (getProblem().hasVariable(bc_flux)) 153 : bc_type = "CoupledVarNeumannBC"; // not AD, but still perfect Jacobian 154 285 : else if (getProblem().hasFunction(bc_flux)) 155 114 : bc_type = _use_ad ? "ADFunctionNeumannBC" : "FunctionNeumannBC"; 156 513 : else if (getProblem().hasPostprocessorValueByName(bc_flux)) 157 : bc_type = "PostprocessorNeumannBC"; 158 : else // this is AD, but we can mix AD and non-AD 159 : bc_type = "FunctorNeumannBC"; 160 : 161 : // Get the parameters for the object type chosen and set the common parameters 162 570 : InputParameters params = getFactory().getValidParams(bc_type); 163 1140 : params.set<NonlinearVariableName>("variable") = var_name; 164 1710 : params.set<std::vector<BoundaryName>>("boundary") = {_neumann_boundaries[s][i]}; 165 : 166 : // Set the flux parameter for the specific type of NeumannBC used 167 570 : if (MooseUtils::parsesToReal(bc_flux)) 168 171 : params.set<Real>("value") = MooseUtils::convert<Real>(bc_flux); 169 399 : else if (getProblem().hasVariable(bc_flux)) 170 342 : params.set<std::vector<VariableName>>("v") = {bc_flux}; 171 285 : else if (getProblem().hasFunction(bc_flux)) 172 228 : params.set<FunctionName>("function") = bc_flux; 173 513 : else if (getProblem().hasPostprocessorValueByName(bc_flux)) 174 342 : params.set<PostprocessorName>("postprocessor") = bc_flux; 175 : else 176 0 : params.set<MooseFunctorName>("functor") = bc_flux; 177 : 178 1140 : getProblem().addBoundaryCondition( 179 1140 : bc_type, prefix() + var_name + "_neumann_bc_" + _neumann_boundaries[s][i], params); 180 570 : } 181 : } 182 : } 183 228 : if (isParamSetByUser("dirichlet_boundaries")) 184 : { 185 : const auto & boundary_values = 186 57 : getParam<std::vector<std::vector<MooseFunctorName>>>("boundary_values"); 187 228 : for (const auto s : index_range(_species_names)) 188 : { 189 171 : const auto & var_name = _species_names[s]; 190 627 : for (const auto i : index_range(_dirichlet_boundaries[s])) 191 : { 192 : const auto & bc_value = boundary_values[s][i]; 193 : // Select the boundary type based on the user parameters and what we know to be most 194 : // efficient 195 456 : std::string bc_type = ""; 196 456 : if (MooseUtils::parsesToReal(bc_value)) 197 171 : bc_type = _use_ad ? "ADDirichletBC" : "DirichletBC"; 198 285 : else if (getProblem().hasVariable(bc_value)) 199 57 : bc_type = _use_ad ? "ADMatchedValueBC" : "MatchedValueBC"; 200 228 : else if (getProblem().hasFunction(bc_value)) 201 57 : bc_type = _use_ad ? "ADFunctionDirichletBC" : "FunctionDirichletBC"; 202 513 : else if (getProblem().hasPostprocessorValueByName(bc_value)) 203 : bc_type = "PostprocessorDirichletBC"; 204 : else // this is AD, but we can mix AD and non-AD 205 : bc_type = "FunctorDirichletBC"; 206 : 207 456 : InputParameters params = getFactory().getValidParams(bc_type); 208 912 : params.set<NonlinearVariableName>("variable") = var_name; 209 1368 : params.set<std::vector<BoundaryName>>("boundary") = {_dirichlet_boundaries[s][i]}; 210 : 211 : // Set the flux parameter for the specific type of DirichletBC used 212 456 : if (MooseUtils::parsesToReal(bc_value)) 213 171 : params.set<Real>("value") = MooseUtils::convert<Real>(bc_value); 214 285 : else if (getProblem().hasVariable(bc_value)) 215 171 : params.set<std::vector<VariableName>>("v") = {bc_value}; 216 228 : else if (getProblem().hasFunction(bc_value)) 217 114 : params.set<FunctionName>("function") = bc_value; 218 513 : else if (getProblem().hasPostprocessorValueByName(bc_value)) 219 342 : params.set<PostprocessorName>("postprocessor") = bc_value; 220 : else 221 0 : params.set<MooseFunctorName>("functor") = bc_value; 222 : 223 912 : getProblem().addBoundaryCondition( 224 912 : bc_type, prefix() + var_name + "_dirichlet_bc_" + _dirichlet_boundaries[s][i], params); 225 456 : } 226 : } 227 : } 228 114 : } 229 : 230 : void 231 114 : MultiSpeciesDiffusionCG::addSolverVariables() 232 : { 233 456 : for (const auto & var_name : _species_names) 234 : { 235 : // If the variable was added outside the Physics 236 342 : if (variableExists(var_name, /*error_if_aux*/ true)) 237 : { 238 0 : if (isParamValid("variable_order")) 239 0 : paramError("variable_order", 240 0 : "Cannot specify the variable order if variable " + var_name + 241 : " is defined outside the Physics block"); 242 : else 243 0 : return; 244 : } 245 : 246 342 : const std::string variable_type = "MooseVariable"; 247 342 : InputParameters params = getFactory().getValidParams(variable_type); 248 1026 : params.set<MooseEnum>("order") = getParam<MooseEnum>("variable_order"); 249 342 : assignBlocks(params, _blocks); 250 342 : params.set<SolverSystemName>("solver_sys") = getSolverSystem(var_name); 251 : 252 342 : getProblem().addVariable(variable_type, var_name, params); 253 342 : } 254 : }