Skip to content

Commit

Permalink
Merge pull request #27959 from kyleeswanson/PR_parsedxyz
Browse files Browse the repository at this point in the history
Adding functor input capability to ParsedAux
  • Loading branch information
GiudGiud authored Jun 27, 2024
2 parents c5bf9ec + b8ac89d commit 1b53c96
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 11 deletions.
2 changes: 2 additions & 0 deletions framework/doc/content/source/auxkernels/ParsedAux.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The parsed expression may contain:

- variables (`coupled_variables` parameter)

- functors (`functor_names` or `functor_symbols` parameter)

- coordinates in space and time (`use_xyzt` parameter)

- constants (`constant_names` for their name in the expression and `constant_expressions` for their values)
Expand Down
57 changes: 57 additions & 0 deletions framework/include/auxkernels/ParsedAux.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ class ParsedAux : public AuxKernel, public FunctionParserUtils<false>
protected:
virtual Real computeValue() override;

/// Function to validate the symbols in _functor_symbols
void validateFunctorSymbols();

/// Function to validate the names in _functor_names
void validateFunctorNames();

/**
* Function to ensure vector entries (names) do not overlap with xyzt or coupled variable names.
* @param names_vec Vector containing names to compare to xyzt and coupled variables names.
* @param param_name Name of the parameter corresponding to names_vec. This will be the paremeter
* errored on, if applicable.
*/
template <typename T>
void validateGenericVectorNames(const std::vector<T> & names_vec, const std::string & param_name);

/// function expression
std::string _function;

Expand All @@ -35,8 +50,50 @@ class ParsedAux : public AuxKernel, public FunctionParserUtils<false>
/// import coordinates and time
const bool _use_xyzt;

/// coordinate and time variable names
const std::vector<std::string> _xyzt;

/// function parser object for the resudual and on-diagonal Jacobian
SymFunctionPtr _func_F;

usingFunctionParserUtilsMembers(false);

/// Functors to use in the parsed expression
const std::vector<MooseFunctorName> & _functor_names;

/// Number of functors
const unsigned int _n_functors;

/// Symbolic name to use for each functor
const std::vector<std::string> _functor_symbols;

/// Vector of pointers to functors
std::vector<const Moose::Functor<Real> *> _functors;

/// Vector of coupled variable names
std::vector<std::string> _coupled_variable_names;
};

template <typename T>
void
ParsedAux::validateGenericVectorNames(const std::vector<T> & names_vec,
const std::string & param_name)
{
for (const auto & name : names_vec)
{
// Make sure symbol is not x, y, z, or t
if (_use_xyzt && (std::find(_xyzt.begin(), _xyzt.end(), name) != _xyzt.end()))
paramError(
param_name,
"x, y, z, and t cannot be used in '" + param_name + "' when use_xyzt=true." +
(param_name == "functor_names" ? " Use 'functor_symbols' to disambiguate." : ""));
// Make sure symbol is not a coupled variable name
if (_coupled_variable_names.size() &&
(std::find(_coupled_variable_names.begin(), _coupled_variable_names.end(), name) !=
_coupled_variable_names.end()))
paramError(
param_name,
"Values in '" + param_name + "' cannot overlap with coupled variable names." +
(param_name == "functor_names" ? " Use 'functor_symbols' to disambiguate." : ""));
}
}
79 changes: 68 additions & 11 deletions framework/src/auxkernels/ParsedAux.C
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "ParsedAux.h"
#include "MooseApp.h"

registerMooseObject("MooseApp", ParsedAux);

Expand Down Expand Up @@ -38,6 +37,13 @@ ParsedAux::validParams()
"constant_expressions",
{},
"Vector of values for the constants in constant_names (can be an FParser expression)");
params.addParam<std::vector<MooseFunctorName>>(
"functor_names", {}, "Functors to use in the parsed expression");
params.addParam<std::vector<std::string>>(
"functor_symbols",
{},
"Symbolic name to use for each functor in 'functor_names' in the parsed expression. If not "
"provided, then the actual functor names will be used in the parsed expression.");

