Skip to content

Commit

Permalink
Restricting MultiAppUserObjectTransfer to boundaries and blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
andrsd committed Dec 2, 2020
1 parent c05cacf commit 9a4ba83
Show file tree
Hide file tree
Showing 14 changed files with 668 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@
!syntax description /Transfers/MultiAppUserObjectTransfer

## Description

MultiAppUserObjectTransfer transfers information from a UserObject in the master/sub application to an AuxVariable in the sub/master application based on the direction of transfer (to_multiapp/from_multiApp).

The transfer can be restricted to a subdomain using the [!param](/Transfers/MultiAppUserObjectTransfer/block) parameter or a boundary using the [!param](/Transfers/MultiAppUserObjectTransfer/boundary) parameter.

## To MultiApp

If the AuxVariable in the sub applications is a nodal AuxVariable, for each node in the sub application the value at the corresponding position in the master application is queried from the master UserObject, and this value is set to the AuxVariable at that node. A similar approach is followed for the elemental AuxVariable but with the centroid of the element instead of nodal position.

## From MultiApp

For nodal AuxVariable in the master application, it is first determined whether the node is contained within the bounding box of the sub application. If the master node lies within a sub application's bounding box, the value of the sub application UserObject at that location is transferred to the master AuxVariable. A similar approach is followed for the elemental AuxVariable but with the centroid of the master element instead of nodal position.

When `all_master_nodes_contained_in_sub_app` option is set to true, an error is generated if the master node/element does not lie within the bounding boxes of any of the sub applications. An error is also generated if the master node/element lies within the bounding boxes of 2 or more sub applications.
When `all_master_nodes_contained_in_sub_app` option is set to true, an error is generated if the master node/element does not lie within the bounding boxes of any of the sub applications. An error is also generated if the master node/element lies within the bounding boxes of 2 or more sub applications.

!syntax parameters /Transfers/MultiAppUserObjectTransfer

Expand Down
64 changes: 61 additions & 3 deletions framework/include/transfers/MultiAppUserObjectTransfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,17 @@ template <>
InputParameters validParams<MultiAppUserObjectTransfer>();

