Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get points for SpatialVPP from user object #18932

Merged
merged 11 commits into from Sep 28, 2021
Merged
Expand Up @@ -11,6 +11,12 @@ This postprocessor may be used to convert spatial user objects such as
postprocessor that can be transferred to another application with a
[MultiAppVectorPostprocessorTransfer](/transfers/MultiAppVectorPostprocessorTransfer.md).

If neither [!param](/VectorPostprocessors/SpatialUserObjectVectorPostprocessor/points)
or [!param](/VectorPostprocessors/SpatialUserObjectVectorPostprocessor/points_file) are
provided, this object will attempt to get the spatial points directly from the user object.
These points will represent locations in space where the user object obtains a unique value.
To use this feature, the user object must define the `spatialPoints()` interface.

## Example Input File Syntax

!listing test/tests/vectorpostprocessors/spatial_userobject_vector_postprocessor/spatial_userobject.i
Expand Down
19 changes: 19 additions & 0 deletions framework/include/userobject/LayeredBase.h
Expand Up @@ -65,6 +65,17 @@ class LayeredBase : private Restartable
*/
virtual unsigned int getLayer(Point p) const;

/**
* Get the center coordinates for the layers (along given direction)
*/
const std::vector<Real> & getLayerCenters() const { return _layer_centers; }

/**
* Get direction of the layers
* @return layer direction
*/
unsigned int direction() const { return _direction; }

virtual void initialize();
virtual void finalize();
virtual void threadJoin(const UserObject & y);
Expand All @@ -87,6 +98,11 @@ class LayeredBase : private Restartable
*/
void getBounds();

/**
* Compute the center points for each layer
*/
void computeLayerCenters();

/// Name of this object
std::string _layered_base_name;

Expand Down Expand Up @@ -117,6 +133,9 @@ class LayeredBase : private Restartable
/// true if this object operates on the displaced mesh, otherwise false
bool _using_displaced_mesh;

/// center coordinates of each layer
std::vector<Real> _layer_centers;

Real _direction_min;
Real _direction_max;

Expand Down
36 changes: 36 additions & 0 deletions framework/include/userobject/NearestPointBase.h
Expand Up @@ -13,6 +13,7 @@
#include "ElementIntegralVariableUserObject.h"
#include "Enumerate.h"
#include "DelimitedFileReader.h"
#include "LayeredBase.h"

// Forward Declarations
class UserObject;
Expand Down Expand Up @@ -81,6 +82,14 @@ class NearestPointBase : public BaseType
*/
virtual Real spatialValue(const Point & p) const override;

/**
* Get the points at which the nearest operation is performed
* @return points
*/
virtual const std::vector<Point> & getPoints() const { return _points; }

virtual const std::vector<Point> spatialPoints() const override;

protected:
/**
* Fills in the `_points` variable from either 'points' or 'points_file' parameter.
Expand Down Expand Up @@ -252,3 +261,30 @@ NearestPointBase<UserObjectType, BaseType>::nearestUserObject(const Point & p) c

return _user_objects[closest];
}

template <typename UserObjectType, typename BaseType>
const std::vector<Point>
NearestPointBase<UserObjectType, BaseType>::spatialPoints() const
{
std::vector<Point> points;

for (MooseIndex(_points) i = 0; i < _points.size(); ++i)
{
std::shared_ptr<LayeredBase> layered_base =
std::dynamic_pointer_cast<LayeredBase>(_user_objects[i]);
if (layered_base)
{
const auto & layers = layered_base->getLayerCenters();
auto direction = layered_base->direction();

for (const auto & l : layers)
{
Point pt = _points[i];
pt(direction) = l;
points.push_back(pt);
}
}
}

return points;
}
Expand Up @@ -41,5 +41,7 @@ class NearestPointIntegralVariablePostprocessor
virtual void finalize() override;

protected:
virtual const std::vector<Point> spatialPoints() const override { return getPoints(); }

VectorPostprocessorValue & _np_post_processor_values;
};
Expand Up @@ -35,4 +35,3 @@ class NearestPointLayeredAverage

NearestPointLayeredAverage(const InputParameters & parameters);
};

11 changes: 11 additions & 0 deletions framework/include/userobject/UserObject.h
Expand Up @@ -99,6 +99,17 @@ class UserObject : public MooseObject,
mooseError(name(), " does not satisfy the Spatial UserObject interface!");
}

/**
* Optional interface function for providing the points at which a UserObject attains
* spatial values. If a UserObject overrides this function, then other objects that
* take both the UserObject and points can instead directly use the points specified
* on the UserObject.
*/
virtual const std::vector<Point> spatialPoints() const
{
mooseError("Spatial UserObject interface is not satisfied; spatialPoints() must be overridden");
}

/**
* Must override.
*
Expand Down
Expand Up @@ -42,7 +42,9 @@ class SpatialUserObjectVectorPostprocessor : public GeneralVectorPostprocessor
virtual void execute() override;

/**
* Read the points at which to evaluate from a vector or file
* Read the points at which to evaluate from a vector ('points'), a file ('points_file'),
* or neither (which will read from the user object directly if it satisfies the
* spatialPoints interface)
*/
void fillPoints();