return params;
}
Expand All @@ -48,19 +54,41 @@ ParsedAux::ParsedAux(const InputParameters & parameters)
_function(getParam<std::string>("expression")),
_nargs(coupledComponents("coupled_variables")),
_args(coupledValues("coupled_variables")),
_use_xyzt(getParam<bool>("use_xyzt"))
_use_xyzt(getParam<bool>("use_xyzt")),
_xyzt({"x", "y", "z", "t"}),
_functor_names(getParam<std::vector<MooseFunctorName>>("functor_names")),
_n_functors(_functor_names.size()),
_functor_symbols(getParam<std::vector<std::string>>("functor_symbols"))
{

for (const auto i : make_range(_nargs))
_coupled_variable_names.push_back(getFieldVar("coupled_variables", i)->name());

// sanity checks
if (!_functor_symbols.empty() && (_functor_symbols.size() != _n_functors))
paramError("functor_symbols", "functor_symbols must be the same length as functor_names.");

validateFunctorSymbols();
validateFunctorNames();

// build variables argument
std::string variables;

// coupled field variables
for (std::size_t i = 0; i < _nargs; ++i)
variables += (i == 0 ? "" : ",") + getFieldVar("coupled_variables", i)->name();
for (const auto i : index_range(_coupled_variable_names))
variables += (i == 0 ? "" : ",") + _coupled_variable_names[i];

// adding functors to the expression
if (_functor_symbols.size())
for (const auto & symbol : _functor_symbols)
variables += (variables.empty() ? "" : ",") + symbol;
else
for (const auto & name : _functor_names)
variables += (variables.empty() ? "" : ",") + name;

// "system" variables
const std::vector<std::string> xyzt = {"x", "y", "z", "t"};
if (_use_xyzt)
for (auto & v : xyzt)
for (auto & v : _xyzt)
variables += (variables.empty() ? "" : ",") + v;

// base function object
Expand Down Expand Up @@ -98,21 +126,50 @@ ParsedAux::ParsedAux(const InputParameters & parameters)
}

// reserve storage for parameter passing buffer
_func_params.resize(_nargs + (_use_xyzt ? 4 : 0));
_func_params.resize(_nargs + _n_functors + (_use_xyzt ? 4 : 0));

for (const auto & name : _functor_names)
_functors.push_back(&getFunctor<Real>(name));
}

Real
ParsedAux::computeValue()
{
for (std::size_t j = 0; j < _nargs; ++j)
for (const auto j : make_range(_nargs))
_func_params[j] = (*_args[j])[_qp];

const auto & state = determineState();
if (isNodal())
{
const Moose::NodeArg node_arg = {_current_node, Moose::INVALID_BLOCK_ID};
for (const auto i : index_range(_functors))
_func_params[_nargs + i] = (*_functors[i])(node_arg, state);
}
else
{
const Moose::ElemQpArg qp_arg = {_current_elem, _qp, _qrule, _q_point[_qp]};
for (const auto i : index_range(_functors))
_func_params[_nargs + i] = (*_functors[i])(qp_arg, state);
}

if (_use_xyzt)
{
for (std::size_t j = 0; j < LIBMESH_DIM; ++j)
_func_params[_nargs + j] = isNodal() ? (*_current_node)(j) : _q_point[_qp](j);
_func_params[_nargs + 3] = _t;
for (const auto j : make_range(LIBMESH_DIM))
_func_params[_nargs + _n_functors + j] = isNodal() ? (*_current_node)(j) : _q_point[_qp](j);
_func_params[_nargs + _n_functors + 3] = _t;
}

return evaluate(_func_F);
}

void
ParsedAux::validateFunctorSymbols()
{
validateGenericVectorNames(_functor_symbols, "functor_symbols");
}

void
ParsedAux::validateFunctorNames()
{
validateGenericVectorNames(_functor_names, "functor_names");
}
95 changes: 95 additions & 0 deletions test/tests/auxkernels/parsed_aux/parsed_aux_functors_test.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
[Mesh]
type = GeneratedMesh

dim = 2

xmin = 0
xmax = 1

ymin = 0
ymax = 1

nx = 10
ny = 10
[]

[Variables]
[u]
order = FIRST
family = LAGRANGE
[]