/**
* Samples a variable's value in the Master domain at the point where
* the MultiApp is. Copies that value into a postprocessor in the
* MultiApp.
* Loops over a target mesh and uses either node or element centroid location (based on the target
* variable type) for sampling a user object (i.e. the object must implement `spatialValue` API).
* This value is then stored into the target variable (either nodal or elemental).
* Note: Higher order variables are not supported.
*
* This transfer can be block and boundary restricted. The BlockRestrictable and
* BoundaryRestrictable classes cannot be used, becuase they would check the block, boundary and
* target variable during object construction. At that time, the underlying sub-app is not created
* yet, so this check would fail. That is also the reason why the block and boundary restriction are
* pulled in during `execute` and not in the constructor. Also note, that in a sub-app setup there
* might be multiple instances of the sub-app, so this check needs to be done on per-sub-app basis.
*/
class MultiAppUserObjectTransfer : public MultiAppConservativeTransfer
{
Expand All @@ -33,6 +41,49 @@ class MultiAppUserObjectTransfer : public MultiAppConservativeTransfer
virtual void execute() override;

protected:
/**
* @return true if this transfer is restricted to a block, otherwise false
*/
bool blockRestricted() const;

/**
* @return true if this transfer is restricted to a boundary, otherwise false
*/
bool boundaryRestricted() const;

/**
* Check that element 'elem' is part of the domain this transfer is restricted to
*/
bool hasBlocks(const Elem * elem) const;

/**
* Check that Node 'node' belongs to block this transfer is restricted to
*
* @param mesh The mesh this transfer is active on
* @param node The node to check
*/
bool hasBlocks(const MooseMesh * mesh, const Node * node) const;

/**
* Check that the node belongs to boundary this transfer is restricted to
*
* @return true if the node belongs to the boundary this transfer is restricted to, false
* otherwise
* @param mesh The mesh this transfer is active on
* @param node The node to check
*/
bool isBoundaryNode(const MooseMesh * mesh, const Node * node) const;

/**
* Check that the element belongs to boundary this transfer is restricted to
*
* @return true if the element belongs to the boundary this transfer is restricted to, false
* otherwise
* @param mesh The mesh this transfer is active on
* @param elem The element to check
*/
bool isBoundaryElem(const MooseMesh * mesh, const Elem * elem) const;

std::string _user_object_name;

/**
Expand All @@ -43,4 +94,11 @@ class MultiAppUserObjectTransfer : public MultiAppConservativeTransfer

/// whether to check the bounding box check or not
const bool _skip_bbox_check;

private:
/// Set of block ids this transfer is restricted to
std::set<SubdomainID> _blk_ids;

/// Set of the boundary ids
std::set<BoundaryID> _bnd_ids;
};
155 changes: 141 additions & 14 deletions framework/src/transfers/MultiAppUserObjectTransfer.C
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ MultiAppUserObjectTransfer::validParams()
"skip_bounding_box_check",
false,
"Skip the check if the to_elem is within the bounding box of the from_app.");
params.addParam<std::vector<SubdomainName>>(
"block", "The block we are transferring to (if not specified, whole domain is used).");
params.addParam<std::vector<BoundaryName>>(
"boundary",
"The boundary we are transferring to (if not specified, whole domain is used unless 'block' "
"parameter is used).");

params.addClassDescription(
"Samples a variable's value in the Master domain at the point where the MultiApp is and "
Expand All @@ -75,6 +81,9 @@ MultiAppUserObjectTransfer::MultiAppUserObjectTransfer(const InputParameters & p
paramError("source_variable",
" You should not provide any source variables since the transfer takes values from "
"user objects ");

if (isParamValid("block") && isParamValid("boundary"))
mooseError(name(), ": Transfer can be either block- or boundary-restricted. Not both.");
}

void
Expand All @@ -100,14 +109,29 @@ MultiAppUserObjectTransfer::execute()

NumericVector<Real> & solution = _multi_app->appTransferVector(i, _to_var_name);

MeshBase * mesh = NULL;
MooseMesh * mesh = NULL;

if (_displaced_target_mesh && _multi_app->appProblemBase(i).getDisplacedProblem())
mesh = &_multi_app->appProblemBase(i).getDisplacedProblem()->mesh();
else
mesh = &_multi_app->appProblemBase(i).mesh();

_blk_ids.clear();
_bnd_ids.clear();
if (isParamValid("block"))
{
mesh = &_multi_app->appProblemBase(i).getDisplacedProblem()->mesh().getMesh();
const std::vector<SubdomainName> & blocks =
getParam<std::vector<SubdomainName>>("block");
std::vector<SubdomainID> ids = mesh->getSubdomainIDs(blocks);
_blk_ids.insert(ids.begin(), ids.end());
}
else if (isParamValid("boundary"))
{
const std::vector<BoundaryName> & boundary_names =
getParam<std::vector<BoundaryName>>("boundary");
std::vector<BoundaryID> ids = mesh->getBoundaryIDs(boundary_names, true);
_bnd_ids.insert(ids.begin(), ids.end());
}
else
mesh = &_multi_app->appProblemBase(i).mesh().getMesh();

auto & fe_type = to_sys->variable_type(var_num);
bool is_constant = fe_type.order == CONSTANT;
Expand All @@ -121,8 +145,14 @@ MultiAppUserObjectTransfer::execute()

if (is_nodal)
{
for (auto & node : mesh->local_node_ptr_range())
for (auto & node : mesh->getMesh().local_node_ptr_range())
{
if (blockRestricted() && !hasBlocks(mesh, node))
continue;

if (boundaryRestricted() && !isBoundaryNode(mesh, node))
continue;

if (node->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this node
{
// The zero only works for LAGRANGE!
Expand All @@ -139,8 +169,15 @@ MultiAppUserObjectTransfer::execute()
else // Elemental
{
std::vector<Point> points;
for (auto & elem : as_range(mesh->local_elements_begin(), mesh->local_elements_end()))
for (auto & elem : as_range(mesh->getMesh().local_elements_begin(),
mesh->getMesh().local_elements_end()))
{
if (blockRestricted() && !hasBlocks(elem))
continue;

if (boundaryRestricted() && !isBoundaryElem(mesh, elem))
continue;

// Skip this element if the variable has no dofs at it.
if (elem->n_dofs(sys_num, var_num) < 1)
continue;
Expand Down Expand Up @@ -168,7 +205,6 @@ MultiAppUserObjectTransfer::execute()
unsigned int offset = 0;
for (auto & point : points) // If this variable has dofs at this elem
{
// The zero only works for LAGRANGE!
dof_id_type dof = elem->dof_number(sys_num, var_num, offset++);

swapper.forceSwap();
Expand Down Expand Up @@ -211,12 +247,28 @@ MultiAppUserObjectTransfer::execute()
// Create a serialized version of the solution vector
NumericVector<Number> * to_solution = to_sys.solution.get();

MeshBase * to_mesh = NULL;
MooseMesh * to_mesh = NULL;

if (_displaced_target_mesh && to_problem.getDisplacedProblem())
to_mesh = &to_problem.getDisplacedProblem()->mesh().getMesh();
to_mesh = &to_problem.getDisplacedProblem()->mesh();
else
to_mesh = &to_problem.mesh().getMesh();
to_mesh = &to_problem.mesh();

_blk_ids.clear();
_bnd_ids.clear();
if (isParamValid("block"))
{
const std::vector<SubdomainName> & blocks = getParam<std::vector<SubdomainName>>("block");
std::vector<SubdomainID> ids = to_mesh->getSubdomainIDs(blocks);
_blk_ids.insert(ids.begin(), ids.end());
}
else if (isParamValid("boundary"))
{
const std::vector<BoundaryName> & boundary_names =
getParam<std::vector<BoundaryName>>("boundary");
std::vector<BoundaryID> ids = to_mesh->getBoundaryIDs(boundary_names, true);
_bnd_ids.insert(ids.begin(), ids.end());
}

auto & fe_type = to_sys.variable_type(to_var_num);
bool is_constant = fe_type.order == CONSTANT;
Expand All @@ -231,8 +283,14 @@ MultiAppUserObjectTransfer::execute()
// boxes
if (is_nodal)
{
for (auto & node : to_mesh->node_ptr_range())
for (auto & node : to_mesh->getMesh().node_ptr_range())
{
if (blockRestricted() && !hasBlocks(to_mesh, node))
continue;

if (boundaryRestricted() && !isBoundaryNode(to_mesh, node))
continue;

if (node->n_dofs(to_sys_num, to_var_num) > 0)
{
unsigned int node_found_in_sub_app = 0;
Expand Down Expand Up @@ -267,8 +325,15 @@ MultiAppUserObjectTransfer::execute()
else // elemental
{
std::vector<Point> points;
for (auto & elem : as_range(to_mesh->elements_begin(), to_mesh->elements_end()))
for (auto & elem :
as_range(to_mesh->getMesh().elements_begin(), to_mesh->getMesh().elements_end()))
{
if (blockRestricted() && !hasBlocks(elem))
continue;

if (boundaryRestricted() && !isBoundaryElem(to_mesh, elem))
continue;

// Skip this element if the variable has no dofs at it.
if (elem->n_dofs(to_sys_num, to_var_num) < 1)
continue;
Expand Down Expand Up @@ -337,8 +402,14 @@ MultiAppUserObjectTransfer::execute()

if (is_nodal)
{
for (auto & node : to_mesh->node_ptr_range())
for (auto & node : to_mesh->getMesh().node_ptr_range())
{
if (blockRestricted() && !hasBlocks(to_mesh, node))
continue;

if (boundaryRestricted() && !isBoundaryNode(to_mesh, node))
continue;

if (node->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this node
{
// See if this node falls in this bounding box
Expand Down Expand Up @@ -367,8 +438,15 @@ MultiAppUserObjectTransfer::execute()
else // Elemental
{
std::vector<Point> points;
for (auto & elem : as_range(to_mesh->elements_begin(), to_mesh->elements_end()))
for (auto & elem :
as_range(to_mesh->getMesh().elements_begin(), to_mesh->getMesh().elements_end()))
{
if (blockRestricted() && !hasBlocks(elem))
continue;

if (boundaryRestricted() && !isBoundaryElem(to_mesh, elem))
continue;

// Skip this element if the variable has no dofs at it.
if (elem->n_dofs(to_sys_num, to_var_num) < 1)
continue;
Expand Down Expand Up @@ -431,3 +509,52 @@ MultiAppUserObjectTransfer::execute()

postExecute();
}

bool
MultiAppUserObjectTransfer::blockRestricted() const
{
return !_blk_ids.empty();
}

bool
MultiAppUserObjectTransfer::boundaryRestricted() const
{
return !_bnd_ids.empty();
}

bool
MultiAppUserObjectTransfer::hasBlocks(const Elem * elem) const
{
return _blk_ids.find(elem->subdomain_id()) != _blk_ids.end();
}

bool
MultiAppUserObjectTransfer::hasBlocks(const MooseMesh * mesh, const Node * node) const
{
const std::set<SubdomainID> & node_blk_ids = mesh->getNodeBlockIds(*node);
std::set<SubdomainID> u;
std::set_intersection(_blk_ids.begin(),
_blk_ids.end(),
node_blk_ids.begin(),
node_blk_ids.end(),
std::inserter(u, u.begin()));
return !u.empty();
}

bool
MultiAppUserObjectTransfer::isBoundaryNode(const MooseMesh * mesh, const Node * node) const
{
for (auto & bid : _bnd_ids)
if (mesh->isBoundaryNode(node->id(), bid))
return true;
return false;
}

bool
MultiAppUserObjectTransfer::isBoundaryElem(const MooseMesh * mesh, const Elem * elem) const
{
for (auto & bid : _bnd_ids)
if (mesh->isBoundaryElem(elem->id(), bid))
return true;
return false;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 9a4ba83

Please sign in to comment.