Skip to content
Permalink
Browse files

Merge pull request #13036 from aeslaughter/pp-doco

Add documentation for Postprocessors
  • Loading branch information...
permcody committed Mar 12, 2019
2 parents 011bce1 + 8865b97 commit 913f3c7612a9a7fc1bf349ecbb58e432cb061aed
@@ -0,0 +1 @@
# PostprocessorInterface
@@ -12,7 +12,7 @@ own parameters, will have an "execute_on" parameter that can be set to various f
flags are listed below.

| Execute Flag | Description |
| - | - |
| :- | :- |
INITIAL | Prior to the first time step.
TIMESTEP_BEGIN | Prior to the solve for each time step.
NONLINEAR | Prior do each non-linear iteration during the solve.
@@ -0,0 +1 @@
# UserObject
@@ -1,10 +1,171 @@
<!-- MOOSE Documentation Stub: Remove this when content is added. -->
# Postprocessor System

A PostProcessor object in MOOSE is a C++ object that computes a single scalar (`Real`) value,
typically the value computed is an aggregation of data from a simulation. For example, the
maximum value of a variable (see [ElementExtremeValue.md]). The value compute may be coupled to
other systems via the `getPostprocessorValue` method available in most MOOSE objects.

MOOSE includes a large number of postprocessors within the framework, the complete list is
provided in [Available Objects list](#available-objects) section.

## Example Input File

The following input file snippet demonstrates the use of the
[ElementExtremeValue](ElementExtremeValue.md) to compute the minimum and maximum of the solution
variable "u".

!listing element_extreme_value.i block=Postprocessors

This snippet is a part of a test that may be executed using the MOOSE test application as follows.

```bash
cd ~/projects/moose/test
make -j8
cd tests/postprocessors/element_extreme_value
~/projects/moose/test/moose_test-opt -i element_extreme_value.i
```

The data from this calculation is reported in the terminal output by default and if [Exodus.md]
output is enabled the values will automatically be included in the output file. It is also possible
to export the data to a comma separated value (csv) file by enabling the [CSV.md]
object within the [Outputs](Outputs/index.md) block.

```bash
Postprocessor Values:
+----------------+----------------+----------------+
| time | max | min |
+----------------+----------------+----------------+
| 0.000000e+00 | 0.000000e+00 | 0.000000e+00 |
| 1.000000e+00 | 9.788675e-01 | 2.113249e-02 |
+----------------+----------------+----------------+
```

## Coupling Example Code

The values computed within a Postprocessor object may be used within other objects that inherit
from the [PostprocessorInterface.md], which is nearly every system within MOOSE. For example, the
the [PostprocessorNeumannBC.md] object allows for a Neumann boundary condition to be set to
a value computed from a postprocessor; this object will be used as example to demonstrate how
coupling is performed.

To understand how the coupling is coded it is beneficial to first see how the coupling is defined
via the input file. The following input file snippet shows that a [PointValue.md] postprocessor
is created and named "right_pp" and the [PostprocessorNeumannBC.md] uses this value to set the
boundary condition.

!listing pp_neumann.i block=Postprocessors BCs

This first step of coding this type of coupling begins by adding the necessary input file syntax to
the object that requires a postprocessor value, PostprocessorNeumannBC in this example. In all MOOSE
objects input file syntax is governed by the validParams function of an object. To add the ability
to couple a postprocessor, simply add a new parameter using the `PostprocessorName` type, as shown
below. Notice, that the add parameters call includes a default value that makes the use of the
postprocessor optional.

!listing PostprocessorNeumannBC.C start=template end=PostprocessorNeumannBC::

The actual postprocessor value must be assigned to a member variable of the class, thus in the header
a member variable must be created, which should always be a constant reference to a
`PostprocessorValue` type. Since this is a reference it must be initialized, this occurs in the
source file by calling the `getPostprocessorValue` method and providing the name used in the
validParams function. The following snippets show declaration of the reference in the header and
the initialization of this reference in the source file. The `_value` member variable is then
available for use anywhere inside the object, for the case of the boundary condition it is utilized
in the computation of the residual.

!listing PostprocessorNeumannBC.h line=PostprocessorValue

!listing PostprocessorNeumannBC.C start=PostprocessorNeumannBC:: end=} include-end=true

