Skip to content

Commit

Permalink
Implement variable check for some boundary restricted objects
Browse files Browse the repository at this point in the history
Makes sure that variable dependencies have degrees of freedom on
all nodes along the boundaries of a boundary restricted object

Closes idaholab#9734
  • Loading branch information
lindsayad committed May 17, 2022
1 parent dc704a7 commit 20700d0
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 16 deletions.
5 changes: 4 additions & 1 deletion framework/include/interfaces/BoundaryRestrictable.h
Expand Up @@ -204,10 +204,13 @@ class BoundaryRestrictable
/// Whether or not this object is restricted to nodesets
bool _bnd_nodal;

/// The moose object that this is an interface for
const MooseObject & _moose_object;

/**
* An initialization routine needed for dual constructors
*/
void initializeBoundaryRestrictable(const MooseObject * moose_object);
void initializeBoundaryRestrictable();

protected:
/**
Expand Down
39 changes: 39 additions & 0 deletions framework/include/loops/BoundaryNodeIntegrityCheckThread.h
@@ -0,0 +1,39 @@
//* 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

// MOOSE includes
#include "MooseMesh.h"
#include "ThreadedNodeLoop.h"
#include "TheWarehouse.h"

class AuxiliarySystem;

class BoundaryNodeIntegrityCheckThread
: public ThreadedNodeLoop<ConstBndNodeRange, ConstBndNodeRange::const_iterator>
{
public:
BoundaryNodeIntegrityCheckThread(FEProblemBase & fe_problem, const TheWarehouse::Query & query);

// Splitting Constructor
BoundaryNodeIntegrityCheckThread(BoundaryNodeIntegrityCheckThread & x, Threads::split split);

virtual void onNode(ConstBndNodeRange::const_iterator & node_it) override;

void join(const BoundaryNodeIntegrityCheckThread & /*y*/);

protected:
/// The auxiliary system to whom we'll delegate the boundary variable dependency integrity check
const AuxiliarySystem & _aux_sys;

/// A warehouse query that we will use to obtain user objects for boundary variable dependency
/// integrity checks
const TheWarehouse::Query & _query;
};
2 changes: 2 additions & 0 deletions framework/include/systems/AuxiliarySystem.h
Expand Up @@ -153,6 +153,8 @@ class AuxiliarySystem : public SystemBase, public PerfGraphInterface

void clearScalarVariableCoupleableTags();

void boundaryAuxKernelIntegrityCheck(const Node & nd, BoundaryID bnd_id, THREAD_ID tid) const;

protected:
void computeScalarVars(ExecFlagType type);
void computeNodalVars(ExecFlagType type);
Expand Down
8 changes: 4 additions & 4 deletions framework/include/warehouses/ExecuteMooseObjectWarehouse.h
Expand Up @@ -42,7 +42,7 @@ class ExecuteMooseObjectWarehouse : public MooseObjectWarehouse<T>
* Adds an object to the storage structure.
* @param object A shared pointer to the object being added
*/
virtual void addObject(std::shared_ptr<T> object, THREAD_ID tid = 0, bool recurse = true);
void addObject(std::shared_ptr<T> object, THREAD_ID tid = 0, bool recurse = true) override;
void addObjectMask(std::shared_ptr<T> object,
THREAD_ID tid = 0,
std::uint16_t flag_mask = std::numeric_limits<std::uint16_t>::max());
Expand Down Expand Up @@ -73,16 +73,16 @@ class ExecuteMooseObjectWarehouse : public MooseObjectWarehouse<T>
/**
* Updates the active objects storage.
*/
virtual void updateActive(THREAD_ID tid = 0);
void updateActive(THREAD_ID tid = 0) override;

///@{
/**
* Convenience methods for calling object setup methods.
*
* Limits call to these methods only to objects being executed on linear/nonlinear iterations.
*/
void jacobianSetup(THREAD_ID tid = 0) const;
void residualSetup(THREAD_ID tid = 0) const;
void jacobianSetup(THREAD_ID tid = 0) const override;
void residualSetup(THREAD_ID tid = 0) const override;
void setup(const ExecFlagType & exec_flag, THREAD_ID tid = 0) const;
///@}

Expand Down
9 changes: 9 additions & 0 deletions framework/include/warehouses/MooseObjectWarehouseBase.h
Expand Up @@ -94,6 +94,7 @@ class MooseObjectWarehouseBase
bool hasActiveBlockObjects(SubdomainID id, THREAD_ID tid = 0) const;
bool hasActiveBoundaryObjects(THREAD_ID tid = 0) const;
bool hasActiveBoundaryObjects(BoundaryID id, THREAD_ID tid = 0) const;
bool hasBoundaryObjects(BoundaryID id, THREAD_ID tid = 0) const;
///@}

