Skip to content

Commit

Permalink
Merge pull request #25445 from GiudGiud/PR_pressure_pin
Browse files Browse the repository at this point in the history
Use a postprocessing step to apply the pressure constraint in loops
  • Loading branch information
GiudGiud authored Sep 14, 2023
2 parents 7412530 + a3847d0 commit 14e1da6
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# NSFVPressurePin

!syntax description /UserObjects/NSFVPressurePin

## Overview

The `NSFVPressurePin` can pin the pressure in two modes:

- by offsetting the pressure variable to make it have an average equal to the [!param](/UserObjects/NSFVPressurePin/phi0) parameter value
- by offsetting the pressure variable to make its value equal to the [!param](/UserObjects/NSFVPressurePin/phi0) parameter value in the element
containing the point specified by the [!param](/UserObjects/NSFVPressurePin/point) parameter.


!alert note
In the [NSFVAction.md], a `NSFVPressurePin` can be used by setting the [!param](/Modules/NavierStokesFV/pinned_pressure_type) parameter
to `average-uo` or `point-value-uo` respectively.

!syntax parameters /UserObjects/NSFVPressurePin

!syntax inputs /UserObjects/NSFVPressurePin

!syntax children /UserObjects/NSFVPressurePin
62 changes: 49 additions & 13 deletions modules/navier_stokes/include/base/NSFVBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ NSFVBase<BaseType>::validParams()
params.addParam<bool>(
"pin_pressure", false, "Switch to enable pressure shifting for incompressible simulations.");

MooseEnum s_type("average point-value", "average");
MooseEnum s_type("average point-value average-uo point-value-uo", "average-uo");
params.addParam<MooseEnum>(
"pinned_pressure_type",
s_type,
Expand Down Expand Up @@ -1267,8 +1267,14 @@ NSFVBase<BaseType>::copyNSNodalVariables()
parameters().template get<std::string>("initial_from_file_timestep"));

if (parameters().template get<bool>("pin_pressure"))
system.addVariableToCopy(
"lambda", "lambda", parameters().template get<std::string>("initial_from_file_timestep"));
{
auto type = parameters().template get<MooseEnum>("pinned_pressure_type");
if (type == "point-value" || type == "average")
system.addVariableToCopy(
"lambda",
"lambda",
parameters().template get<std::string>("initial_from_file_timestep"));
}