## Creating a `Postprocessor` Object

In general, every Postprocessor object has two methods that must be defined "execute" and
"getValue".

First, consider the execute method. This method is called by MOOSE at different time
depending on the type of postprocessor object. Therefore, when creating a Postprocessor object
the new object should inherit from one of the following C++ classes:

- +GeneralPostprocessor+: "execute" is called once on each execution flag.
- +NodalPostprocessor+: "execute" is called for each +node+ within the mesh on each execution flag.
- +ElementalPostprocessor+: "execute" is called for each +element+ within the mesh on each execution
flag.
- +InternalSidePostprocessor+: "execute" is called for each +side+, that is not on a boundary,
within the mesh on each execution flag.
- +SidePostprocessor+: "execute" is called for each +side+, that is on a boundary, within the mesh
on each execution flag.

The use of execution flags is discussed in the [Execute On](#execute-on) section.

The getValue method is responsible for returning the value of the postprocessor object, this
value is what is used by all objects that are coupled to the postprocessor. In some cases the
necessary communication is performed within this method, but in general this following is preferred.

### Parallel Considerations

When creating a postprocessor it is often necessary to perform some parallel communication
to ensure that the value being computed is correct across processes and threads. Three additional
methods exists for making this process as simple as possible.

- `initialize`: This is called prior to the execution of the postprocessor and should be used
to setup the object to be in a known state. It is important to point out that execution
in this context includes all calls to the execute method. For example, for a `NodalPostprocessor`
object the initialize method is called and then the execute method is called for all nodes.
- `finalize`: This is called after the execution of the postprocessor and is intended to perform
communication to prepare the object for the call to the getValue method.
- `threadJoin`: This is called after the execution of the postprocessor and is intended to perform
aggregation for shared memory parallelism.

To understand the use of these methods the [AverageNodalVariableValue.md] postprocessor shall be
used as an example. As the name suggests this postprocessor computes the average of the value
of a variable at the nodes. To perform this calculation the variable values from each node
are summed as is the number of values within the execute method. Then the getValue method
returns the average by returning the sum divided by the count. The following snippet shows the
these two methods: the `_u[_qp]` is the value of the variable at the current node that comes
from a shared base class and `_sum` and `_n` are a member variables defined within class for
performing the calculation.

!listing AverageNodalVariableValue.C start=doco-execute-get-start end=doco-execute-get-end include-start=false

In parallel, the calls to the execute method occur on each process or thread on a subset of the
domain, in this case nodes. Therefore, the computed values must be combined to get the actual
summations required to compute the average value. The first step is to setup the state
of this calculation within the initialize method, which in this example sets the
`_sum` and `_n` member variables to zero.

!listing AverageNodalVariableValue.C start=doco-init-start end=doco-init-end include-start=false

After the aforementioned execute method is called for each node the computed values for `_sum` and
`_n` must be aggregated from across processes to the root processes. For this problem a gather
operation is required to collect the values computed on all processes to the root process. This is
accomplished via the `gatherSum` method.

!listing AverageNodalVariableValue.C start=doco-final-start end=doco-final-end include-start=false

Of course, the type of communication necessary depends on the calculation being performed. The
[UserObject.md] base class includes helper methods for common parallel communications functions.

The initialize and finalize methods are utilized to aggregate for message passing (MPI) based
parallelism. For shared memory parallelism the theadJoin method is used. This method is called,
like finalize, after execution is complete and includes a single argument. This argument is a
reference to a UserObject, which is a base class of Postprocessor objects. The purpose of this
method is to enable the aggregation for the Postprocessor objects that were executed on other
threads to the object on the root thread. For the AverageNodalVariableValue postprocessor the
values for `_sum` and `_n` on the root process object are updated to include the these same values
from the other threads.

!listing AverageNodalVariableValue.C start=doco-thread-start end=doco-thread-end include-start=false


## Execute On... id=execute-on

Postprocessor objects inherit from the [SetupInterface.md] that allows the objects to execute and
varying and multiple times during a simulation, such as during initialization and at the end of
each time step. Refer to the [SetupInterface.md] for additional information.

# Postprocessors System

!syntax list /Postprocessors objects=True actions=False subsystems=False

!syntax list /Postprocessors objects=False actions=False subsystems=True

!syntax list /Postprocessors objects=False actions=True subsystems=False

@@ -24,14 +24,13 @@ class AverageNodalVariableValue : public NodalVariablePostprocessor
AverageNodalVariableValue(const InputParameters & parameters);

virtual void initialize() override;
virtual void finalize() override;
virtual void execute() override;

virtual Real getValue() override;

virtual void threadJoin(const UserObject & y) override;

protected:
Real _avg;
Real _sum;
unsigned int _n;
};

