Start | Previous | Next

Porous Flow Tutorial Page 10. Unleashing the full power of PorousFlow: using Kernels and Materials

Now we're ready to build an input file from scratch using Kernels and Materials instead of the Actions we've been using so far. Inevitably you'll have to do this yourself when running PorousFlow simulations: you'll always want some PorousFlow features (boundary conditions, line sources, postprocessors, AuxKernels, etc) that aren't built by the Actions.

We're going to build the simulation from Page 08 which involved unsaturated flow. After building the input file, you can compare it with the Action version. The mesh and Variables remain unchanged. For clarity later on, the porepressure variable has been renamed 'pp'

[Variables]
  [pp]
  []
[]
(modules/porous_flow/examples/tutorial/10.i)

Let's start by building the PorousFlowDictator. We have one phase, one component and no chemistry. The single PorousFlow variable is called pp:

[UserObjects]
  [dictator]
    type = PorousFlowDictator
    porous_flow_vars = pp
    number_fluid_phases = 1
    number_fluid_components = 1
  []
(modules/porous_flow/examples/tutorial/10.i)

It is always useful to put the name of the PorousFlowDictator in the GlobalParams block, since all PorousFlow objects need it:

[GlobalParams]
  PorousFlowDictator = dictator
[]
(modules/porous_flow/examples/tutorial/10.i)

The DE is unsaturated single-phase flow. Refer to the governing equations document. Unsaturated single-phase flow is described by the first equation without the coupling terms to solid mechanics, radioactive decay, chemistry and sources:

(1)

Here since there is just one fluid component. The fluid mass is and the fluid velocity is . Hence we have two Kernels (refer to the bottom of governing equations for their types)

[Kernels]
  [time_derivative]
    type = PorousFlowMassTimeDerivative
    variable = pp
  []
  [flux]
    type = PorousFlowAdvectiveFlux
    variable = pp
    gravity = '0 0 0'
  []
[]
(modules/porous_flow/examples/tutorial/10.i)

It is often common to define some AuxVariables for visualisation purposes (or to feed as coupled variables to other MOOSE objects). A useful variable here is the fluid saturation, which is computed using a PorousFlowPropertyAux so the variable must be a constant monomial:

[AuxVariables]
  [sat]
    family = MONOMIAL
    order = CONSTANT
  []
[]

[AuxKernels]
  [saturation]
    type = PorousFlowPropertyAux
    variable = sat
    property = saturation
  []
[]
(modules/porous_flow/examples/tutorial/10.i)

The BCs remain the same: they used a PorousFlowSink to withdraw fluid from the injection area. The fluid properties also remain the same. For reference, these two blocks are:

[BCs]
  [production]
    type = PorousFlowSink
    variable = pp
    fluid_phase = 0
    flux_function = 1E-2
    use_relperm = true
    boundary = injection_area
  []
[]

[FluidProperties]
  [the_simple_fluid]
    type = SimpleFluidProperties
    bulk_modulus = 2E9
    viscosity = 1.0E-3
    density0 = 1000.0
  []
[]
(modules/porous_flow/examples/tutorial/10.i)

The final block to create is the Materials. This is always the most complicated part of creating an input file, and really only comes by experience.

  • You can run MOOSE multiple times, each time getting "undefined" errors like the one at the top of Page 09 and slowly add the required Materials until you get no errors. The information near the bottom of Page 09 is useful here.

  • You can inspect other similar input files in the PorousFlow test suite. There are over 300 tests so you're very likely to find what you need. Don't expect the files to always correspond to physically-sensible models (sometimes they're deliberately insensible to test obscure aspects of PorousFlow) but at least they are guaranteed to run!

  • You can ask on the MOOSE Discussion forum.

In this case, the DEs involve porosity, fluid saturation, fluid density, permeability and viscosity. The fluid mass is lumped to the nodes, so we'll only need porosity at the nodes:

  [porosity]
    type = PorousFlowPorosity
    porosity_zero = 0.1
  []
(modules/porous_flow/examples/tutorial/10.i)

The permeability is also needed:

  [permeability_aquifer]
    type = PorousFlowPermeabilityConst
    block = aquifer
    permeability = '1E-14 0 0   0 1E-14 0   0 0 1E-14'
  []
  [permeability_caps]
    type = PorousFlowPermeabilityConst
    block = caps
    permeability = '1E-15 0 0   0 1E-15 0   0 0 1E-16'
  []
(modules/porous_flow/examples/tutorial/10.i)

These Materials were also in the model of Page 08.

Now we need to build the saturation. This is not computed by the PorousFlowPropertyAux above. That AuxKernel just retrieves the material property and puts it into an AuxVariable. As mentioned in Page 09 PorousFlow simulations can use a variety of primary Variables. A set of fundamental Materials computes porepressures, saturations, temperatures and mass fractions from these primary Variables. In this case, our primary Variable is just porepressure and we only need to compute a single saturation. However, various other PorousFlow objects need temperature as an input, so we must compute it too, even though we just set it to a constant 293. Also, mass fraction needs to be computed, although it is trivially 1.0 for this problem.

  [saturation_calculator]
    type = PorousFlow1PhaseP
    porepressure = pp
    capillary_pressure = pc
  []
  [temperature]
    type = PorousFlowTemperature
    temperature = 293
  []
  [massfrac]
    type = PorousFlowMassFraction
  []
(modules/porous_flow/examples/tutorial/10.i)

These are our so-called "fundamental Materials". In almost every PorousFlow simulation you will see similar Materials. The saturation calculator uses the capillary-pressure function. It is a UserObject:

[UserObjects]
  [dictator]
    type = PorousFlowDictator
    porous_flow_vars = pp
    number_fluid_phases = 1
    number_fluid_components = 1
  []
  [pc]
    type = PorousFlowCapillaryPressureVG
    alpha = 1E-6
    m = 0.6
  []
[]
(modules/porous_flow/examples/tutorial/10.i)

The density and viscosity need to be computed. This is achieved by a PorousFlowSingleComponentFluid

  [simple_fluid]
    type = PorousFlowSingleComponentFluid
    fp = the_simple_fluid
    phase = 0
  []
(modules/porous_flow/examples/tutorial/10.i)

Finally, the relative permeability must be defined for each phase (just one phase in this example)

  [relperm]
    type = PorousFlowRelativePermeabilityCorey
    n = 3
    s_res = 0.1
    sum_s_res = 0.1
    phase = 0
(modules/porous_flow/examples/tutorial/10.i)

Our input file has been built! You may check that it gives exactly the same answers as the one on Page 08. It is 232 lines long while the one on Page 08 is only 139 lines long. Now that you've reached this point, you can start to build much more powerful models that don't use the PorousFlow Actions: models that involve multi-phase, multi-component flows, complicated thermal couplings, elasto-plasticity, chemical reactions, line sources and sinks, and sophisticated boundary terms!

Start | Previous | Next