if (_turbulence_handling == "mixing-length")
getProblem().getAuxiliarySystem().addVariableToCopy(
Expand Down Expand Up @@ -1351,11 +1357,13 @@ NSFVBase<BaseType>::addINSVariables()
// Add lagrange multiplier for pinning pressure, if needed
if (parameters().template get<bool>("pin_pressure"))
{
auto type = parameters().template get<MooseEnum>("pinned_pressure_type");
auto lm_params = getFactory().getValidParams("MooseVariableScalar");
lm_params.template set<MooseEnum>("family") = "scalar";
lm_params.template set<MooseEnum>("order") = "first";

addNSNonlinearVariable("MooseVariableScalar", "lambda", lm_params);
if (type == "point-value" || type == "average")
addNSNonlinearVariable("MooseVariableScalar", "lambda", lm_params);
}

// Add turbulence-related variables
Expand Down Expand Up @@ -1627,21 +1635,48 @@ NSFVBase<BaseType>::addINSMassKernels()
if (parameters().template get<bool>("pin_pressure"))
{
MooseEnum pin_type = parameters().template get<MooseEnum>("pinned_pressure_type");
std::string kernel_type;
std::string object_type;
if (pin_type == "point-value")
kernel_type = "FVPointValueConstraint";
object_type = "FVPointValueConstraint";
else if (pin_type == "average")
object_type = "FVIntegralValueConstraint";
else if (pin_type == "average-uo")
object_type = "NSFVPressurePin";
else
kernel_type = "FVIntegralValueConstraint";
InputParameters params = getFactory().getValidParams(kernel_type);
params.template set<CoupledName>("lambda") = {"lambda"};
object_type = "NSFVPressurePin";

// Create the average value postprocessor if needed
if (pin_type == "average-uo")
{
// Volume average by default, but we could do inlet or outlet for example
InputParameters params = getFactory().getValidParams("ElementAverageValue");
params.template set<std::vector<VariableName>>("variable") = {_pressure_name};
assignBlocks(params, _blocks);
params.template set<std::vector<OutputName>>("outputs") = {"none"};
getProblem().addPostprocessor("ElementAverageValue", "nsfv_pressure_average", params);
}

InputParameters params = getFactory().getValidParams(object_type);
if (pin_type == "point-value" || pin_type == "average")
params.template set<CoupledName>("lambda") = {"lambda"};
else if (pin_type == "point-value-uo")
params.template set<MooseEnum>("pin_type") = "point-value";
else
params.template set<MooseEnum>("pin_type") = "average";

params.template set<PostprocessorName>("phi0") =
parameters().template get<PostprocessorName>("pinned_pressure_value");
params.template set<NonlinearVariableName>("variable") = _pressure_name;
if (pin_type == "point-value")
if (pin_type == "point-value" || pin_type == "point-value-uo")
params.template set<Point>("point") =
parameters().template get<Point>("pinned_pressure_point");
else if (pin_type == "average-uo")
params.template set<PostprocessorName>("pressure_average") = "nsfv_pressure_average";

getProblem().addFVKernel(kernel_type, prefix() + "ins_mass_pressure_constraint", params);
if (pin_type == "point-value" || pin_type == "average")
getProblem().addFVKernel(object_type, prefix() + "ins_mass_pressure_constraint", params);
else
getProblem().addUserObject(object_type, prefix() + "ins_mass_pressure_pin", params);
}
}

Expand Down Expand Up @@ -3070,8 +3105,9 @@ NSFVBase<BaseType>::checkGeneralControlErrors()
checkDependentParameterError("pin_pressure", {"pinned_pressure_type"}, true);

MooseEnum pin_type = parameters().template get<MooseEnum>("pinned_pressure_type");
checkDependentParameterError(
"pinned_pressure_type", {"pinned_pressure_point"}, pin_type == "point-value");
checkDependentParameterError("pinned_pressure_type",
{"pinned_pressure_point"},
pin_type == "point-value" || pin_type == "point-value-uo");
}

if (!_has_energy_equation)
Expand Down
58 changes: 58 additions & 0 deletions modules/navier_stokes/include/userobjects/NSFVPressurePin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once

#include "GeneralUserObject.h"
#include "BlockRestrictable.h"
#include "INSFVPressureVariable.h"
#include "NonADFunctorInterface.h"

class MooseMesh;
class INSFVPressureVariable;

/**
* This user-object corrects the pressure
*/
class NSFVPressurePin : public GeneralUserObject,
public BlockRestrictable,
public NonADFunctorInterface
{
public:
static InputParameters validParams();
NSFVPressurePin(const InputParameters & params);

void initialSetup() override{};
void initialize() override{};
void execute() override;
void finalize() override{};

protected:
/// LibMesh mesh class for the current simulation mesh
MeshBase & _mesh;

/// The thread 0 copy of the pressure variable
INSFVPressureVariable * const _p;

/// Value of the pressure pin
const PostprocessorValue & _p0;

/// Pressure pin type
const MooseEnum _pressure_pin_type;

/// If using point-value pressure pin, the point at which to apply the pin
const Point _pressure_pin_point;

/// If using average pressure pin, provides the average pressure value
const PostprocessorValue * const _current_pressure_average;

private:
/// The nonlinear system
SystemBase & _sys;
};
121 changes: 121 additions & 0 deletions modules/navier_stokes/src/userobjects/NSFVPressurePin.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "NSFVPressurePin.h"
#include "SubProblem.h"
#include "SystemBase.h"
#include "NS.h"