@@ -11,6 +11,7 @@

registerMooseObject("MooseApp", PostprocessorDirichletBC);

// Used by MOOSEDocs: syntax/Postprocessors/index.md
template <>
InputParameters
validParams<PostprocessorDirichletBC>()
@@ -22,37 +22,50 @@ validParams<AverageNodalVariableValue>()
}

AverageNodalVariableValue::AverageNodalVariableValue(const InputParameters & parameters)
: NodalVariablePostprocessor(parameters), _avg(0), _n(0)
: NodalVariablePostprocessor(parameters), _sum(0), _n(0)
{
}

// doco-init-start
void
AverageNodalVariableValue::initialize()
{
_avg = 0;
_sum = 0;
_n = 0;
}
// doco-init-end

// doco-execute-get-start
void
AverageNodalVariableValue::execute()
{
_avg += _u[_qp];
_sum += _u[_qp];
_n++;
}

Real
AverageNodalVariableValue::getValue()
{
gatherSum(_avg);
return _sum / _n;
}
// doco-execute-get-end

// doco-final-start
void
AverageNodalVariableValue::finalize()
{
gatherSum(_sum);
gatherSum(_n);

return _avg / _n;
}
// doco-final-end

// doco-thread-start
void
AverageNodalVariableValue::threadJoin(const UserObject & y)
{
const AverageNodalVariableValue & pps = static_cast<const AverageNodalVariableValue &>(y);
_avg += pps._avg;
_sum += pps._sum;
_n += pps._n;
}
// doco-thread-end
@@ -1,3 +1,5 @@
# NOTE: This file is used within the documentation, so please do not change names within the file
# without checking that associated documentation is not affected, see syntax/Postprocessors/index.md.
[Mesh]
type = GeneratedMesh
dim = 2
@@ -6,45 +8,45 @@
[]

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

[AuxVariables]
[./aux]
[aux]
initial_condition = 5
[../]
[]
[]

[Kernels]
[./diff]
[diff]
type = Diffusion
variable = u
[../]
[]
[]

[BCs]
[./left]
[left]
type = DirichletBC
variable = u
boundary = left
value = 0
[../]
[./right]
[]
[right]
type = PostprocessorNeumannBC
variable = u
boundary = right
postprocessor = right_pp
[../]
[]
[]

[Postprocessors]
[./right_pp]
[right_pp]
type = PointValue
point = '0.5 0.5 0'
variable = aux
execute_on = 'initial'
[../]
[]
[]

[Executioner]
@@ -6,42 +6,42 @@
[]

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

[Kernels]
[./diff]
[diff]
type = Diffusion
variable = u
[../]
[]
[]

[BCs]
[./left]
[left]
type = DirichletBC
variable = u
boundary = left
value = 0
[../]
[./right]
[]
[right]
type = DirichletBC
variable = u
boundary = right
value = 1
[../]
[]
[]

[Postprocessors]
[./max]
[max]
type = ElementExtremeValue
variable = u
[../]
[./min]
[]
[min]
type = ElementExtremeValue
variable = u
value_type = min
[../]
[]
[]

[Executioner]
@@ -54,4 +54,3 @@
[Outputs]
exodus = true
[]

0 comments on commit 913f3c7

Please sign in to comment.
You can’t perform that action at this time.