Expand Down
20 changes: 20 additions & 0 deletions framework/src/userobject/LayeredBase.C
Expand Up @@ -119,6 +119,7 @@ LayeredBase::LayeredBase(const InputParameters & parameters)
_layer_has_value.resize(_num_layers);

getBounds();
computeLayerCenters();
}

Real
Expand Down Expand Up @@ -320,6 +321,25 @@ LayeredBase::getLayer(Point p) const
}
}

void
LayeredBase::computeLayerCenters()
{
_layer_centers.resize(_num_layers);

if (_interval_based)
{
Real dx = (_direction_max - _direction_min) / _num_layers;

for (unsigned int i = 0; i < _num_layers; ++i)
_layer_centers[i] = (i + 0.5) * dx;
}
else
{
for (unsigned int i = 0; i < _num_layers; ++i)
_layer_centers[i] = 0.5 * (_layer_bounds[i + 1] + _layer_bounds[i]);
}
}

void
LayeredBase::setLayerValue(unsigned int layer, Real value)
{
Expand Down
Expand Up @@ -47,24 +47,29 @@ SpatialUserObjectVectorPostprocessor::SpatialUserObjectVectorPostprocessor(
void
SpatialUserObjectVectorPostprocessor::fillPoints()
{
if (isParamValid("points") && isParamValid("points_file"))
mooseError(name(), ": Both 'points' and 'points_file' cannot be specified simultaneously.");

if (isParamValid("points"))
if (!isParamValid("points") && !isParamValid("points_file"))
{
_points = getParam<std::vector<Point>>("points");
_points = _uo.spatialPoints();
}
else if (isParamValid("points_file"))
else
{
const FileName & points_file = getParam<FileName>("points_file");
if (isParamValid("points") && isParamValid("points_file"))
paramError("points", "Both 'points' and 'points_file' cannot be specified simultaneously.");

MooseUtils::DelimitedFileReader file(points_file, &_communicator);
file.setFormatFlag(MooseUtils::DelimitedFileReader::FormatFlag::ROWS);
file.read();
_points = file.getDataAsPoints();
if (isParamValid("points"))
{
_points = getParam<std::vector<Point>>("points");
}
else if (isParamValid("points_file"))
{
const FileName & points_file = getParam<FileName>("points_file");

MooseUtils::DelimitedFileReader file(points_file, &_communicator);
file.setFormatFlag(MooseUtils::DelimitedFileReader::FormatFlag::ROWS);
file.read();
_points = file.getDataAsPoints();
}
}
else
mooseError(name(), ": You need to supply either 'points' or 'points_file' parameter.");
}

void
Expand Down
@@ -0,0 +1,13 @@
spatial_from_uo
0.57200144204315
0.59327203110192
0.72217401051094
0.92988140336612
0.94305416628624
0.97815035204218
0.35772503752114
0.40398494853582
0.63253972645224
0.84480651655479
0.87493343496837
0.95253935097336
@@ -0,0 +1,11 @@
spatial_from_uo
0.31666529764005
0.81666529764055
0.40555618331948
0.90555618331745
0.503334383066
1.0033343830657
0.60238241390942
1.102382413908
0.70185372601401
1.2018537260165
@@ -0,0 +1,105 @@
[Mesh]
type = GeneratedMesh
dim = 3
xmax = 1.5
ymax = 1.5
zmax = 1.2
nx = 10
ny = 10
nz = 10
[]

[Variables]
[u]
[]
[]

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

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

[AuxKernels]
[np_layered_average]
type = SpatialUserObjectAux
variable = np_layered_average
execute_on = timestep_end
user_object = npla
[]
[]

[BCs]
[left]
type = DirichletBC
variable = u
boundary = left
value = 0
[]
[one]
type = DirichletBC
variable = u
boundary = 'right back top'
value = 1
[]
[]

[UserObjects]
[npla]
type = NearestPointLayeredAverage
direction = y
num_layers = 3
variable = u
points = '0.375 0.0 0.3
1.125 0.0 0.3
0.375 0.0 0.9
1.125 0.0 0.9'
[]
[]

[VectorPostprocessors]
# getting the points from the user object itself is here exactly equivalent to the points
# provided in the 'spatial_manually_provided' vector postprocessor
[spatial_from_uo]
type = SpatialUserObjectVectorPostprocessor
userobject = npla
[]
[spatial_manually_provided]
type = SpatialUserObjectVectorPostprocessor
userobject = npla
points = '0.375 0.25 0.3
0.375 0.75 0.3
0.375 1.25 0.3

1.125 0.25 0.3
1.125 0.75 0.3
1.125 1.25 0.3

0.375 0.25 0.9
0.375 0.75 0.9
0.375 1.25 0.9

1.125 0.25 0.9
1.125 0.75 0.9
1.125 1.25 0.9'
[]
[]

[Executioner]
type = Steady
petsc_options_iname = '-pc_type -pc_hypre_type'
petsc_options_value = 'hypre boomeramg'
[]

[Outputs]
csv = true
execute_on = 'final'
[]