diff --git a/include/reduced_basis/rb_parameters.h b/include/reduced_basis/rb_parameters.h index 778e49d5d79..2f95fd19e52 100644 --- a/include/reduced_basis/rb_parameters.h +++ b/include/reduced_basis/rb_parameters.h @@ -44,11 +44,17 @@ class RBParameters { public: + /** + * Constructor. Initializes the _n_steps parameter to 1 for + * backwards compatibility, but the set_n_steps() function can + * always be called later to update this value. + */ + RBParameters(); + /** * The special functions can be defaulted for this class, as it * does not manage any memory itself. */ - RBParameters () = default; RBParameters (RBParameters &&) = default; RBParameters (const RBParameters &) = default; RBParameters & operator= (const RBParameters &) = default; @@ -257,6 +263,16 @@ class RBParameters */ unsigned int n_parameters() const; + /** + * Set the number of steps this RBParameters object is intended to + * represent, in the case that there are no actual parameters stored + * on it. Note: this value will only be used in the no-parameters + * case; if there are actual parameters specified in this class, the + * number set via this API is ignored. All parameters stored within + * the RBParameters object must have n_steps() steps. + */ + void set_n_steps(unsigned int n_steps); + /** * Returns the number of steps stored for all parameters. For * simplicity, we require all parameters to store the same number of @@ -352,6 +368,14 @@ class RBParameters std::size_t index, Real value); + /** + * The number of steps represented by this RBParameters object, in + * the case where there are no parameters actually stored on it. If + * there are parameters stored on this RBParameters object, then the + * n_steps() API returns that number of steps instead. + */ + unsigned int _n_steps; + /** * The map that stores the actual parameter vectors. Each vector is * indexed by a name. diff --git a/src/reduced_basis/rb_parameters.C b/src/reduced_basis/rb_parameters.C index a58c7aa830c..ce3345ff6ed 100644 --- a/src/reduced_basis/rb_parameters.C +++ b/src/reduced_basis/rb_parameters.C @@ -27,6 +27,11 @@ namespace libMesh { +RBParameters::RBParameters() : + _n_steps(1) +{ +} + RBParameters::RBParameters(const std::map & parameter_map) { // Backwards compatible support for constructing an RBParameters @@ -38,6 +43,7 @@ RBParameters::RBParameters(const std::map & parameter_map) void RBParameters::clear() { + _n_steps = 1; _parameters.clear(); _extra_parameters.clear(); } @@ -159,11 +165,16 @@ unsigned int RBParameters::n_parameters() const return cast_int(_parameters.size()); } +void RBParameters::set_n_steps(unsigned int n_steps) +{ + _n_steps = n_steps; +} + unsigned int RBParameters::n_steps() const { // Quick return if there are no parameters if (_parameters.empty()) - return 0; + return _n_steps; // If _parameters is not empty, we can check the number of steps in the first param auto size_first = _parameters.begin()->second.size(); diff --git a/src/reduced_basis/rb_theta.C b/src/reduced_basis/rb_theta.C index 02e69c37bd1..09aaedfd805 100644 --- a/src/reduced_basis/rb_theta.C +++ b/src/reduced_basis/rb_theta.C @@ -25,14 +25,37 @@ namespace libMesh { -Number RBTheta::evaluate(const RBParameters &) { return 1.; } +Number RBTheta::evaluate(const RBParameters & mu) +{ + // The RBTheta::evaluate() API is not general enough to handle the + // multi-step RBParameters case, and you must therefore call + // RBTheta::evaluate_vec() instead. + libmesh_error_msg_if(mu.n_steps() > 1, + "You should only call the evaluate_vec() API when using multi-step RBParameters objects."); + + return 1.; +} std::vector RBTheta::evaluate_vec(const std::vector & mus) { - std::vector result(mus.size()); - for (auto i : index_range(mus)) - result[i] = evaluate(mus[i]); + // Eventual return value + std::vector result; + + for (const auto & mu : mus) + { + // Backwards-compatible behavior: for single-step RBParameters objects, we fall back on + // calling the scalar evaluate() function for this RBTheta object, which may have been + // overridden by the user. + if (mu.n_steps() == 1) + result.push_back( this->evaluate(mu) ); + else + { + // For multistep RBParameters objects, all we can do is return + // mu.n_steps() copies of 1 here at the base class level. + result.insert(result.end(), /*count=*/mu.n_steps(), /*val=*/1.); + } + } return result; } diff --git a/tests/utils/rb_parameters_test.C b/tests/utils/rb_parameters_test.C index 73b3041e9cf..275185f9380 100644 --- a/tests/utils/rb_parameters_test.C +++ b/tests/utils/rb_parameters_test.C @@ -14,6 +14,7 @@ public: CPPUNIT_TEST( testOldConstructor ); CPPUNIT_TEST( testIterators ); CPPUNIT_TEST( testAppend ); + CPPUNIT_TEST( testNSteps ); CPPUNIT_TEST_SUITE_END(); public: @@ -117,6 +118,25 @@ public: for (int i=0; i<3; ++i) CPPUNIT_ASSERT_EQUAL(params1.get_step_value("b", i), Real(i+3)); } + + void testNSteps() + { + LOG_UNIT_TEST; + + // A default-constructed RBparameters object has 1 step by definition + RBParameters params; + CPPUNIT_ASSERT_EQUAL(params.n_steps(), static_cast(1)); + + // Set the number of steps to use in the no-parameters case + params.set_n_steps(10); + CPPUNIT_ASSERT_EQUAL(params.n_steps(), static_cast(10)); + + // Define multiple steps for a single parameter. Now we no longer + // use the set_n_steps() value, since we have actual steps. + params.push_back_value("a", 1.); + params.push_back_value("a", 2.); + CPPUNIT_ASSERT_EQUAL(params.n_steps(), static_cast(2)); + } }; CPPUNIT_TEST_SUITE_REGISTRATION ( RBParametersTest );