ConservativeAdvection

Description

The ConservativeAdvection kernel implements an advection term given for the domain () defined as

(1) where is the advecting velocity and the second term on the left hand side represents the strong forms of other kernels. ConservativeAdvection does not assume that the velocity is divergence free and instead applies to the test function in the weak variational form after integrating by parts, which results in the following (without numerical stabilization)

(2) where are the test functions and is the finite element solution of the weak formulation. The first term is the volumetric term and the second term is a surface term describing the advective flux out of the volume. ConservativeAdvection corresponds to the former volumetric term, while the surface term is implemented as a BC in MOOSE (see discussion below regarding OutflowBC and InflowBC).

Without numerical stabilization the corresponding Jacobian is given by

(3)

Full upwinding

Advective flow is notoriously prone to physically-incorrect overshoots and undershoots, so in many simulations some numerical stabilization is used to reduce or eliminate this spurious behaviour. Full-upwinding Dalen (1979) and Adhikary and Wilkins (2011) is an example of numerical stabilization and this essentially adds numerical diffusion to completely eliminate overshoots and undershoots. Full-upwinding is available in ConservativeAdvection by setting the upwinding_type appropriately.

note

Full upwinding only works for continuous FEM

In DE systems describing more than just advection (e.g., in diffusion-advection problems) full upwinding may be used on the advection alone. In practise, it is reasonably common that these more complicated cases benefit from numerical stabilization on their other terms too, in which case full upwinding could also be used, but this is not mandatory and is not implemented in the ConservativeAdvection Kernel.

For each element in the mesh, full upwinding is implemented in the following way. For each , the quantity (4) is evaluated. If is positive then mass (or heat, or whatever represents) is flowing out of node , and this is called an "upwind" node. If , the residual for node is set to (5) Here is the value of at the node . Define the total mass flowing from the upwind nodes: (6) Similarly, define (7) Mass is conserved if the residual for the downwind nodes is defined to be (8)

Full upwinding adds more numerical diffusion than most other numerical stabilization techniques such as SUPG and TVD. Another problem is that steady-state can be hard to achieve in nonlinear problems where the velocity is not fixed and changes every nonlinear iteration (this does not occur for ConservativeAdvection). On the other hand, full upwinding is computationally cheap.

Example Syntax

ConservativeAdvection can be used in a variety of problems, including advection-diffusion-reaction. The syntax for ConservativeAdvection is demonstrated in this Kernels block from a pure advection test case:


[Kernels]
  [./udot]
    type = TimeDerivative
    variable = u
  [../]
  [./advection]
    type = ConservativeAdvection
    variable = u
    velocity = '1 0 0'
  [../]
[]
(../moose/test/tests/kernels/conservative_advection/no_upwinding_1D.i)

The velocity is supplied as a three component vector with order , , and .

Boundary conditions for pure advection

To form the correct equations, the boundary term needs to be included in the BCs block of a MOOSE input file ( is the outward normal to the boundary). An OutflowBC may be used, for instance


[BCs]
  [./allow_mass_out]
    type = OutflowBC
    boundary = right
    variable = u
    velocity = '1 0 0'
  [../]
[]
(../moose/test/tests/kernels/conservative_advection/none_in_all_out.i)

Physically this subtracts "fluid mass" (or whatever represents) from the boundary.

For adding the OutflowBC allows "fluid" to flow freely through the boundary. The advective velocity is "blowing fluid" into this boundary, and the OutflowBC is removing it at the correct rate, because the flux through any area is .

On the other hand, including an OutflowBC for isn't usually desirable. Adding the OutflowBC in this case fixes at the boundary to its initial condition. This is because the ConservativeAdvection Kernel is taking fluid from the boundary to the interior of the model, but at the same time the OutflowBC is removing : note that , so the OutflowBC is actually adding fluid at the same rate the ConservativeAdvection Kernel is removing it. The physical interpretation is that something external to the model is adding fluid at exactly the rate specified by the initial conditions at that boundary.

Instead, for users typically want to specify a particular value for an injected flux. This is achieved by using an InflowBC. This adds , where (kg.m.s) is the injection rate. For instance


[BCs]
  [./u_injection_left]
    type = InflowBC
    boundary = left
    variable = u
    velocity = '1 0 0'
    inlet_conc = 1
  [../]
[]
(../moose/test/tests/kernels/conservative_advection/full_upwinding_1D.i)

To make impermeable boundaries, either for or , simply use no BC at that boundary. Then for there is no BC to remove fluid from that boundary so the fluid "piles up" there. For the omission of a BC can be thought of setting in an InflowBC.

Comparison of no upwinding and full upwinding

The tests

# ConservativeAdvection with upwinding_type = None
# Apply a velocity = (1, 0, 0) and see a pulse advect to the right
# Note there are overshoots and undershoots
[Mesh]
  type = GeneratedMesh
  dim = 1
  nx = 10
[]

[Variables]
  [./u]
  [../]
[]

[BCs]
  [./u_injection_left]
    type = InflowBC
    boundary = left
    variable = u
    velocity = '1 0 0'
    inlet_conc = 1
  [../]
[]

[Kernels]
  [./udot]
    type = TimeDerivative
    variable = u
  [../]
  [./advection]
    type = ConservativeAdvection
    variable = u
    velocity = '1 0 0'
  [../]
[]

[Executioner]
  type = Transient
  solve_type = LINEAR
  dt = 0.1
  end_time = 1
  l_tol = 1E-14