/**
Expand Down Expand Up @@ -345,6 +346,14 @@ MooseObjectWarehouseBase<T>::getBoundaryObjects(THREAD_ID tid /* = 0*/) const
return _all_boundary_objects[tid];
}

template <typename T>
bool
MooseObjectWarehouseBase<T>::hasBoundaryObjects(BoundaryID id, THREAD_ID tid /* = 0*/) const
{
checkThreadID(tid);
return _all_boundary_objects[tid].find(id) != _all_boundary_objects[tid].end();
}

template <typename T>
const std::vector<std::shared_ptr<T>> &
MooseObjectWarehouseBase<T>::getBoundaryObjects(BoundaryID id, THREAD_ID tid /* = 0*/) const
Expand Down
22 changes: 12 additions & 10 deletions framework/src/interfaces/BoundaryRestrictable.C
Expand Up @@ -44,9 +44,10 @@ BoundaryRestrictable::BoundaryRestrictable(const MooseObject * moose_object, boo
_block_ids(_empty_block_ids),
_bnd_tid(moose_object->isParamValid("_tid") ? moose_object->getParam<THREAD_ID>("_tid") : 0),
_bnd_material_data(_bnd_feproblem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA, _bnd_tid)),
_bnd_nodal(nodal)
_bnd_nodal(nodal),
_moose_object(*moose_object)
{
initializeBoundaryRestrictable(moose_object);
initializeBoundaryRestrictable();
}

// Dual restricted constructor
Expand All @@ -62,16 +63,17 @@ BoundaryRestrictable::BoundaryRestrictable(const MooseObject * moose_object,
_block_ids(block_ids),
_bnd_tid(moose_object->isParamValid("_tid") ? moose_object->getParam<THREAD_ID>("_tid") : 0),
_bnd_material_data(_bnd_feproblem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA, _bnd_tid)),
_bnd_nodal(nodal)
_bnd_nodal(nodal),
_moose_object(*moose_object)
{
initializeBoundaryRestrictable(moose_object);
initializeBoundaryRestrictable();
}

