Skip to content

Commit

Permalink
Restrict use of writableCoupledValue (idaholab#22563)
Browse files Browse the repository at this point in the history
  • Loading branch information
dschwen committed Feb 22, 2023
1 parent db9e5cb commit 46fce34
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
10 changes: 6 additions & 4 deletions framework/include/interfaces/Coupleable.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,9 @@ class Coupleable
std::vector<const ArrayVariableValue *> coupledArrayValues(const std::string & var_name) const;

/**
* Returns a *writable* reference to a coupled variable. Note: you
* should not have to use this very often (use coupledValue()
* instead) but there are situations, such as writing to multiple
* AuxVariables from a single AuxKernel, where it is required.
* Returns a *writable* reference to a coupled variable for writing to multiple
* AuxVariables from a single AuxKernel or a UserObject. Only one object can obtain
* a writable reference in a simulation.
* @param var_name Name of coupled variable
* @param comp Component number for vector of coupled variables
* @return Reference to a VariableValue for the coupled variable
Expand Down Expand Up @@ -1621,6 +1620,9 @@ class Coupleable
/// vector tag names for which we need to request older solution states from the system
const std::set<std::string> _older_state_tags = {Moose::OLD_SOLUTION_TAG,
Moose::OLDER_SOLUTION_TAG};

/// keep a set of allocated writable variable references to make sure only one object can obtain them per thread
std::vector<std::set<std::string>> _writable_copled_variables;
};

template <typename T>
Expand Down
54 changes: 53 additions & 1 deletion framework/src/interfaces/Coupleable.C
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include "MooseObject.h"
#include "SystemBase.h"

#include "AuxKernel.h"
#include "ElementUserObject.h"
#include "NodalUserObject.h"

Coupleable::Coupleable(const MooseObject * moose_object, bool nodal, bool is_fv)
: _c_parameters(moose_object->parameters()),
_c_name(_c_parameters.get<std::string>("_object_name")),
Expand Down Expand Up @@ -49,9 +53,11 @@ Coupleable::Coupleable(const MooseObject * moose_object, bool nodal, bool is_fv)
: false),
_coupleable_max_qps(Moose::constMaxQpsPerElem),
_is_fv(is_fv),
_obj(moose_object)
_obj(moose_object),
_writable_copled_variables(libMesh::n_threads())
{
SubProblem & problem = *_c_parameters.getCheckedPointerParam<SubProblem *>("_subproblem");
_obj->getMooseApp().registerInterfaceObject(*this);

unsigned int optional_var_index_counter = 0;

Expand Down Expand Up @@ -828,6 +834,52 @@ Coupleable::coupledArrayValues(const std::string & var_name) const
VariableValue &
Coupleable::writableCoupledValue(const std::string & var_name, unsigned int comp)
{
// make sure only one object can access a variable

for (const auto & ci : _obj->getMooseApp().getInterfaceObjects<Coupleable>())
if (ci != this && ci->_writable_copled_variables[_c_tid].count(var_name))
mooseError("'",
ci->_obj->name(),
"' already obtained a writable reference to '",
var_name,
"'. Only one object can obtain such a reference per variable in a simulation.");

// check that the variable type (elemental/nodal) is compatible with the object type
const auto * aux = dynamic_cast<const AuxKernel *>(this);
const auto * euo = dynamic_cast<const ElementUserObject *>(this);
const auto * nuo = dynamic_cast<const NodalUserObject *>(this);

if (!aux && !euo && !nuo)
mooseError("writableCoupledvalue() can only be called from AuxKernels, ElementUserObjects, or "
"NodalUserObjects. '",
_obj->name(),
"' is neither of those.");

const auto * var = getVar(var_name, comp);
if (!var)
mooseError(
"Unable to create a writable reference to '", var_name, "', is it a constant expression?");

if (aux && aux->isNodal() != var->isNodal())
mooseError("The AuxKernel '",
_obj->name(),
"' and the variable '",
var_name,
"' must both either be nodal or elemental.");
if (euo && var->isNodal())
mooseError("The ElementUserObject '",
_obj->name(),
"' cannot obtain a writable reference to the nodal variable '",
var_name,
"'.");
if (nuo && !var->isNodal())
mooseError("The NodalUserObject '",
_obj->name(),
"' cannot obtain a writable reference to the elemental variable '",
var_name,
"'.");

_writable_copled_variables[_c_tid].insert(var_name);
return const_cast<VariableValue &>(coupledValue(var_name, comp));
}

Expand Down

0 comments on commit 46fce34

Please sign in to comment.