[v]
order = FIRST
family = LAGRANGE
[]
[]

[AuxVariables]
[parsed]
order = FIRST
family = LAGRANGE
[]
[]

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

[diff_v]
type = Diffusion
variable = v
[]
[]

[BCs]
[left_u]
type = DirichletBC
variable = u
boundary = top
value = 0
[]

[right_u]
type = DirichletBC
variable = u
boundary = bottom
value = 1
[]

[left_v]
type = DirichletBC
variable = v
boundary = left
value = 0
[]

[right_v]
type = DirichletBC
variable = v
boundary = right
value = 1
[]
[]

[AuxKernels]
[set_parsed]
type = ParsedAux
variable = parsed
functor_names = 'u v'
functor_symbols = 'u v'
expression = '(u-0.5)^3*v'
[]
[]

[Executioner]
type = Steady

solve_type = 'PJFNK'
[]

[Outputs]
exodus = true
[]
54 changes: 54 additions & 0 deletions test/tests/auxkernels/parsed_aux/tests
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,58 @@
issues = '#15877'
requirement = "The parsed expression AuxKernel in The system shall expose quadrature/nodal point coordinates and time if requested by the user."
[../]
[./functor_test]
type = 'Exodiff'
input = 'parsed_aux_functors_test.i'
exodiff = 'parsed_aux_functors_test_out.e'
scale_refine = 3
issues = '#21244'
requirement = "The system shall be capable of computing values from a functor."
[../]
[errors]
issues = '#21244'
requirement = 'The system shall report an error if'
[functor_symbol_length]
type = RunException
input = 'parsed_aux_functors_test.i'
cli_args = "AuxKernels/set_parsed/functor_names='u v' AuxKernels/set_parsed/functor_symbols='u v w'"
expect_err = "functor_symbols must be the same length as functor_names."
detail = 'functor symbols parameter does not have the same length as functor names parameter'
[../]
[invalid_functor_symbol]
type = RunException
input = 'parsed_aux_functors_test.i'
cli_args = "AuxKernels/set_parsed/functor_names='u v' AuxKernels/set_parsed/functor_symbols='x v' AuxKernels/set_parsed/use_xyzt=true"
expect_err = "x, y, z, and t cannot be used in 'functor_symbols' when use_xyzt=true."
detail = "functor symbols parameter contains 'x', 'y', 'z', or 't' when coordinates and time parameters are already in use"
[../]
[functor_symbol_variable_name_overlap]
type = RunException
input = 'parsed_aux_functors_test.i'
cli_args = "AuxKernels/set_parsed/functor_symbols='u v' AuxKernels/set_parsed/coupled_variables='u v'"
expect_err = "Values in 'functor_symbols' cannot overlap with coupled variable names."
detail = "functor symbols cannot overlap with coupled variable names"
[../]
[invalid_functor_name]
type = RunException
input = 'parsed_aux_functors_test.i'
cli_args = "AuxKernels/set_parsed/functor_names='x v' AuxKernels/set_parsed/functor_symbols='' AuxKernels/set_parsed/use_xyzt=true"
expect_err = "x, y, z, and t cannot be used in 'functor_names' when use_xyzt=true. Use 'functor_symbols' to disambiguate."
detail = "functor names parameter contains 'x', 'y', 'z', or 't' when coordinates and time parameters are already in use"
[../]
[functor_name_variable_name_overlap]
type = RunException
input = 'parsed_aux_functors_test.i'
cli_args = "AuxKernels/set_parsed/functor_names='u v' AuxKernels/set_parsed/coupled_variables='u v' AuxKernels/set_parsed/functor_symbols=''"
expect_err = "Values in 'functor_names' cannot overlap with coupled variable names. Use 'functor_symbols' to disambiguate."
detail = "functor names cannot overlap with coupled variable names"
[../]
[expression]
type = RunException
input = 'parsed_aux_functors_test.i'
cli_args = "AuxKernels/set_parsed/expression='l'"
expect_err = "Invalid function"
detail = "an invalid function is provided."
[../]
[]
[]

0 comments on commit 1b53c96

Please sign in to comment.