#include "libmesh/mesh_base.h"
#include "libmesh/elem_range.h"
#include "libmesh/numeric_vector.h"
#include "libmesh/mesh_tools.h"

using namespace libMesh;

registerMooseObject("NavierStokesApp", NSFVPressurePin);

InputParameters
NSFVPressurePin::validParams()
{
auto params = GeneralUserObject::validParams();
params += BlockRestrictable::validParams();

// Not much flexibility there, applying the pin at the wrong time prevents convergence
ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
// all bad choices
exec_enum.removeAvailableFlags(EXEC_LINEAR, EXEC_NONE, EXEC_TIMESTEP_BEGIN, EXEC_ALWAYS);
exec_enum = {EXEC_TIMESTEP_END};

// Avoid uninitialized residual objects
params.suppressParameter<bool>("force_preic");

params.addParam<NonlinearVariableName>("variable", NS::pressure, "Pressure variable");
params.addParam<PostprocessorName>("phi0", "Pressure pin value");
MooseEnum pin_types("point-value average");
params.addRequiredParam<MooseEnum>("pin_type", pin_types, "How to pin the pressure");
params.addParam<Point>(
"point",
"The XYZ coordinates of a point inside an element where the pinned value shall be enforced.");
params.addParam<PostprocessorName>(
"pressure_average", "A postprocessor that computes the average of the pressure variable");

params.addClassDescription("Pins the pressure after a solve");

return params;
}

NSFVPressurePin::NSFVPressurePin(const InputParameters & params)
: GeneralUserObject(params),
BlockRestrictable(this),
NonADFunctorInterface(this),
_mesh(UserObject::_subproblem.mesh().getMesh()),
_p(dynamic_cast<INSFVPressureVariable *>(
&UserObject::_subproblem.getVariable(0, getParam<NonlinearVariableName>("variable")))),
_p0(getPostprocessorValue("phi0")),
_pressure_pin_type(getParam<MooseEnum>("pin_type")),
_pressure_pin_point(_pressure_pin_type == "point-value" ? getParam<Point>("point")
: Point(0, 0, 0)),
_current_pressure_average(
_pressure_pin_type == "average" ? &getPostprocessorValue("pressure_average") : nullptr),
_sys(*getCheckedPointerParam<SystemBase *>("_sys"))
{
if (!_p)
paramError(NS::pressure, "the pressure must be a INSFVPressureVariable.");
// Check execute_on of the postprocessor
if (_pressure_pin_type == "average" &&
!_fe_problem.getUserObjectBase(getParam<PostprocessorName>("pressure_average"))
.getExecuteOnEnum()
.contains(getExecuteOnEnum()))
paramError("pressure_average",
"Pressure average postprocessor must include the pin execute_on flags");
}

