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 "FVInterfaceKernel.h"
11 : #include "FEProblemBase.h"
12 : #include "SystemBase.h"
13 : #include "MooseVariableFV.h"
14 : #include "Assembly.h"
15 :
16 : InputParameters
17 57690 : FVInterfaceKernel::validParams()
18 : {
19 57690 : InputParameters params = MooseObject::validParams();
20 57690 : params += BoundaryRestrictableRequired::validParams();
21 57690 : params += SetupInterface::validParams();
22 57690 : params += FunctionInterface::validParams();
23 57690 : params += DistributionInterface::validParams();
24 57690 : params += UserObjectInterface::validParams();
25 57690 : params += TransientInterface::validParams();
26 57690 : params += PostprocessorInterface::validParams();
27 57690 : params += VectorPostprocessorInterface::validParams();
28 57690 : params += GeometricSearchInterface::validParams();
29 57690 : params += MeshChangedInterface::validParams();
30 57690 : params += TaggingInterface::validParams();
31 57690 : params += NeighborCoupleableMooseVariableDependencyIntermediateInterface::validParams();
32 57690 : params += TwoMaterialPropertyInterface::validParams();
33 57690 : params += ADFunctorInterface::validParams();
34 :
35 57690 : params.addRequiredParam<std::vector<SubdomainName>>(
36 : "subdomain1", "The subdomains on the 1st side of the boundary.");
37 57690 : params.addRequiredParam<std::vector<SubdomainName>>(
38 : "subdomain2", "The subdomains on the 2nd side of the boundary.");
39 57690 : params.addRequiredParam<NonlinearVariableName>(
40 : "variable1", "The name of the first variable that this interface kernel applies to");
41 57690 : params.addParam<NonlinearVariableName>(
42 : "variable2",
43 : "The name of the second variable that this interface kernel applies to. If not supplied, "
44 : "variable1 will be used.");
45 173070 : params.addParam<bool>("use_displaced_mesh",
46 115380 : false,
47 : "Whether or not this object should use the "
48 : "displaced mesh for computation. Note that "
49 : "in the case this is true but no "
50 : "displacements are provided in the Mesh block "
51 : "the undisplaced mesh will still be used.");
52 :
53 57690 : params.addParam<unsigned short>("ghost_layers", 1, "The number of layers of elements to ghost.");
54 173070 : params.addParam<bool>("use_point_neighbors",
55 115380 : false,
56 : "Whether to use point neighbors, which introduces additional ghosting to "
57 : "that used for simple face neighbors.");
58 57690 : params.addParamNamesToGroup("ghost_layers use_point_neighbors", "Parallel ghosting");
59 :
60 : // FV Interface Kernels always need one layer of ghosting because the elements
61 : // on each side of the interface may be on different MPI ranks, but we still
62 : // need to access them as a pair to compute the numerical face flux.
63 57690 : params.addRelationshipManager(
64 : "ElementSideNeighborLayers",
65 : Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC |
66 : Moose::RelationshipManagerType::COUPLING,
67 0 : [](const InputParameters & obj_params, InputParameters & rm_params)
68 : {
69 915 : rm_params.set<unsigned short>("layers") = obj_params.get<unsigned short>("ghost_layers");
70 915 : rm_params.set<bool>("use_point_neighbors") = obj_params.get<bool>("use_point_neighbors");
71 915 : });
72 :
73 57690 : params.addParamNamesToGroup("use_displaced_mesh", "Advanced");
74 57690 : params.addCoupledVar("displacements", "The displacements");
75 57690 : params.declareControllable("enable");
76 57690 : params.registerBase("FVInterfaceKernel");
77 57690 : params.registerSystemAttributeName("FVInterfaceKernel");
78 57690 : params.set<bool>("_residual_object") = true;
79 57690 : return params;
80 0 : }
81 :
82 331 : FVInterfaceKernel::FVInterfaceKernel(const InputParameters & parameters)
83 : : MooseObject(parameters),
84 : BoundaryRestrictableRequired(this, false),
85 : SetupInterface(this),
86 : FunctionInterface(this),
87 : DistributionInterface(this),
88 : UserObjectInterface(this),
89 : TransientInterface(this),
90 : PostprocessorInterface(this),
91 : VectorPostprocessorInterface(this),
92 : GeometricSearchInterface(this),
93 : MeshChangedInterface(parameters),
94 : TaggingInterface(this),
95 : NeighborCoupleableMooseVariableDependencyIntermediateInterface(
96 : this, /*nodal=*/false, /*neighbor_nodal=*/false, /*is_fv=*/true),
97 : TwoMaterialPropertyInterface(this, Moose::EMPTY_BLOCK_IDS, boundaryIDs()),
98 : ADFunctorInterface(this),
99 331 : _tid(getParam<THREAD_ID>("_tid")),
100 331 : _subproblem(*getCheckedPointerParam<SubProblem *>("_subproblem")),
101 662 : _var1(_subproblem.getVariable(_tid, getParam<NonlinearVariableName>("variable1"))
102 331 : .sys()
103 331 : .getFVVariable<Real>(_tid, getParam<NonlinearVariableName>("variable1"))),
104 662 : _var2(_subproblem
105 331 : .getVariable(_tid,
106 662 : isParamValid("variable2") ? getParam<NonlinearVariableName>("variable2")
107 404 : : getParam<NonlinearVariableName>("variable1"))
108 331 : .sys()
109 331 : .getFVVariable<Real>(_tid,
110 662 : isParamValid("variable2")
111 662 : ? getParam<NonlinearVariableName>("variable2")
112 404 : : getParam<NonlinearVariableName>("variable1"))),
113 331 : _assembly(_subproblem.assembly(_tid, _var1.sys().number())),
114 662 : _mesh(_subproblem.mesh())
115 : {
116 331 : if (getParam<bool>("use_displaced_mesh"))
117 0 : paramError("use_displaced_mesh", "FV interface kernels do not yet support displaced mesh");
118 :
119 331 : _subproblem.haveADObjects(true);
120 331 : addMooseVariableDependency(&_var1);
121 331 : addMooseVariableDependency(&_var2);
122 :
123 662 : for (const auto & sub_name : getParam<std::vector<SubdomainName>>("subdomain1"))
124 331 : _subdomain1.insert(_mesh.getSubdomainID(sub_name));
125 662 : for (const auto & sub_name : getParam<std::vector<SubdomainName>>("subdomain2"))
126 331 : _subdomain2.insert(_mesh.getSubdomainID(sub_name));
127 :
128 331 : if (!_var1.hasBlocks(_subdomain1))
129 4 : paramError("variable1",
130 : "variable1 does not exist on all the blocks specified by the subdomain1 parameter");
131 327 : if (!_var2.hasBlocks(_subdomain2))
132 : {
133 8 : const bool var2_provided = isParamValid("variable2");
134 8 : const std::string var_name = var2_provided ? "variable2" : "variable1";
135 8 : paramError(var_name,
136 : var_name,
137 : " does not exist on all the blocks specified by the subdomain2 parameter",
138 : var2_provided ? ""
139 : : ".\nNote that you did not provide the variable2 parameter, "
140 : "so variable1 was implicitly used on subdomain2");
141 0 : }
142 319 : }
143 :
144 : void
145 13816 : FVInterfaceKernel::setupData(const FaceInfo & fi)
146 : {
147 13816 : _face_info = &fi;
148 13816 : _normal = fi.normal();
149 13816 : _elem_is_one = _subdomain1.find(fi.elem().subdomain_id()) != _subdomain1.end();
150 :
151 : #ifndef NDEBUG
152 : const auto ft1 = fi.faceType(std::make_pair(_var1.number(), _var1.sys().number()));
153 : const auto ft2 = fi.faceType(std::make_pair(_var2.number(), _var2.sys().number()));
154 : constexpr auto ft_both = FaceInfo::VarFaceNeighbors::BOTH;
155 : constexpr auto ft_elem = FaceInfo::VarFaceNeighbors::ELEM;
156 : constexpr auto ft_neigh = FaceInfo::VarFaceNeighbors::NEIGHBOR;
157 : mooseAssert(
158 : (_elem_is_one && (ft1 == ft_elem || ft1 == ft_both) && (ft2 == ft_neigh || ft2 == ft_both)) ||
159 : (!_elem_is_one && (ft1 == ft_neigh || ft1 == ft_both) &&
160 : (ft2 == ft_elem || ft2 == ft_both)),
161 : "Face type was not recognized. Check that the specified boundaries are interfaces.");
162 : #endif
163 13816 : }
164 :
165 : void
166 11284 : FVInterfaceKernel::addResidual(const Real resid, const unsigned int var_num, const bool neighbor)
167 : {
168 11284 : neighbor ? prepareVectorTagNeighbor(_assembly, var_num) : prepareVectorTag(_assembly, var_num);
169 11284 : _local_re(0) = resid;
170 11284 : accumulateTaggedLocalResidual();
171 11284 : }
172 :
173 : void
174 0 : FVInterfaceKernel::addJacobian(const ADReal & resid,
175 : const dof_id_type dof_index,
176 : const Real scaling_factor)
177 : {
178 0 : addJacobian(_assembly,
179 0 : std::array<ADReal, 1>{{resid}},
180 0 : std::array<dof_id_type, 1>{{dof_index}},
181 : scaling_factor);
182 0 : }
183 :
184 : void
185 8784 : FVInterfaceKernel::computeResidual(const FaceInfo & fi)
186 : {
187 8784 : setupData(fi);
188 :
189 8784 : const auto r = MetaPhysicL::raw_value(fi.faceArea() * fi.faceCoord() * computeQpResidual());
190 :
191 : // If the two variables belong to two different nonlinear systems, we only contribute to the one
192 : // which is being assembled right now
193 : mooseAssert(_var1.sys().number() == _subproblem.currentNlSysNum(),
194 : "The interface kernel should contribute to the system which variable1 belongs to!");
195 8784 : addResidual(_elem_is_one ? r : -r, _var1.number(), _elem_is_one ? false : true);
196 8784 : if (_var1.sys().number() == _var2.sys().number())
197 2296 : addResidual(_elem_is_one ? -r : r, _var2.number(), _elem_is_one ? true : false);
198 8784 : }
199 :
200 : void
201 40 : FVInterfaceKernel::computeResidualAndJacobian(const FaceInfo & fi)
202 : {
203 40 : computeJacobian(fi);
204 40 : }
205 :
206 : void
207 4744 : FVInterfaceKernel::computeJacobian(const FaceInfo & fi)
208 : {
209 4744 : setupData(fi);
210 :
211 4744 : const auto r = fi.faceArea() * fi.faceCoord() * computeQpResidual();
212 :
213 : // If the two variables belong to two different nonlinear systems, we only contribute to the one
214 : // which is being assembled right now
215 : mooseAssert(_var1.sys().number() == _subproblem.currentNlSysNum(),
216 : "The interface kernel should contribute to the system which variable1 belongs to!");
217 14232 : addResidualsAndJacobian(_assembly,
218 4744 : std::array<ADReal, 1>{{_elem_is_one ? r : -r}},
219 4744 : _elem_is_one ? _var1.dofIndices() : _var1.dofIndicesNeighbor(),
220 4744 : _var1.scalingFactor());
221 4744 : if (_var1.sys().number() == _var2.sys().number())
222 4512 : addResidualsAndJacobian(_assembly,
223 1504 : std::array<ADReal, 1>{{_elem_is_one ? -r : r}},
224 1504 : _elem_is_one ? _var2.dofIndicesNeighbor() : _var2.dofIndices(),
225 1504 : _var2.scalingFactor());
226 10992 : }
227 :
228 : Moose::ElemArg
229 13528 : FVInterfaceKernel::elemArg(const bool correct_skewness) const
230 : {
231 13528 : return {_face_info->elemPtr(), correct_skewness};
232 : }
233 :
234 : Moose::ElemArg
235 13528 : FVInterfaceKernel::neighborArg(const bool correct_skewness) const
236 : {
237 13528 : return {_face_info->neighborPtr(), correct_skewness};
238 : }
239 :
240 : Moose::FaceArg
241 224 : FVInterfaceKernel::singleSidedFaceArg(const MooseVariableFV<Real> & variable,
242 : const FaceInfo * fi,
243 : const Moose::FV::LimiterType limiter_type,
244 : const bool correct_skewness,
245 : const Moose::StateArg * state_limiter) const
246 : {
247 224 : if (!fi)
248 224 : fi = _face_info;
249 :
250 224 : const bool defined_on_elem_side = variable.hasBlocks(fi->elem().subdomain_id());
251 224 : bool defined_on_neighbor_side = false;
252 224 : if (fi->neighborPtr())
253 224 : defined_on_neighbor_side = variable.hasBlocks(fi->neighbor().subdomain_id());
254 :
255 77 : const Elem * const elem = defined_on_elem_side && defined_on_neighbor_side
256 448 : ? nullptr
257 147 : : (defined_on_elem_side ? fi->elemPtr() : fi->neighborPtr());
258 :
259 224 : return {fi, limiter_type, true, correct_skewness, elem, state_limiter};
260 : }
261 :
262 : bool
263 0 : FVInterfaceKernel::hasFaceSide(const FaceInfo &, bool) const
264 : {
265 : // Our default interface kernel treats elem and neighbor sides equivalently so we will assume for
266 : // now that we will happily consume functor evaluations on either side of a face and any
267 : // interpolation between said evaluations
268 0 : return true;
269 : }
|