void
BoundaryRestrictable::initializeBoundaryRestrictable(const MooseObject * moose_object)
BoundaryRestrictable::initializeBoundaryRestrictable()
{
// The name and id of the object
const std::string & name = moose_object->getParam<std::string>("_object_name");
const std::string & name = _moose_object.getParam<std::string>("_object_name");

// If the mesh pointer is not defined, but FEProblemBase is, get it from there
if (_bnd_feproblem != NULL && _bnd_mesh == NULL)
Expand All @@ -83,10 +85,10 @@ BoundaryRestrictable::initializeBoundaryRestrictable(const MooseObject * moose_o
"a pointer to the MooseMesh via '_mesh'");

// If the user supplies boundary IDs
if (moose_object->isParamValid("boundary"))
if (_moose_object.isParamValid("boundary"))
{
// Extract the blocks from the input
_boundary_names = moose_object->getParam<std::vector<BoundaryName>>("boundary");
_boundary_names = _moose_object.getParam<std::vector<BoundaryName>>("boundary");

// Get the IDs from the supplied names
_vec_ids = _bnd_mesh->getBoundaryIDs(_boundary_names, true);
Expand All @@ -102,7 +104,7 @@ BoundaryRestrictable::initializeBoundaryRestrictable(const MooseObject * moose_o
// Produce error if the object is not allowed to be both block and boundary restricted
if (!_bnd_dual_restrictable && !_bnd_ids.empty() && !_block_ids.empty())
if (!_block_ids.empty() && _block_ids.find(Moose::ANY_BLOCK_ID) == _block_ids.end())
moose_object->paramError("boundary",
_moose_object.paramError("boundary",
"Attempted to restrict the object '",
name,
"' to a boundary, but the object is already restricted by block(s)");
Expand Down Expand Up @@ -168,7 +170,7 @@ BoundaryRestrictable::initializeBoundaryRestrictable(const MooseObject * moose_o
"error.\n"
"Note: If you are running with adaptivity you should prefer using side sets.";

moose_object->paramError("boundary", msg.str());
_moose_object.paramError("boundary", msg.str());
}
}
}
Expand Down
74 changes: 74 additions & 0 deletions framework/src/loops/BoundaryNodeIntegrityCheckThread.C
@@ -0,0 +1,74 @@
//* 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

// MOOSE includes
#include "BoundaryNodeIntegrityCheckThread.h"
#include "AuxiliarySystem.h"
#include "FEProblem.h"
#include "AuxKernel.h"
#include "NodalUserObject.h"

#include "libmesh/threads.h"
#include "libmesh/node.h"

BoundaryNodeIntegrityCheckThread::BoundaryNodeIntegrityCheckThread(
FEProblemBase & fe_problem, const TheWarehouse::Query & query)
: ThreadedNodeLoop<ConstBndNodeRange, ConstBndNodeRange::const_iterator>(fe_problem),
_aux_sys(fe_problem.getAuxiliarySystem()),
_query(query)
{
}

// Splitting Constructor
BoundaryNodeIntegrityCheckThread::BoundaryNodeIntegrityCheckThread(
BoundaryNodeIntegrityCheckThread & x, Threads::split split)
: ThreadedNodeLoop<ConstBndNodeRange, ConstBndNodeRange::const_iterator>(x, split),
_aux_sys(x._aux_sys),
_query(x._query)
{
}

void
BoundaryNodeIntegrityCheckThread::onNode(ConstBndNodeRange::const_iterator & node_it)
{
const BndNode * const bnode = *node_it;
const auto boundary_id = bnode->_bnd_id;
const Node * const node = bnode->_node;

if (node->processor_id() != _fe_problem.processor_id())
return;

// aux check
_aux_sys.boundaryAuxKernelIntegrityCheck(*node, boundary_id, _tid);

// uo check
std::vector<NodalUserObject *> objs;
_query.clone()
.condition<AttribThread>(_tid)
.condition<AttribInterfaces>(Interfaces::NodalUserObject)
.condition<AttribBoundaries>(boundary_id, true)
.queryInto(objs);
for (const auto & uo : objs)
{
const auto & mv_deps = uo->getMooseVariableDependencies();
for (const auto * const var : mv_deps)
if (!node->n_dofs(var->sys().number(), var->number()))
mooseError("Nodal user object '",
uo->name(),
"' depends on variable '",
var->name(),
"'. However, that variable does not have degrees of freedom on node with id ",
node->id());
}
}

void
BoundaryNodeIntegrityCheckThread::join(const BoundaryNodeIntegrityCheckThread & /*y*/)
{
}
9 changes: 8 additions & 1 deletion framework/src/problems/FEProblemBase.C
Expand Up @@ -99,6 +99,7 @@
#include "ADUtils.h"
#include "Executioner.h"
#include "VariadicTable.h"
#include "BoundaryNodeIntegrityCheckThread.h"

#include "libmesh/exodusII_io.h"
#include "libmesh/quadrature.h"
Expand Down Expand Up @@ -730,8 +731,9 @@ FEProblemBase::initialSetup()
std::set<std::string> depend_objects_aux = _aux->getDependObjects();

// This replaces all prior updateDependObjects calls on the old user object warehouses.
TheWarehouse::Query uo_query = theWarehouse().query().condition<AttribSystem>("UserObject");
std::vector<UserObject *> userobjs;
theWarehouse().query().condition<AttribSystem>("UserObject").queryInto(userobjs);
uo_query.queryInto(userobjs);
groupUserObjects(
theWarehouse(), getAuxiliarySystem(), _app.getExecuteOnEnum(), userobjs, depend_objects_ic);

Expand Down Expand Up @@ -985,6 +987,11 @@ FEProblemBase::initialSetup()
}
}

// check that variables are defined along boundaries before executing user objects and aux kernels
ConstBndNodeRange & bnd_nodes = *mesh().getBoundaryNodeRange();
BoundaryNodeIntegrityCheckThread bnict(*this, uo_query);
Threads::parallel_reduce(bnd_nodes, bnict);

if (!_app.isRecovering())
{
execTransfers(EXEC_INITIAL);
Expand Down
30 changes: 30 additions & 0 deletions framework/src/systems/AuxiliarySystem.C
Expand Up @@ -923,6 +923,36 @@ AuxiliarySystem::computeNodalVarsHelper(
}
}

void
AuxiliarySystem::boundaryAuxKernelIntegrityCheck(const Node & nd,
const BoundaryID bnd_id,
const THREAD_ID tid) const
{
auto check = [&nd, bnd_id, tid](const auto & warehouse)
{
if (!warehouse.hasBoundaryObjects(bnd_id, tid))
return;

const auto & bnd_objects = warehouse.getBoundaryObjects(bnd_id, tid);
for (const auto & bnd_object : bnd_objects)
{
const auto & mv_deps = bnd_object->getMooseVariableDependencies();
for (const auto * const var : mv_deps)
if (!nd.n_dofs(var->sys().number(), var->number()))
mooseError("Boundary restricted aux kernel '",
bnd_object->name(),
"' depends on variable '",
var->name(),
"'. However, that variable does not have degrees of freedom on node with id ",
nd.id());
}
};

check(_nodal_aux_storage);
check(_nodal_vec_aux_storage);
check(_nodal_array_aux_storage);
}

template void AuxiliarySystem::computeElementalVarsHelper<AuxKernel>(
const MooseObjectWarehouse<AuxKernel> &,
const std::vector<std::vector<MooseVariableFEBase *>> &);
Expand Down

0 comments on commit 20700d0

Please sign in to comment.