FVInterfaceKernels System
For an overview of MOOSE FV please see Finite Volume Design Decisions in MOOSE.
FVInterfaceKernels are meant to communicate data at interfaces between subdomains. An FVInterfaceKernel may contribute to the residuals/Jacobians of a single variable, specified with the parameter variable1, or to multiple variables by also using the variable2 parameter. There are two additional critical/required parameters: subdomain1 and subdomain2. In cases for which an FVInterfaceKernel is operating on two variables, subdomain1 should correspond to the subdomain(s) neighboring the boundary parameter that variable1 lives on, and similarly for subdomain2 and variable2. By checking the subdomain parameters against the subdomain IDs of the FaceInfo::elem and FaceInfo::neighbor members a FVInterfaceKernel developer can be sure that they are fetching and using sensical data. For instance, a developer may want to create an FVInterfaceKernel that uses prop1 on the subdomain1 side of the boundary and prop2 on the subdomain2 side of the boundary. However, MOOSE only provides these APIs for fetching material properties: get(AD)MaterialProperty and getNeighbor(AD)MaterialProperty. The return value of get(AD)MaterialProperty will always correspond to a material property evaluation on the FaceInfo::elem side of a (inter)face, while the return value of getNeighbor(AD)MaterialProperty will always correspond to a material property evaluation on the FaceInfo::neighbor side of a (inter)face. However, when moving along an interface, it is possible that the FaceInfo::elem side of the interface is sometimes the subdomain1 side and sometimes the subdomain2 side. So making use of the subdomain parameters, we provide a protected method called elemIsOne() that returns a boolean indicating whether the FaceInfo::elem side of the interface corresponds to the subdomain1 side of the interface. This allows the developer to write code like the following:
FVFooInterface::FVFooInterface(const InputParameters & params)
: FVInterfaceKernel(params),
_coeff1_elem(getADMaterialProperty<Real>("coeff1")),
_coeff2_elem(getADMaterialProperty<Real>("coeff2")),
_coeff1_neighbor(getNeighborADMaterialProperty<Real>("coeff1")),
_coeff2_neighbor(getNeighborADMaterialProperty<Real>("coeff2"))
{
}
ADReal
FVFooInterface::computeQpResidual()
{
const auto & coef_elem = elemIsOne() ? _coeff1_elem : _coeff2_elem;
const auto & coef_neighbor = elemIsOne() ? _coeff2_neighbor : _coeff1_neighbor;
/// Code that uses coef_elem and coef_neighbor
}
and have confidence that they have good data in coef_elem and coef_neighbor and have clarity about what is happening in their code.
When using an FVInterfaceKernel which connects variables that belong to different nonlinear systems, create two kernels with flipped variable and material property parameters. The reason behind this is that the interface kernel will only contribute to the system which variable1 belongs to. For an example, see:
[Mesh]
[gmg]
type = CartesianMeshGenerator
dim = 1
ix = '50 50'
dx = '1 1'
subdomain_id = '0 1'
[]
[sds]
type = SideSetsBetweenSubdomainsGenerator
input = gmg
new_boundary = 'between'
paired_block = '1'
primary_block = '0'
[]
[]
[Problem]
nl_sys_names = 'u v'
error_on_jacobian_nonzero_reallocation = true
[]
[Variables]
[u]
type = MooseVariableFVReal
nl_sys = 'u'
block = 0
[]
[v]
type = MooseVariableFVReal
nl_sys = 'v'
block = 1
[]
[]
[FVKernels]
[diff_u]
type = FVDiffusion
variable = u
coeff = 3.0
[]
[force_u]
type = FVBodyForce
variable = u
function = 5
[]
[diff_v]
type = FVDiffusion
variable = v
coeff = 1.0
[]
[force_v]
type = FVBodyForce
variable = v
function = 5
[]
[]
[FVInterfaceKernels]
[diff_ik]
type = FVDiffusionInterface
variable1 = u
variable2 = v
boundary = 'between'
coeff1 = 3
coeff2 = 1
subdomain1 = 0
subdomain2 = 1
[]
[diff_ik_v]
type = FVDiffusionInterface
variable1 = v
variable2 = u
boundary = 'between'
coeff1 = 1
coeff2 = 3
subdomain1 = 1
subdomain2 = 0
[]
[]
[FVBCs]
[left_u]
type = FVDirichletBC
variable = u
boundary = left
value = 0
[]
[right_v]
type = FVDirichletBC
variable = v
boundary = right
value = 1
[]
[]
[Executioner]
type = SteadySolve2
solve_type = 'NEWTON'
petsc_options = '-snes_monitor'
petsc_options_iname = '-pc_type -pc_hypre_type'
petsc_options_value = 'hypre boomeramg'
first_nl_sys_to_solve = 'u'
second_nl_sys_to_solve = 'v'
number_of_iterations = 200
nl_abs_tol = 1e-10
[]
[Outputs]
print_nonlinear_residuals = false
print_linear_residuals = false
exodus = true
[]
(test/tests/fviks/diffusion/multisystem.i)