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.

commentnote

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
    solver_sys = 'u'
    block = 0
  []
  [v]
    type = MooseVariableFVReal
    solver_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
[]
(moose/test/tests/fviks/diffusion/multisystem.i)