void
NSFVPressurePin::execute()
{
// Get the value of the pin
Real pin_value = 0;
if (_pressure_pin_type == "point-value")
{
Real point_value = _sys.system().point_value(_p->number(), _pressure_pin_point, false);

/**
* If we get exactly zero, we don't know if the locator couldn't find an element, or
* if the solution is truly zero, more checking is needed.
*/
if (MooseUtils::absoluteFuzzyEqual(point_value, 0.0))
{
auto pl = _mesh.sub_point_locator();
pl->enable_out_of_mesh_mode();

auto * elem = (*pl)(_pressure_pin_point);
auto elem_id = elem ? elem->id() : DofObject::invalid_id;
gatherMin(elem_id);

if (elem_id == DofObject::invalid_id)
mooseError("No element to gather point pressure from located at ", _pressure_pin_point);
// Default at construction
pl->disable_out_of_mesh_mode();
}

pin_value = _p0 - point_value;
}
else
pin_value = _p0 - *_current_pressure_average;

// Offset the entire pressure vector by the value of the pin
NumericVector<Number> & sln = _sys.solution();
std::set<dof_id_type> local_dofs;
_sys.system().local_dof_indices(_p->number(), local_dofs);
for (const auto dof : local_dofs)
sln.add(dof, pin_value);
sln.close();
_sys.system().update();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
exodiff = 'lid-driven-action_out.e'
requirement = 'The system shall be able to solve the incompressible Navier-Stokes equations in a lid-driven cavity using the finite volume Navier-Stokes action.'
[]
[exo-action-uo-pin-average]
type = 'Exodiff'
input = 'lid-driven-action.i'
cli_args = 'Modules/NavierStokesFV/pinned_pressure_type=average-uo Postprocessors/lambda/type=Receiver Postprocessors/lambda/default=0'
exodiff = 'lid-driven-action_out.e'
requirement = 'The system shall be able to solve the incompressible Navier-Stokes equations in a lid-driven cavity using the finite volume Navier-Stokes action and an average pressure pin applied at the end of every time step.'
[]
[exo-approximate-rc-action]
type = 'Exodiff'
input = 'lid-driven-action.i'
Expand All @@ -25,20 +32,36 @@
input = 'lid-driven.i'
exodiff = 'lid-driven-point-pressure.e'
requirement = 'The system shall be able to solve the incompressible Navier-Stokes equations in a lid-driven cavity by fixing the point value of the pressure at a certain coordinate.'
cli_args = "FVKernels/mean_zero_pressure/type='FVPointValueConstraint' FVKernels/mean_zero_pressure/point='0.001 0.099 0.0' Outputs/file_base='lid-driven-point-pressure'"
cli_args = "FVKernels/mean_zero_pressure/type='FVPointValueConstraint' "
"FVKernels/mean_zero_pressure/point='0.001 0.099 0.0' "
"Outputs/file_base='lid-driven-point-pressure'"
[]
[point-pressure-action]
type = 'Exodiff'
input = 'lid-driven-action.i'
exodiff = 'lid-driven-point-pressure-action.e'
requirement = 'The system shall be able to solve the incompressible Navier-Stokes equations in a lid-driven cavity by fixing the point value of the pressure at a certain coordinate using the NSFV action syntax.'
cli_args = "Modules/NavierStokesFV/pinned_pressure_type=point-value Modules/NavierStokesFV/pinned_pressure_point='0.001 0.099 0.0' Outputs/file_base='lid-driven-point-pressure-action'"
cli_args = "Modules/NavierStokesFV/pinned_pressure_type=point-value "
"Modules/NavierStokesFV/pinned_pressure_point='0.001 0.099 0.0' "
"Outputs/file_base='lid-driven-point-pressure-action'"
[]
[point-pressure-action-uo]
type = 'Exodiff'
input = 'lid-driven-action.i'
exodiff = 'lid-driven-point-pressure-action.e'
requirement = 'The system shall be able to solve the incompressible Navier-Stokes equations in a lid-driven cavity by fixing the point value of the pressure at a certain coordinate using the Navier-Stokes finite volume action syntax, with a post-treatment of the pressure rather than a Lagrange multiplier-based constraint.'
cli_args = "Modules/NavierStokesFV/pinned_pressure_type=point-value-uo "
"Modules/NavierStokesFV/pinned_pressure_point='0.001 0.099 0.0' "
"Outputs/file_base='lid-driven-point-pressure-action' "
"Postprocessors/lambda/type=Receiver Postprocessors/lambda/default=0"
prereq = 'point-pressure-action'
[]
[point-pressure-action-error]
type = 'RunException'
input = 'lid-driven-action.i'
requirement = 'The system shall throw an error if the user requests integral value pressure pinning while specifying a point for the pin.'
expect_err = "This parameter should not be given by the user with the corresponding pinned_pressure_type setting!"
expect_err = "This parameter should not be given by the user with the corresponding "
"pinned_pressure_type setting!"
cli_args = "Modules/NavierStokesFV/pinned_pressure_point='0.001 0.099 0.0'"
[]
[nonsingular]
Expand Down

0 comments on commit 14e1da6

Please sign in to comment.