Porous Flow Tutorial Page 09. An overview of the PorousFlow architecture
Sometimes PorousFlow can be very frustrating to run because MOOSE keeps spitting back things like
Material property 'PorousFlow_matrix_internal_energy_nodal', requested by 'PorousFlowUnsaturated_EnergyTimeDerivative' is not defined on block caps
You have to create a
Material that supplies a property called
PorousFlow_matrix_internal_energy_nodal, but which PorousFlow Material do you choose? In multi-component, multi-phase problems these error messages get even more obscure. To debug your input file it is helpful to understand the overall design of PorousFlow.
The PorousFlow design
Yes, it is actually designed and not just hacked together! The design is fundamentally influenced by the following requirements
Multi-component, multi-phase fluids need to be simulated. This means that the
Materials, etc are all built using C++
std::vectorsof components and phases, that are sized at runtime when MOOSE reads your input file. An alternative approach would be to have a separate 1-component, 1-phase module; another module for 2-component, 1-phase; another for 3-component, 1-phase, another for 2-component, 2-phase, etc, as well as all the possible couplings with temperature, mechanics and chemistry. This would be a huge task, made even worse by the exhaustive (and exhausting) testing and documentation. Unfortunately, not only do the
std::vectorsmake the code quite complex, but they necessitate the Joiners (see below). However, to make things easier for users,
Actionshave been created that cover the common use-case of single-phase fluid flow. These have been used in the tutorial so far, but will be abandoned in Page 10.
In many PorousFlow simulations, mass lumping and full upwinding or the Kuzmin-Turek TVD scheme are critical to avoid unphysical results (eg, negative concentrations or saturations) and to vastly improve convergence (to prevent fluid from being withdrawn from a node where there is no fluid). However, MOOSE is not really suited to this approach because the
Kernelsneed all the Material properties (and other things) evaluated at the nodes, rather than at the quadpoints. A special
PorousFlowMaterialhas been created that allows all other PorousFlow Materials to be evaluated at nodes by specifying the
at_nodesinput parameter. The required version of each material is added automatically, so the user shouldn't need to set the
In contrast to much of the remainder of MOOSE, good nonlinear convergence is only obtained when the Jacobian is built using all the derivative information (a short discussion has already been presented on Page 02). The
porous_flow_varsinput parameter of the
PorousFlowDictatorcontrols which derivatives are entered into the Jacobian. However, sometimes the derivatives are extremely complicated (you will see hundreds of lines of chain-rules if you look at the code) so MOOSE's DerivativeMaterial system is used which allows developers to specify the derivatives if they desire, but will return 0 if none are specified.
PorousFlow can run the same simulation using a variety of different nonlinear
Variables! For instance, a two-phase simulation can use two porepressure variables, or a single porepressure and a saturation variable. Or a thermally-coupled simulation can use porepressure and temperature, or can use enthalpy as a
Variableinstead. The reasons for this are: that the choice of
Variablescan greatly affect the nonlinear convergence; and, when phase changes (boiling of a liquid) occur, a new set of variables is needed, or persistant variables that are not just porepressure and temperature, should be used. PorousFlow provides a set of fundamental Materials that compute porepressures, saturations, temperature and mass fractions from the
Variables. Gradients of these quantities, and derivatives with the respect to the
Variablesare also computed. Those porepressures, saturations, temperature and mass fractions are then
Materialproperties and are used by everything else in PorousFlow.
Often you're not sure which PorousFlow
Kernel describes which DE! The DEs are described in the governing equations and at the bottom of that page is a table showing the Kernel names and their mathematical expressions.
These form the heart of PorousFlow. Usually the
[Materials] block in the input file is the longest and most complicated block.
Mentioned above is the
at_nodes input parameter. The standard in PorousFlow is that a
Material computes a property called
at_nodes = true, while it computes the property
at_nodes = false.
Almost all PorousFlow
Materials compute derivatives, and most of them retrieve derivative information from other
Materials and combine then in ghastly chain-rules. The standard is that these are called
Materials also compute
In the input file, you specify things like densities, relative permeabilities, etc, for each phase or component. But most PorousFlow
Kernels, etc, require these to be formatted into C++
std::vectors. This is what the
PorousFlowJoiner does. Even single-phase, single-component simulations need Joiners: they just create
std::vectors with length 1. These are added automatically by the action system.
What Material do I need?
grep utility is your friend here! Do the following
cd porous_flow/src/materials grep matrix_internal *.C
to find the
Material needed to solve the above MOOSE "undefined" error.