[]

[Outputs]
  exodus = true
[]
(../moose/test/tests/kernels/conservative_advection/no_upwinding_1D.i)

and

# ConservativeAdvection with upwinding_type = full
# Apply a velocity = (1, 0, 0) and see a pulse advect to the right
# Note that the pulse diffuses more than with no upwinding,
# but there are no overshoots and undershoots and that the
# center of the pulse at u=0.5 advects with the correct velocity
[Mesh]
  type = GeneratedMesh
  dim = 1
  nx = 10
[]

[Variables]
  [./u]
  [../]
[]

[BCs]
  [./u_injection_left]
    type = InflowBC
    boundary = left
    variable = u
    velocity = '1 0 0'
    inlet_conc = 1
  [../]
[]

[Kernels]
  [./udot]
    type = MassLumpedTimeDerivative
    variable = u
  [../]
  [./advection]
    type = ConservativeAdvection
    variable = u
    velocity = '1 0 0'
    upwinding_type = full
  [../]
[]

[Executioner]
  type = Transient
  solve_type = LINEAR
  dt = 0.1
  end_time = 1
  l_tol = 1E-14
[]

[Outputs]
  exodus = true
[]
(../moose/test/tests/kernels/conservative_advection/full_upwinding_1D.i)

describe the same physical situation: advection from left to right along a line. A source at the left boundary introduces into the domain at a fixed rate (using an InflowBC). The right boundary is impermeable (no BC), so when arrives there it starts building up at the boundary. It is clear from the figures below that no upwinding leads to unphysical overshoots and undershoots, while full upwinding results in none of that oscillatory behaviour but instead produces more numerical diffusion.

after 0.1 seconds of advection

after 0.5 seconds of advection

Input Parameters

  • variableThe name of the variable that this Kernel operates on

    C++ Type:NonlinearVariableName

    Description:The name of the variable that this Kernel operates on

  • velocityVelocity vector

    C++ Type:libMesh::VectorValue

    Description:Velocity vector

Required Parameters

  • upwinding_typenoneType of upwinding used. None: Typically results in overshoots and undershoots, but numerical diffusion is minimised. Full: Overshoots and undershoots are avoided, but numerical diffusion is large

    Default:none

    C++ Type:MooseEnum

    Description:Type of upwinding used. None: Typically results in overshoots and undershoots, but numerical diffusion is minimised. Full: Overshoots and undershoots are avoided, but numerical diffusion is large

  • blockThe list of block ids (SubdomainID) that this object will be applied

    C++ Type:std::vector

    Description:The list of block ids (SubdomainID) that this object will be applied

Optional Parameters

  • enableTrueSet the enabled status of the MooseObject.

    Default:True

    C++ Type:bool

    Description:Set the enabled status of the MooseObject.

  • save_inThe name of auxiliary variables to save this Kernel's residual contributions to. Everything about that variable must match everything about this variable (the type, what blocks it's on, etc.)

    C++ Type:std::vector

    Description:The name of auxiliary variables to save this Kernel's residual contributions to. Everything about that variable must match everything about this variable (the type, what blocks it's on, etc.)

  • use_displaced_meshFalseWhether or not this object should use the displaced mesh for computation. Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used.

    Default:False

    C++ Type:bool

    Description:Whether or not this object should use the displaced mesh for computation. Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used.

  • control_tagsAdds user-defined labels for accessing object parameters via control logic.

    C++ Type:std::vector

    Description:Adds user-defined labels for accessing object parameters via control logic.

  • seed0The seed for the master random number generator

    Default:0

    C++ Type:unsigned int

    Description:The seed for the master random number generator

  • diag_save_inThe name of auxiliary variables to save this Kernel's diagonal Jacobian contributions to. Everything about that variable must match everything about this variable (the type, what blocks it's on, etc.)

    C++ Type:std::vector

    Description:The name of auxiliary variables to save this Kernel's diagonal Jacobian contributions to. Everything about that variable must match everything about this variable (the type, what blocks it's on, etc.)

  • implicitTrueDetermines whether this object is calculated using an implicit or explicit form

    Default:True

    C++ Type:bool

    Description:Determines whether this object is calculated using an implicit or explicit form

Advanced Parameters

  • vector_tagsnontimeThe tag for the vectors this Kernel should fill

    Default:nontime

    C++ Type:MultiMooseEnum

    Description:The tag for the vectors this Kernel should fill

  • extra_vector_tagsThe extra tags for the vectors this Kernel should fill

    C++ Type:std::vector

    Description:The extra tags for the vectors this Kernel should fill

  • matrix_tagssystemThe tag for the matrices this Kernel should fill

    Default:system

    C++ Type:MultiMooseEnum

    Description:The tag for the matrices this Kernel should fill

  • extra_matrix_tagsThe extra tags for the matrices this Kernel should fill

    C++ Type:std::vector

    Description:The extra tags for the matrices this Kernel should fill

Tagging Parameters

References

  1. D. Adhikary and A. Wilkins. Analysis of finite element discretisation schemes for multi-phase Darcy flow. Defect and Diffusion Forum, 318:33–40, 2011. doi:10.4028/www.scientific.net/DDF.318.33.[BibTeX]
  2. ~V. Dalen. Simplified Finite-Element Models for Reservoir Flow Problems. Society of Petroleum Engineers Journal, 19:333–342, 1979. doi:10.2118/7196-PA.[BibTeX]