diff --git a/framework/contrib/hit/parse.cc b/framework/contrib/hit/parse.cc index 2cb726b20659..1ccde40cc4b7 100644 --- a/framework/contrib/hit/parse.cc +++ b/framework/contrib/hit/parse.cc @@ -218,19 +218,29 @@ Node::getNodeView() } const std::string & -Node::filename() +Node::filename() const { return _hnv.node_pool()->stream_name(); } +std::string +Node::fileLocation(const bool with_column /* = true */) const +{ + std::stringstream ss; + ss << filename() << ":" << line(); + if (with_column) + ss << "." << column(); + return ss.str(); +} + int -Node::line() +Node::line() const { return _hnv.line(); } int -Node::column() +Node::column() const { return _hnv.column(); } @@ -253,7 +263,7 @@ Node::floatVal() valthrow(); } std::string -Node::strVal() +Node::strVal() const { valthrow(); } @@ -280,7 +290,7 @@ Node::vecStrVal() #undef valthrow NodeType -Node::type() +Node::type() const { if (_hnv.type() == wasp::BLANK_LINE) return NodeType::Blank; @@ -319,22 +329,16 @@ Node::children(NodeType t) return nodes; } -Node * -Node::parent() -{ - return _parent; -} - Node * Node::root() { - if (_parent == nullptr) + if (isRoot()) return this; return _parent->root(); } std::string -Node::path() +Node::path() const { if (!_override_path.empty()) return _override_path; @@ -343,7 +347,7 @@ Node::path() } std::string -Node::fullpath() +Node::fullpath() const { if (_parent == nullptr) return ""; @@ -425,9 +429,7 @@ Comment::render(int indent, const std::string & indent_text, int /*maxlen*/) } Node * -Comment::clone(bool - absolute_path -) +Comment::clone(bool absolute_path) { auto n = new Comment(_dhi, _hnv); n->setInline(_isinline); @@ -468,7 +470,7 @@ Section::clearLegacyMarkers() } std::string -Section::path() +Section::path() const { return Node::path(); } @@ -531,7 +533,7 @@ Field::Field(std::shared_ptr dhi, wasp::HITNodeView } std::string -Field::path() +Field::path() const { return Node::path(); } @@ -740,7 +742,7 @@ Field::setVal(const std::string & value, Kind kind) } std::string -Field::val() +Field::val() const { return extractValue(_hnv.data()); } @@ -887,7 +889,7 @@ Field::floatVal() } std::string -Field::strVal() +Field::strVal() const { const auto value = val(); std::string s = value; diff --git a/framework/contrib/hit/parse.h b/framework/contrib/hit/parse.h index 103ccb699f52..c1e4c14558a0 100644 --- a/framework/contrib/hit/parse.h +++ b/framework/contrib/hit/parse.h @@ -76,7 +76,7 @@ enum class NodeType Comment, /// Represents comments that are not directly part of the actual hit document. Field, /// Represents field-value pairs (i.e. paramname=val). Blank, /// Represents a blank line - Other, /// Represents any other type of node + Other, /// Represents any other type of node }; /// Traversal order for walkers. Determines if the walker on a node is executed before or @@ -176,23 +176,26 @@ class Node wasp::HITNodeView getNodeView(); /// type returns the type of the node (e.g. one of Field, Section, Comment, etc.) - NodeType type(); + NodeType type() const; /// path returns this node's local/direct contribution its full hit path. For section nodes, this /// is the section name, for field nodes, this is the field/parameter name, for other nodes this /// is empty. if setOverridePath (wasp) has been called for this Node, then that set path is /// returned. - virtual std::string path(); + virtual std::string path() const; /// fullpath returns the full hit path to this node (including all parent sections /// recursively) starting from the tree's root node. - std::string fullpath(); + std::string fullpath() const; /// line returns the line number of the original parsed input (file) that contained the start of /// the content that this node was built from. - int line(); + int line() const; /// column returns the starting column number of this node in the original parsed input - int column(); + int column() const; /// name returns the file name of the original parsed input (file) that contained the start of /// the content that this node was built from. - const std::string & filename(); + const std::string & filename() const; + /// returns the file location in the form :. where + /// the column is optional defined by \p with_column + std::string fileLocation(const bool with_column = true) const; /// the following functions return the stored value of the node (if any exists) of the type /// indicated in the function name. If the node holds a value of a different type or doesn't hold @@ -203,7 +206,7 @@ class Node /// strVal is special in that it only throws an exception if the node doesn't hold a value at /// all. All nodes with a value hold data that was originally represented as a string in the /// parsed input - so this returns that raw string. - virtual std::string strVal(); + virtual std::string strVal() const; /// the vec-prefixed value retrieval functions assume the node holds a string-typed value holding /// whitespace delimited entries of the element type indicated in the function name. virtual std::vector vecFloatVal(); @@ -222,9 +225,14 @@ class Node /// children returns a list of this node's children of the given type t. std::vector children(NodeType t = NodeType::All); /// parent returns a pointer to this node's parent node or nullptr if this node has no parent. - Node * parent(); + ///@{ + Node * parent() { return _parent; } + const Node * parent() const { return _parent; } + ///@} /// root returns the root node for the gepot tree this node resides in. Node * root(); + /// Whether or not this is the root + bool isRoot() const { return parent() == nullptr; } /// clone returns a complete (deep) copy of this node. The caller will be responsible for /// managing the memory/deallocation of the returned clone node. virtual Node * clone(bool absolute_path = false) = 0; @@ -285,7 +293,6 @@ class Node wasp::HITNodeView _hnv; private: - template T paramInner(Node *) { @@ -442,7 +449,7 @@ class Section : public Node void clearLegacyMarkers(); /// path returns the hit path located in the section's header i.e. the section's name. - virtual std::string path() override; + virtual std::string path() const override; virtual std::string render(int indent = 0, const std::string & indent_text = default_indent, int maxlen = 0) override; @@ -472,7 +479,7 @@ class Field : public Node Field(std::shared_ptr dhi, wasp::HITNodeView hnv); /// path returns the hit Field name (i.e. content before the "=") - virtual std::string path() override; + virtual std::string path() const override; virtual std::string render(int indent = 0, const std::string & indent_text = default_indent, int maxlen = 0) override; @@ -490,7 +497,7 @@ class Field : public Node void setVal(const std::string & value, Kind kind = Kind::None); /// val returns the raw text of the field's value as it was read from the hit input. This is /// the value set by setVal. - std::string val(); + std::string val() const; virtual std::vector vecFloatVal() override; virtual std::vector vecBoolVal() override; @@ -499,7 +506,7 @@ class Field : public Node virtual bool boolVal() override; virtual int64_t intVal() override; virtual double floatVal() override; - virtual std::string strVal() override; + virtual std::string strVal() const override; private: Kind _kind; diff --git a/framework/doc/content/source/interfaces/DataFileInterface.md b/framework/doc/content/source/interfaces/DataFileInterface.md index 4030c637f9d8..c4e431e3c9da 100644 --- a/framework/doc/content/source/interfaces/DataFileInterface.md +++ b/framework/doc/content/source/interfaces/DataFileInterface.md @@ -13,9 +13,10 @@ getDataFileNameByName | Finds a data file given a relative path Files located in `moose/framework/data`, the `moose/modules/*/data`, or `/data` directories can be retrieved using the `getDataFileName(const std::string & param)` function, where `param` is an input parameter of type -`FileName` +`DataFileName` -`getDataFileName` will search (in this order) +If the provided path is absolute, no searching will take place and the absolute +path will be used. Otherwise, `getDataFileName` will search (in this order) - relative to the input file - relative to the running binary in the shared directory (assuming the application is installed) diff --git a/framework/include/actions/Action.h b/framework/include/actions/Action.h index de6740bd838a..4b9057cfbd82 100644 --- a/framework/include/actions/Action.h +++ b/framework/include/actions/Action.h @@ -120,6 +120,34 @@ class Action : public MooseBase, */ virtual void act() = 0; + /** + * Associates the object's parameters \p params with the input location from this + * Action's parameter with the name \p param_name, if one exists. + * + * For example, you have a parameter in this action of type bool with name "add_mesh". + * You then add an action within this action that creates a mesh if this param is + * true. If you call associateWithParameter("add_mesh", action_params) where + * action_params are the parameters for the action, we then associate that action + * with the "add_mesh" parameter. Therefore, the resulting created mesh will also + * be associated with the "add_mesh" param and any errors that are non-parameter errors + * (i.e., mooseError/mooseWarning) will have the line context of the "add_mesh" + * parameter in this action. The same goes for any errors that are produce within + * the created action. + */ + void associateWithParameter(const std::string & param_name, InputParameters & params) const; + + /** + * The same as associateWithParameter() without \p from_params, but instead + * allows you to associate this with another object's parameters instead of the + * parameters from this action. + * + * An example here is when you want to associate the creation of an action with + * an arugment from the aplication. + */ + void associateWithParameter(const InputParameters & from_params, + const std::string & param_name, + InputParameters & params) const; + // The registered syntax for this block if any std::string _registered_identifier; diff --git a/framework/include/actions/ActionFactory.h b/framework/include/actions/ActionFactory.h index 882ff59325b2..d11fa985b4f3 100644 --- a/framework/include/actions/ActionFactory.h +++ b/framework/include/actions/ActionFactory.h @@ -100,6 +100,14 @@ class ActionFactory */ bool isRegisteredTask(const std::string & task) const { return _tasks.count(task); } + /** + * @return The InputParameters for the object that is currently being constructed, + * if any. + * + * Can be used to ensure that all Actions are created using the ActionFactory + */ + const InputParameters * currentlyConstructing() const; + private: template static std::shared_ptr buildAction(const InputParameters & parameters) @@ -119,4 +127,9 @@ class ActionFactory /// The registered tasks std::set _tasks; + + /// The object's parameters that are currently being constructed (if any). + /// This is a vector because we create within create, thus the last entry is the + /// one that is being constructed at the moment + std::vector _currently_constructing; }; diff --git a/framework/include/actions/ActionWarehouse.h b/framework/include/actions/ActionWarehouse.h index 7f52ea3e53c0..ed72d4c100e6 100644 --- a/framework/include/actions/ActionWarehouse.h +++ b/framework/include/actions/ActionWarehouse.h @@ -249,6 +249,13 @@ class ActionWarehouse : public ConsoleStreamInterface const std::string & getMooseAppName(); const std::string & getCurrentTaskName() const { return _current_task; } + /** + * @return The current action that is running, if any + */ + const Action * getCurrentAction() const { return _current_action; } + /** + * @return The name of the current action that is running + */ std::string getCurrentActionName() const; /** @@ -304,6 +311,8 @@ class ActionWarehouse : public ConsoleStreamInterface // When executing the actions in the warehouse, this string will always contain // the current task name std::string _current_task; + // The current action that is running + Action * _current_action; // // data created by actions @@ -322,7 +331,5 @@ class ActionWarehouse : public ConsoleStreamInterface /// Last task to run before (optional) early termination - blank means no early termination. std::string _final_task; - ActionIterator _act_iter; - const std::list _empty_action_list; }; diff --git a/framework/include/actions/CommonOutputAction.h b/framework/include/actions/CommonOutputAction.h index 0ff6e212397b..9193573300bf 100644 --- a/framework/include/actions/CommonOutputAction.h +++ b/framework/include/actions/CommonOutputAction.h @@ -12,6 +12,8 @@ // MOOSE includes #include "Action.h" +#include + /** * Meta-action for creating common output object parameters * This action serves two purpose, first it adds common output object @@ -35,8 +37,11 @@ class CommonOutputAction : public Action /** * Helper method for creating the short-cut actions * @param object_type String of the object type, i.e., the value of 'type=' in the input file + * @param param_name The name of the input parameter that is responsible for creating, if any */ - void create(std::string object_type); + void create(std::string object_type, + const std::optional & param_name, + const InputParameters * const from_params = nullptr); /** * Check if a Console object that outputs to the screen has been defined diff --git a/framework/include/base/Factory.h b/framework/include/base/Factory.h index 4064d4a3fec7..820d316216f3 100644 --- a/framework/include/base/Factory.h +++ b/framework/include/base/Factory.h @@ -70,11 +70,18 @@ class Factory * @param print_deprecated controls the deprecated message * @return The created object */ + ///@{ + std::unique_ptr createUnique(const std::string & obj_name, + const std::string & name, + const InputParameters & parameters, + THREAD_ID tid = 0, + bool print_deprecated = true); std::shared_ptr create(const std::string & obj_name, const std::string & name, const InputParameters & parameters, THREAD_ID tid = 0, bool print_deprecated = true); + ///@} /** * Build an object (must be registered) @@ -84,21 +91,39 @@ class Factory * @param tid The thread id that this copy will be created for * @return The created object */ + ///@{ + template + std::unique_ptr createUnique(const std::string & obj_name, + const std::string & name, + const InputParameters & parameters, + const THREAD_ID tid = 0); template std::shared_ptr create(const std::string & obj_name, const std::string & name, const InputParameters & parameters, - THREAD_ID tid = 0) - { - std::shared_ptr new_object = - std::dynamic_pointer_cast(create(obj_name, name, parameters, tid, false)); - if (!new_object) - mooseError("We expected to create an object of type '" + demangle(typeid(T).name()) + - "'.\nInstead we received a parameters object for type '" + obj_name + - "'.\nDid you call the wrong \"add\" method in your Action?"); + const THREAD_ID tid = 0); + ///@} + + /** + * Clones the object \p object. + * + * Under the hood, this creates a copy of the InputParameters from \p object + * and constructs a new object with the copied parameters. The suffix _clone + * will be added to the object's name, where is incremented each time + * the object is cloned. + */ + template + std::unique_ptr clone(const T & object); - return new_object; - } + /** + * Copy constructs the object \p object. + * + * Under the hood, the new object's parameters will point to the same address + * as the parameters in \p object. This can be dangerous and thus this is only + * allowed for a subset of objects. + */ + template + std::unique_ptr copyConstruct(const T & object); /** * Releases any shared resources created as a side effect of creating an object through @@ -133,6 +158,14 @@ class Factory MooseApp & app() { return _app; } + /** + * @return The InputParameters for the object that is currently being constructed, + * if any. + * + * Can be used to ensure that all MooseObjects are created using the Factory + */ + const InputParameters * currentlyConstructing() const; + private: /** * Parse time string (mm/dd/yyyy HH:MM) @@ -153,6 +186,23 @@ class Factory */ void reportUnregisteredError(const std::string & obj_name) const; + /** + * Initializes the data structures and the parameters (in the InputParameterWarehouse) + * for the object with the given state. + */ + InputParameters & initialize(const std::string & type, + const std::string & name, + const InputParameters & from_params, + const THREAD_ID tid); + + /** + * Finalizes the creaction of \p object of type \p type. + * + * This will do some sanity checking on whether or not the parameters in the + * created object match the valid paramters of the associated type. + */ + void finalize(const std::string & type, const MooseObject & object); + /// Reference to the application MooseApp & _app; @@ -183,4 +233,94 @@ class Factory /// again - which is okay/allowed, while still allowing us to detect/reject cases of duplicate /// object name registration where the label/appname is not identical. std::set> _objects_by_label; + + /// The object's parameters that are currently being constructed (if any). + /// This is a vector because we create within create, thus the last entry is the + /// one that is being constructed at the moment + std::vector _currently_constructing; + + /// Counter for keeping track of the number of times an object with a given name has + /// been cloned so that we can continue to create objects with unique names + std::map _clone_counter; }; + +template +std::unique_ptr +Factory::createUnique(const std::string & obj_name, + const std::string & name, + const InputParameters & parameters, + const THREAD_ID tid) +{ + auto object = createUnique(obj_name, name, parameters, tid, false); + if (!dynamic_cast(object.get())) + mooseError("We expected to create an object of type '" + demangle(typeid(T).name()) + + "'.\nInstead we received a parameters object for type '" + obj_name + + "'.\nDid you call the wrong \"add\" method in your Action?"); + + return std::unique_ptr(static_cast(object.release())); +} + +template +std::shared_ptr +Factory::create(const std::string & obj_name, + const std::string & name, + const InputParameters & parameters, + const THREAD_ID tid) +{ + return std::move(createUnique(obj_name, name, parameters, tid)); +} + +template +std::unique_ptr +Factory::clone(const T & object) +{ + static_assert(std::is_base_of_v, "Not a MooseObject"); + + const auto tid = object.template getParam("_tid"); + if (tid != 0) + mooseError("Factory::clone(): The object ", + object.typeAndName(), + " is threaded but cloning does not work with threaded objects"); + + // Clone the parameters; we can't copy construct InputParameters + InputParameters cloned_params = emptyInputParameters(); + cloned_params += object.parameters(); + if (const auto hit_node = object.parameters().getHitNode()) + cloned_params.setHitNode(*hit_node, {}); + + // Fill the new parameters in the warehouse + const auto type = static_cast(object).type(); + const auto clone_count = _clone_counter[&object]++; + const auto name = object.name() + "_clone" + std::to_string(clone_count); + const auto & params = initialize(type, name, cloned_params, 0); + + // Construct the object + _currently_constructing.push_back(¶ms); + auto cloned_object = std::make_unique(params); + _currently_constructing.pop_back(); + + // Do some sanity checking + finalize(type, *cloned_object); + + return cloned_object; +} + +template +std::unique_ptr +Factory::copyConstruct(const T & object) +{ + static_assert(std::is_base_of_v, "Not a MooseObject"); + + const auto type = static_cast(object).type(); + const auto base = object.parameters().getBase(); + if (!base || (*base != "MooseMesh" && *base != "RelationshipManager")) + mooseError("Copy construction of ", type, " objects is not supported."); + + _currently_constructing.push_back(&object.parameters()); + auto cloned_object = std::make_unique(object); + _currently_constructing.pop_back(); + + finalize(type, *cloned_object); + + return cloned_object; +} diff --git a/framework/include/base/MooseApp.h b/framework/include/base/MooseApp.h index 605483d1aacb..1f67d754f561 100644 --- a/framework/include/base/MooseApp.h +++ b/framework/include/base/MooseApp.h @@ -27,7 +27,7 @@ #include "MeshGeneratorSystem.h" #include "RestartableDataReader.h" #include "Backup.h" - +#include "MooseBase.h" #include "libmesh/parallel_object.h" #include "libmesh/mesh_base.h" #include "libmesh/point.h" @@ -55,6 +55,10 @@ namespace libMesh { class ExodusII_IO; } +namespace hit +{ +class Node; +} /** * Base class for MOOSE-based applications @@ -68,7 +72,8 @@ class ExodusII_IO; */ class MooseApp : public ConsoleStreamInterface, public PerfGraphInterface, - public libMesh::ParallelObject + public libMesh::ParallelObject, + public MooseBase { public: /** @@ -96,15 +101,6 @@ class MooseApp : public ConsoleStreamInterface, TheWarehouse & theWarehouse() { return *_the_warehouse; } - /** - * Get the name of the object. In the case of MooseApp, the name of the object is *NOT* the name - * of the application. It's the name of the created application which is usually "main". If you - * have subapps, then each individual subapp will have a unique name which typically comes from - * the input file (e.g. sub0, sub1, etc...). - * @return The name of the object - */ - const std::string & name() const { return _name; } - /** * Get printable name of the application. */ @@ -125,13 +121,6 @@ class MooseApp : public ConsoleStreamInterface, */ InputParameters & parameters() { return _pars; } - /** - * Get the type of this object as a string. This is a string version of the class name (e.g. - * MooseTestApp). - * @return The the type of the object - */ - const std::string & type() const; - /** * The RankMap is a useful object for determining how the processes * are laid out on the physical nodes of the cluster @@ -349,10 +338,9 @@ class MooseApp : public ConsoleStreamInterface, const InputParameters & params); /** - * Deprecated helper function to link the new added Builder back to Parser. This function will be - *removed after new Parser and builder are merged + * @return The Parser **/ - Moose::Builder & parser(); + Parser & parser(); private: /** @@ -940,6 +928,15 @@ class MooseApp : public ConsoleStreamInterface, /// The file suffix for restartable data std::filesystem::path restartFolderBase(const std::filesystem::path & folder_base) const; + /** + * @return The hit node that is responsible for creating the current action that is running, + * if any + * + * Can be used to link objects that are created by an action to the action that + * created them in input + */ + const hit::Node * getCurrentActionHitNode() const; + private: /** * Purge this relationship manager from meshes and DofMaps and finally from us. This method is @@ -1474,7 +1471,7 @@ template const T & MooseApp::getParam(const std::string & name) const { - return InputParameters::getParamHelper(name, _pars, static_cast(0)); + return InputParameters::getParamHelper(name, _pars, static_cast(0), this); } template @@ -1484,13 +1481,13 @@ MooseApp::getRenamedParam(const std::string & old_name, const std::string & new_ // this enables having a default on the new parameter but bypassing it with the old one // Most important: accept new parameter if (isParamSetByUser(new_name) && !isParamValid(old_name)) - return InputParameters::getParamHelper(new_name, _pars, static_cast(0)); + return InputParameters::getParamHelper(new_name, _pars, static_cast(0), this); // Second most: accept old parameter else if (isParamValid(old_name) && !isParamSetByUser(new_name)) - return InputParameters::getParamHelper(old_name, _pars, static_cast(0)); + return InputParameters::getParamHelper(old_name, _pars, static_cast(0), this); // Third most: accept default for new parameter else if (isParamValid(new_name) && !isParamValid(old_name)) - return InputParameters::getParamHelper(new_name, _pars, static_cast(0)); + return InputParameters::getParamHelper(new_name, _pars, static_cast(0), this); // Refuse: no default, no value passed else if (!isParamValid(old_name) && !isParamValid(new_name)) mooseError(_pars.blockFullpath() + ": parameter '" + new_name + diff --git a/framework/include/base/MooseBase.h b/framework/include/base/MooseBase.h index 5fcdd9efc73a..519c2eda90fe 100644 --- a/framework/include/base/MooseBase.h +++ b/framework/include/base/MooseBase.h @@ -11,6 +11,9 @@ #include +class InputParameters; +class MooseApp; + #define usingMooseBaseMembers \ using MooseBase::getMooseApp; \ using MooseBase::type; \ @@ -20,8 +23,6 @@ using MooseBase::_app; \ using MooseBase::_name -class MooseApp; - /** * Base class for everything in MOOSE with a name and a type. * You will most likely want to inherit instead @@ -31,10 +32,10 @@ class MooseApp; class MooseBase { public: - MooseBase(const std::string & type, const std::string & name, MooseApp & app) - : _app(app), _type(type), _name(name) - { - } + MooseBase(const std::string & type, + const std::string & name, + MooseApp & app, + const InputParameters & params); virtual ~MooseBase() = default; @@ -59,18 +60,36 @@ class MooseBase * Get the class's combined type and name; useful in error handling. * @return The type and name of this class in the form ' ""'. */ - std::string typeAndName() const - { - return type() + std::string(" \"") + name() + std::string("\""); - } + std::string typeAndName() const; + + /** + * @returns A prefix to be used in errors that contains the input + * file location associated with this object (if any) and the + * name and type of the object. + */ + std::string errorPrefix(const std::string & error_type) const; + + /** + * Calls moose error with the message \p msg. + * + * Will prefix the message with the subapp name if one exists. + * + * If \p with_prefix, then add the prefix from errorPrefix() + * to the error. + */ + [[noreturn]] void callMooseError(std::string msg, const bool with_prefix) const; protected: /// The MOOSE application this is associated with MooseApp & _app; /// The type of this class - const std::string & _type; + const std::string _type; + + /// The name of this class + const std::string _name; - /// The name of this class, reference to value stored in InputParameters - const std::string & _name; +private: + /// The object's parameteres + const InputParameters & _params; }; diff --git a/framework/include/base/MooseBaseErrorInterface.h b/framework/include/base/MooseBaseErrorInterface.h index 97227eb83ffd..a28be84a003a 100644 --- a/framework/include/base/MooseBaseErrorInterface.h +++ b/framework/include/base/MooseBaseErrorInterface.h @@ -14,22 +14,13 @@ #include "MooseError.h" #include "MooseBase.h" -/// Needed to break include cycle between MooseApp.h and Action.h -class MooseApp; -[[noreturn]] void callMooseErrorRaw(std::string & msg, MooseApp * app); - /** * Interface that provides APIs to output errors/warnings/info messages */ class MooseBaseErrorInterface : public ConsoleStreamInterface { public: - MooseBaseErrorInterface(const MooseBase * const base) - : ConsoleStreamInterface(base->getMooseApp()), _app(base->getMooseApp()), _moose_base(base) - { - } - - virtual ~MooseBaseErrorInterface() = default; + MooseBaseErrorInterface(const MooseBase & base); /** * Emits an error prefixed with object name and type. @@ -38,9 +29,8 @@ class MooseBaseErrorInterface : public ConsoleStreamInterface [[noreturn]] void mooseError(Args &&... args) const { std::ostringstream oss; - moose::internal::mooseStreamAll(oss, errorPrefix("error"), std::forward(args)...); - std::string msg = oss.str(); - callMooseErrorRaw(msg, &_app); + moose::internal::mooseStreamAll(oss, std::forward(args)...); + _moose_base.callMooseError(oss.str(), /* with_prefix = */ true); } /** @@ -51,8 +41,7 @@ class MooseBaseErrorInterface : public ConsoleStreamInterface { std::ostringstream oss; moose::internal::mooseStreamAll(oss, std::forward(args)...); - std::string msg = oss.str(); - callMooseErrorRaw(msg, &_app); + _moose_base.callMooseError(oss.str(), /* with_prefix = */ false); } /** @@ -62,7 +51,7 @@ class MooseBaseErrorInterface : public ConsoleStreamInterface void mooseWarning(Args &&... args) const { moose::internal::mooseWarningStream( - _console, errorPrefix("warning"), std::forward(args)...); + _console, _moose_base.errorPrefix("warning"), std::forward(args)...); } /** @@ -86,17 +75,7 @@ class MooseBaseErrorInterface : public ConsoleStreamInterface moose::internal::mooseInfoStream(_console, std::forward(args)...); } - /** - * A descriptive prefix for errors for this object: - * - * The following occurred in the object "", of type "". - */ - std::string errorPrefix(const std::string & error_type) const; - private: - /// The MOOSE application this is associated with - MooseApp & _app; - /// The MooseBase class deriving from this interface - const MooseBase * const _moose_base; + const MooseBase & _moose_base; }; diff --git a/framework/include/base/MooseBaseParameterInterface.h b/framework/include/base/MooseBaseParameterInterface.h index 9298f297c002..80472ec98d80 100644 --- a/framework/include/base/MooseBaseParameterInterface.h +++ b/framework/include/base/MooseBaseParameterInterface.h @@ -9,13 +9,12 @@ #pragma once -// MOOSE includes +#include "MooseBaseErrorInterface.h" + #include "MooseBase.h" #include "InputParameters.h" -#include "Registry.h" #include "MooseUtils.h" #include "MooseObjectParameterName.h" -#include "MooseBaseErrorInterface.h" #include @@ -43,7 +42,7 @@ std::string paramErrorPrefix(const InputParameters & params, const std::string & class MooseBaseParameterInterface { public: - MooseBaseParameterInterface(const InputParameters & parameters, const MooseBase * base); + MooseBaseParameterInterface(const MooseBase & base, const InputParameters & parameters); virtual ~MooseBaseParameterInterface() = default; @@ -53,7 +52,7 @@ class MooseBaseParameterInterface MooseObjectParameterName uniqueParameterName(const std::string & parameter_name) const { return MooseObjectParameterName( - _pars.get("_moose_base"), _moose_base->name(), parameter_name); + _pars.get("_moose_base"), _moose_base.name(), parameter_name); } /** @@ -145,11 +144,6 @@ class MooseBaseParameterInterface template void paramInfo(const std::string & param, Args... args) const; - /** - * A descriptive prefix for errors for an object - */ - std::string objectErrorPrefix(const std::string & error_type) const; - /** * Connect controllable parameter of this action with the controllable parameters of the * objects added by this action. @@ -175,7 +169,7 @@ class MooseBaseParameterInterface private: /// The MooseBase object that inherits this class - const MooseBase * const _moose_base; + const MooseBase & _moose_base; template std::string paramErrorMsg(const std::string & param, Args... args) const @@ -184,7 +178,7 @@ class MooseBaseParameterInterface // With no input location information, append object info (name + type) const std::string object_prefix = - _pars.inputLocation(param).empty() ? objectErrorPrefix("parameter error") : ""; + _pars.inputLocation(param).empty() ? _moose_base.errorPrefix("parameter error") : ""; std::ostringstream oss; moose::internal::mooseStreamAll(oss, std::forward(args)...); @@ -209,7 +203,7 @@ template const T & MooseBaseParameterInterface::getParam(const std::string & name) const { - return InputParameters::getParamHelper(name, _pars, static_cast(0)); + return InputParameters::getParamHelper(name, _pars, static_cast(0), &_moose_base); } template @@ -220,13 +214,13 @@ MooseBaseParameterInterface::getRenamedParam(const std::string & old_name, // this enables having a default on the new parameter but bypassing it with the old one // Most important: accept new parameter if (isParamSetByUser(new_name) && !isParamValid(old_name)) - return InputParameters::getParamHelper(new_name, _pars, static_cast(0)); + return InputParameters::getParamHelper(new_name, _pars, static_cast(0), &_moose_base); // Second most: accept old parameter else if (isParamValid(old_name) && !isParamSetByUser(new_name)) - return InputParameters::getParamHelper(old_name, _pars, static_cast(0)); + return InputParameters::getParamHelper(old_name, _pars, static_cast(0), &_moose_base); // Third most: accept default for new parameter else if (isParamValid(new_name) && !isParamValid(old_name)) - return InputParameters::getParamHelper(new_name, _pars, static_cast(0)); + return InputParameters::getParamHelper(new_name, _pars, static_cast(0), &_moose_base); // Refuse: no default, no value passed else if (!isParamValid(old_name) && !isParamValid(new_name)) mooseError(_pars.blockFullpath() + ": parameter '" + new_name + @@ -243,8 +237,8 @@ template MooseBaseParameterInterface::paramError(const std::string & param, Args... args) const { Moose::show_trace = false; - std::string msg = paramErrorMsg(param, std::forward(args)...); - callMooseErrorRaw(msg, &_moose_base->getMooseApp()); + _moose_base.callMooseError(paramErrorMsg(param, std::forward(args)...), + /* with_prefix = */ false); Moose::show_trace = true; } diff --git a/framework/include/base/MooseObjectUnitTest.h b/framework/include/base/MooseObjectUnitTest.h index 4f882df5bd49..789463dac9ce 100644 --- a/framework/include/base/MooseObjectUnitTest.h +++ b/framework/include/base/MooseObjectUnitTest.h @@ -12,7 +12,6 @@ #include "gtest/gtest.h" #include "MooseMesh.h" -#include "GeneratedMesh.h" #include "FEProblem.h" #include "AppFactory.h" #include "MooseMain.h" @@ -83,11 +82,13 @@ class MooseObjectUnitTest : public ::testing::Test void buildObjects() { InputParameters mesh_params = _factory.getValidParams("GeneratedMesh"); - mesh_params.set("_object_name") = "name1"; - mesh_params.set("_type") = "GeneratedMesh"; mesh_params.set("dim") = "3"; - _mesh = std::make_unique(mesh_params); + mesh_params.set("nx") = 2; + mesh_params.set("ny") = 2; + mesh_params.set("nz") = 2; + _mesh = _factory.createUnique("GeneratedMesh", "name1", mesh_params); _mesh->setMeshBase(_mesh->buildMeshBaseObject()); + _mesh->buildMesh(); InputParameters problem_params = _factory.getValidParams("FEProblem"); problem_params.set("mesh") = _mesh.get(); @@ -95,10 +96,26 @@ class MooseObjectUnitTest : public ::testing::Test _fe_problem = _factory.create("FEProblem", "problem", problem_params); _fe_problem->createQRules(QGAUSS, FIRST, FIRST, FIRST); + + _app->actionWarehouse().problemBase() = _fe_problem; } + template + T & addObject(const std::string & type, const std::string & name, InputParameters & params); + std::unique_ptr _mesh; std::shared_ptr _app; Factory & _factory; std::shared_ptr _fe_problem; }; + +template +T & +MooseObjectUnitTest::addObject(const std::string & type, + const std::string & name, + InputParameters & params) +{ + auto objects = _fe_problem->addObject(type, name, params); + mooseAssert(objects.size() == 1, "Doesn't work with threading"); + return *objects[0]; +} diff --git a/framework/include/base/Registry.h b/framework/include/base/Registry.h index c8143ee04179..ba00cbd34a38 100644 --- a/framework/include/base/Registry.h +++ b/framework/include/base/Registry.h @@ -10,6 +10,7 @@ #pragma once #include "InputParameters.h" +#include "MooseObject.h" #include #include @@ -114,7 +115,7 @@ struct RegistryEntryBase : public RegistryEntryData RegistryEntryBase(const RegistryEntryData & data) : RegistryEntryData(data) {} virtual ~RegistryEntryBase() {} /// proxy functions - virtual std::shared_ptr build(const InputParameters & parameters) = 0; + virtual std::unique_ptr build(const InputParameters & parameters) = 0; virtual std::shared_ptr buildAction(const InputParameters & parameters) = 0; virtual InputParameters buildParameters() = 0; /// resolve the name from _classname, _alias, and _name @@ -133,7 +134,7 @@ template struct RegistryEntry : public RegistryEntryBase { RegistryEntry(const RegistryEntryData & data) : RegistryEntryBase(data) {} - virtual std::shared_ptr build(const InputParameters & parameters) override; + virtual std::unique_ptr build(const InputParameters & parameters) override; virtual std::shared_ptr buildAction(const InputParameters & parameters) override; virtual InputParameters buildParameters() override; }; @@ -258,13 +259,12 @@ Registry::getRegisteredName() } template -std::shared_ptr +std::unique_ptr RegistryEntry::build(const InputParameters & parameters) { - if constexpr (!std::is_base_of_v) - mooseError("The object to be built is not derived from MooseObject."); - else - return std::make_shared(parameters); + if constexpr (std::is_base_of_v) + return std::make_unique(parameters); + mooseError("The object to be built is not derived from MooseObject."); } template diff --git a/framework/include/interfaces/DataFileInterface.h b/framework/include/interfaces/DataFileInterface.h index 1093fc5d524d..43883e601146 100644 --- a/framework/include/interfaces/DataFileInterface.h +++ b/framework/include/interfaces/DataFileInterface.h @@ -23,7 +23,7 @@ class DataFileInterface /** * The parameter type this interface expects for a data file name. */ - using DataFileParameterType = FileName; + using DataFileParameterType = DataFileName; /** * Constructing the object diff --git a/framework/include/mesh/ConcentricCircleMesh.h b/framework/include/mesh/ConcentricCircleMesh.h index fb2abd914621..627ffe9eb6d6 100644 --- a/framework/include/mesh/ConcentricCircleMesh.h +++ b/framework/include/mesh/ConcentricCircleMesh.h @@ -25,10 +25,7 @@ class ConcentricCircleMesh : public MooseMesh ConcentricCircleMesh(const ConcentricCircleMesh & /* other_mesh */) = default; ConcentricCircleMesh & operator=(const ConcentricCircleMesh & other_mesh) = delete; - virtual std::unique_ptr safeClone() const override - { - return std::make_unique(*this); - } + virtual std::unique_ptr safeClone() const override; virtual void buildMesh() override; diff --git a/framework/include/parser/Builder.h b/framework/include/parser/Builder.h index 0fcb03819053..ba3b1004a60d 100644 --- a/framework/include/parser/Builder.h +++ b/framework/include/parser/Builder.h @@ -155,29 +155,6 @@ class Builder : public ConsoleStreamInterface, public hit::Walker bool in_global, GlobalParamsAction * global_block); - /** - * Sets an input parameter representing a file path using input file data. The file path is - * modified to be relative to the directory this application's input file is in. - */ - template - void setFilePathParam(const std::string & full_name, - const std::string & short_name, - InputParameters::Parameter * param, - InputParameters & params, - bool in_global, - GlobalParamsAction * global_block); - - /** - * Sets an input parameter representing a vector of file paths using input file data. The file - * paths are modified to be relative to the directory this application's input file is in. - */ - template - void setVectorFilePathParam(const std::string & full_name, - const std::string & short_name, - InputParameters::Parameter> * param, - InputParameters & params, - bool in_global, - GlobalParamsAction * global_block); /** * Template method for setting any double indexed type parameter read from the input file or * command line. diff --git a/framework/include/parser/Parser.h b/framework/include/parser/Parser.h index ec6eba53805f..37e551278481 100644 --- a/framework/include/parser/Parser.h +++ b/framework/include/parser/Parser.h @@ -113,16 +113,16 @@ class Parser { public: /** - * Constructor given a list of input files, given in \p input_filenames + * Constructor given a list of input files, given in \p input_filenames. + * + * Optionally, the file contents can be provided via text in \p input_text. */ - Parser(const std::vector & input_filenames); + Parser(const std::vector & input_filenames, + const std::optional> & input_text = {}); /** - * Constructor for a single input file, given in \p input_filename + * Constructor, given a file in \p input_filename. * - * Optionally, \p input_text can be provided if you wish to parse contents - * from this text instead of reading \p input_filename. This is currently used - * within the language server for parsing contents of a file that have not - * necessary been saved to disk yet. + * Optionally, the file contents can be provided via text in \p input_text. */ Parser(const std::string & input_filename, const std::optional & input_text = {}); @@ -177,8 +177,8 @@ class Parser /// The input file names const std::vector _input_filenames; - /// The optional input text (to augment reading a single input with the MooseServer) - const std::optional _input_text; + /// The optional input text contents (to support not reading by file) + const std::optional> _input_text; /// The application types extracted from [Application] block std::string _app_type; diff --git a/framework/include/problems/FEProblemBase.h b/framework/include/problems/FEProblemBase.h index 677f0e7791f3..5ebfc3379f6a 100644 --- a/framework/include/problems/FEProblemBase.h +++ b/framework/include/problems/FEProblemBase.h @@ -943,9 +943,8 @@ class FEProblemBase : public SubProblem, public Restartable ReporterData & getReporterData(ReporterData::WriteKey /*key*/) { return _reporter_data; } // UserObjects ///// - virtual void addUserObject(const std::string & user_object_name, - const std::string & name, - InputParameters & parameters); + virtual std::vector> addUserObject( + const std::string & user_object_name, const std::string & name, InputParameters & parameters); // TODO: delete this function after apps have been updated to not call it const ExecuteMooseObjectWarehouse & getUserObjects() const diff --git a/framework/include/relationshipmanagers/AugmentSparsityOnInterface.h b/framework/include/relationshipmanagers/AugmentSparsityOnInterface.h index 47b65c843891..a2847b63a941 100644 --- a/framework/include/relationshipmanagers/AugmentSparsityOnInterface.h +++ b/framework/include/relationshipmanagers/AugmentSparsityOnInterface.h @@ -46,10 +46,7 @@ class AugmentSparsityOnInterface : public RelationshipManager * A clone() is needed because GhostingFunctor can not be shared between * different meshes. The operations in GhostingFunctor are mesh dependent. */ - virtual std::unique_ptr clone() const override - { - return std::make_unique(*this); - } + virtual std::unique_ptr clone() const override; /** * Update the cached _lower_to_upper map whenever our Mesh has been diff --git a/framework/include/relationshipmanagers/GhostEverything.h b/framework/include/relationshipmanagers/GhostEverything.h index 97952aabbfe9..b7540794bbb3 100644 --- a/framework/include/relationshipmanagers/GhostEverything.h +++ b/framework/include/relationshipmanagers/GhostEverything.h @@ -25,10 +25,7 @@ class GhostEverything : public RelationshipManager processor_id_type p, map_type & coupled_elements) override; - std::unique_ptr clone() const override - { - return std::make_unique(*this); - } + std::unique_ptr clone() const override; std::string getInfo() const override; diff --git a/framework/include/relationshipmanagers/GhostHigherDLowerDPointNeighbors.h b/framework/include/relationshipmanagers/GhostHigherDLowerDPointNeighbors.h index 0c542a7f4b04..d73a79350b5e 100644 --- a/framework/include/relationshipmanagers/GhostHigherDLowerDPointNeighbors.h +++ b/framework/include/relationshipmanagers/GhostHigherDLowerDPointNeighbors.h @@ -25,10 +25,7 @@ class GhostHigherDLowerDPointNeighbors : public RelationshipManager processor_id_type p, map_type & coupled_elements) override; - std::unique_ptr clone() const override - { - return std::make_unique(*this); - } + std::unique_ptr clone() const override; std::string getInfo() const override; diff --git a/framework/include/relationshipmanagers/GhostLowerDElems.h b/framework/include/relationshipmanagers/GhostLowerDElems.h index 64690c92e762..7a19be077889 100644 --- a/framework/include/relationshipmanagers/GhostLowerDElems.h +++ b/framework/include/relationshipmanagers/GhostLowerDElems.h @@ -25,10 +25,7 @@ class GhostLowerDElems : public RelationshipManager processor_id_type p, map_type & coupled_elements) override; - std::unique_ptr clone() const override - { - return std::make_unique(*this); - } + std::unique_ptr clone() const override; std::string getInfo() const override; diff --git a/framework/include/relationshipmanagers/ProxyRelationshipManager.h b/framework/include/relationshipmanagers/ProxyRelationshipManager.h index 52ed3fff8500..1c4544ef5379 100644 --- a/framework/include/relationshipmanagers/ProxyRelationshipManager.h +++ b/framework/include/relationshipmanagers/ProxyRelationshipManager.h @@ -45,10 +45,7 @@ class ProxyRelationshipManager : public RelationshipManager * A clone() is needed because GhostingFunctor can not be shared between * different meshes. The operations in GhostingFunctor are mesh dependent. */ - virtual std::unique_ptr clone() const override - { - return std::make_unique(*this); - } + virtual std::unique_ptr clone() const override; protected: virtual void internalInitWithMesh(const MeshBase &) override{}; diff --git a/framework/include/userobjects/NearestPointBase.h b/framework/include/userobjects/NearestPointBase.h index cdb64fa4736c..49edaf038248 100644 --- a/framework/include/userobjects/NearestPointBase.h +++ b/framework/include/userobjects/NearestPointBase.h @@ -69,19 +69,16 @@ class NearestPointBase : public BaseType * @param p The point. * @return The UserObject closest to p. */ - std::shared_ptr nearestUserObject(const Point & p) const; + UserObjectType & nearestUserObject(const Point & p) const; std::vector _points; - std::vector> _user_objects; + std::vector> _user_objects; // To specify whether the distance is defined based on point or radius const unsigned int _dist_norm; // The axis around which the radius is determined const unsigned int _axis; - // The list of InputParameter objects. This is a list because these cannot be copied (or moved). - std::list _sub_params; - using BaseType::_communicator; using BaseType::_current_elem; using BaseType::isParamValid; @@ -129,17 +126,21 @@ NearestPointBase::NearestPointBase(const InputParamete fillPoints(); - _user_objects.reserve(_points.size()); + _user_objects.resize(_points.size()); - // Build each of the UserObject objects: + // Build each of the UserObject objects that we will manage manually + // If you're looking at this in the future and want to replace this behavior, + // _please_ don't do it. MOOSE should manage these objects. for (MooseIndex(_points) i = 0; i < _points.size(); ++i) { - auto sub_params = emptyInputParameters(); - sub_params += parameters; - sub_params.set("_object_name") = name() + "_sub" + std::to_string(i); - - _sub_params.push_back(sub_params); - _user_objects.emplace_back(std::make_shared(_sub_params.back())); + const auto uo_type = MooseUtils::prettyCppType(); + auto sub_params = this->_app.getFactory().getValidParams(uo_type); + sub_params.applyParameters(parameters, {}, true); + + const auto sub_name = name() + "_sub" + std::to_string(i); + auto uo = this->_app.getFactory().template createUnique( + uo_type, sub_name, sub_params, this->_tid); + _user_objects[i] = std::move(uo); } } @@ -184,7 +185,7 @@ template void NearestPointBase::execute() { - nearestUserObject(_current_elem->vertex_average())->execute(); + nearestUserObject(_current_elem->vertex_average()).execute(); } template @@ -209,11 +210,11 @@ template Real NearestPointBase::spatialValue(const Point & p) const { - return nearestUserObject(p)->spatialValue(p); + return nearestUserObject(p).spatialValue(p); } template -std::shared_ptr +UserObjectType & NearestPointBase::nearestUserObject(const Point & p) const { unsigned int closest = 0; @@ -252,7 +253,7 @@ NearestPointBase::nearestUserObject(const Point & p) c } } - return _user_objects[closest]; + return *_user_objects[closest]; } template @@ -263,8 +264,7 @@ NearestPointBase::spatialPoints() const for (MooseIndex(_points) i = 0; i < _points.size(); ++i) { - std::shared_ptr layered_base = - std::dynamic_pointer_cast(_user_objects[i]); + auto layered_base = dynamic_cast(_user_objects[i].get()); if (layered_base) { const auto & layers = layered_base->getLayerCenters(); diff --git a/framework/include/utils/InputParameterWarehouse.h b/framework/include/utils/InputParameterWarehouse.h index e51d0103e39d..9895508c1951 100644 --- a/framework/include/utils/InputParameterWarehouse.h +++ b/framework/include/utils/InputParameterWarehouse.h @@ -14,12 +14,12 @@ #include "MooseTypes.h" #include "ControllableItem.h" #include "ControllableParameter.h" -#include "Factory.h" -#include "ActionFactory.h" #include "ControlOutput.h" // Forward declarations class InputParameters; +class Factory; +class ActionFactory; /** * Storage container for all InputParamter objects. @@ -43,6 +43,24 @@ class InputParameterWarehouse */ virtual ~InputParameterWarehouse() = default; + /** + * Class that is used as a parameter to [add/remove]InputParameters() + * to restrict access. + */ + class AddRemoveParamsKey + { + friend class Factory; + friend class ActionFactory; + FRIEND_TEST(InputParameterWarehouseTest, getControllableItems); + FRIEND_TEST(InputParameterWarehouseTest, getControllableParameter); + FRIEND_TEST(InputParameterWarehouseTest, getControllableParameterValues); + FRIEND_TEST(InputParameterWarehouseTest, emptyControllableParameterValues); + FRIEND_TEST(InputParameterWarehouseTest, addControllableParameterConnection); + FRIEND_TEST(InputParameterWarehouseTest, addControllableParameterAlias); + AddRemoveParamsKey() {} + AddRemoveParamsKey(const AddRemoveParamsKey &) {} + }; + ///@{ /** * Return a const reference to the InputParameters for the named object @@ -105,17 +123,6 @@ class InputParameterWarehouse std::vector getControllableParameterNames(const MooseObjectParameterName & input) const; -private: - /// Storage for the InputParameters objects - /// TODO: Remove multimap - std::vector>> _input_parameters; - - /// Storage for controllable parameters via ControllableItem objects, a unique_ptr is - /// used to avoid creating multiple copies. All access to the objects are done via - /// pointers. The ControllableItem objects are not designed and will not be used directly in - /// user code. All user level access goes through the ControllableParameter object. - std::vector>> _controllable_items; - /** * Method for adding a new InputParameters object * @param parameters The InputParameters object to copy and store in the warehouse @@ -126,17 +133,30 @@ class InputParameterWarehouse * are generic until Factory::create() is called and the actual MooseObject * is created. * - * This method is private, because only the factories that are creating objects should be - * able to call this method. + * This method is protected by the AddRemoveParamsKey, because only the factories + * that are creating objects should be able to call this method. */ InputParameters & addInputParameters(const std::string & name, const InputParameters & parameters, - THREAD_ID tid = 0); + THREAD_ID tid, + const AddRemoveParamsKey); /** * Allows for the deletion and cleanup of an object while the simulation is running. */ - void removeInputParameters(const MooseObject & moose_object, THREAD_ID tid = 0); + void + removeInputParameters(const MooseObject & moose_object, THREAD_ID tid, const AddRemoveParamsKey); + +private: + /// Storage for the InputParameters objects + /// TODO: Remove multimap + std::vector>> _input_parameters; + + /// Storage for controllable parameters via ControllableItem objects, a unique_ptr is + /// used to avoid creating multiple copies. All access to the objects are done via + /// pointers. The ControllableItem objects are not designed and will not be used directly in + /// user code. All user level access goes through the ControllableParameter object. + std::vector>> _controllable_items; /** * Returns a ControllableParameter object that contains all matches to ControllableItem objects @@ -173,15 +193,6 @@ class InputParameterWarehouse THREAD_ID tid = 0) const; ///@} - ///@{ - /// The factory is allowed to call addInputParameters and removeInputParameters. - friend std::shared_ptr Factory::create( - const std::string &, const std::string &, const InputParameters &, THREAD_ID, bool); - friend std::shared_ptr - ActionFactory::create(const std::string &, const std::string &, InputParameters &); - friend void Factory::releaseSharedObjects(const MooseObject &, THREAD_ID); - ///@} - /// Only controls are allowed to call getControllableParameter. The /// Control::getControllableParameter is the only method that calls getControllableParameter. /// However, this method cannot be made a friend explicitly because the method would need to be @@ -190,12 +201,12 @@ class InputParameterWarehouse friend class Control; // Allow unit test to call methods - FRIEND_TEST(InputParameterWarehouse, getControllableItems); - FRIEND_TEST(InputParameterWarehouse, getControllableParameter); - FRIEND_TEST(InputParameterWarehouse, getControllableParameterValues); - FRIEND_TEST(InputParameterWarehouse, emptyControllableParameterValues); - FRIEND_TEST(InputParameterWarehouse, addControllableParameterConnection); - FRIEND_TEST(InputParameterWarehouse, addControllableParameterAlias); + FRIEND_TEST(InputParameterWarehouseTest, getControllableItems); + FRIEND_TEST(InputParameterWarehouseTest, getControllableParameter); + FRIEND_TEST(InputParameterWarehouseTest, getControllableParameterValues); + FRIEND_TEST(InputParameterWarehouseTest, emptyControllableParameterValues); + FRIEND_TEST(InputParameterWarehouseTest, addControllableParameterConnection); + FRIEND_TEST(InputParameterWarehouseTest, addControllableParameterAlias); }; template diff --git a/framework/include/utils/InputParameters.h b/framework/include/utils/InputParameters.h index 4965de727d10..fac30599db1a 100644 --- a/framework/include/utils/InputParameters.h +++ b/framework/include/utils/InputParameters.h @@ -32,14 +32,29 @@ class FunctionParserBase #include #include #include +#include + +#include // Forward declarations class Action; +class ActionFactory; +class Factory; +class FEProblemBase; class InputParameters; class MooseEnum; class MooseObject; +class MooseBase; class MultiMooseEnum; class Problem; +namespace hit +{ +class Node; +} +namespace Moose +{ +class Builder; +} /** * The main MOOSE class responsible for handling user-defined @@ -73,6 +88,35 @@ class InputParameters : public Parameters ArgumentType argument_type; }; + /** + * Class that is used as a parameter to setHitNode() that allows only + * relevant classes to set the hit node + */ + class SetHitNodeKey + { + friend class Action; + friend class ActionFactory; + friend class Moose::Builder; + friend class Factory; + friend class FEProblemBase; + friend class InputParameters; + FRIEND_TEST(InputParametersTest, fileNames); + SetHitNodeKey() {} + SetHitNodeKey(const SetHitNodeKey &) {} + }; + + /** + * Class that is used as a parameter to setHitNode(param) that allows only + * relevant classes to set the hit node + */ + class SetParamHitNodeKey + { + friend class Moose::Builder; + FRIEND_TEST(InputParametersTest, fileNames); + SetParamHitNodeKey() {} + SetParamHitNodeKey(const SetParamHitNodeKey &) {} + }; + /** * This method adds a description of the class that will be displayed * in the input file syntax dump @@ -528,6 +572,11 @@ class InputParameters : public Parameters */ void registerBase(const std::string & value); + /** + * @return The base system of the object these parameters are for, if any + */ + std::optional getBase() const; + /** * This method is used to define the MOOSE system name that is used by the TheWarehouse object * for storing objects to be retrieved for execution. The base class of every object class @@ -629,6 +678,28 @@ class InputParameters : public Parameters */ void checkParams(const std::string & parsing_syntax); + /** + * Finalizes the parameters, which must be done before constructing any objects + * with these parameters (to be called in the corresponding factories). + * typed parameters. + * + * This calls checkParams() and sets up the absolute paths for all file name. + */ + void finalize(const std::string & parsing_syntax); + + /** + * @return A file base to associate with the parameter with name \p param_name. + * + * We have the following cases: + * - The parameter itself has a hit node set (context for that parameter) + * - The InputParameters object has a hit node set (context for all parameters) + * - Neither of the above and we die + * + * In the event that a the parameter is set via command line, this will + * attempt to look at the parameter's parents to find a suitable context. + */ + std::filesystem::path getParamFileBase(const std::string & param_name) const; + /** * Methods returning iterators to the coupled variables names stored in this * InputParameters object @@ -799,7 +870,7 @@ class InputParameters : public Parameters static const T & getParamHelper(const std::string & name, const InputParameters & pars, const T * the_type, - const MooseObject * moose_object = nullptr); + const MooseBase * moose_base = nullptr); ///@} using Parameters::get; @@ -842,60 +913,49 @@ class InputParameters : public Parameters */ std::set reservedValues(const std::string & name) const; - ///@{ /** - * Get/set a string representing the location (i.e. filename,linenum) in the input text for the + * @return A string representing the location (i.e. filename,linenum) in the input text for the * block containing parameters for this object. */ - std::string & blockLocation() { return _block_location; } - const std::string & blockLocation() const { return _block_location; } - ///@} + std::string blockLocation() const; - ///@{ /** - * Get/set a string representing the full HIT parameter path from the input file (e.g. + * @return A string representing the full HIT parameter path from the input file (e.g. * "Mesh/foo") for the block containing parameters for this object. */ - std::string & blockFullpath() { return _block_fullpath; } - const std::string & blockFullpath() const { return _block_fullpath; } - ///@} + std::string blockFullpath() const; - ///@{ /** - * Get/set a string representing the location in the input text the parameter originated from - * (i.e. filename,linenum) for the given param. + * @return The hit node associated with setting the parameter \p param, if any */ - const std::string & inputLocation(const std::string & param) const - { - return at(param)._input_location; - } - std::string & inputLocation(const std::string & param) { return at(param)._input_location; } - ///@} + const hit::Node * getHitNode(const std::string & param) const; + /** + * Sets the hit node associated with the parameter \p param to \p node + * + * Is protected to be called by only the Builder via the SetParamHitNodeKey. + */ + void setHitNode(const std::string & param, const hit::Node & node, const SetParamHitNodeKey); - ///@{ /** - * Get/set a string representing the full HIT parameter path from the input file (e.g. + * @return A string representing the location in the input text the parameter originated from + * (i.e. filename,linenum) for the given param + */ + std::string inputLocation(const std::string & param) const; + + /** + * @return A string representing the full HIT parameter path from the input file (e.g. * "Mesh/foo/bar" for param "bar") for the given param. */ - const std::string & paramFullpath(const std::string & param) const - { - return at(param)._param_fullpath; - } - std::string & paramFullpath(const std::string & param) { return at(param)._param_fullpath; } - ///@} + std::string paramFullpath(const std::string & param) const; /// generate error message prefix with parameter name and location (if available) std::string errorPrefix(const std::string & param) const; /** - * Get/set a string representing the raw, unmodified token text for the given param. This is - * usually only set/useable for file-path type parameters. + * @return A string representing the raw, unmodified token text for the given param. + * This is only set if this parameter is parsed from hit */ - std::string & rawParamVal(const std::string & param) { return _params[param]._raw_val; } - const std::string & rawParamVal(const std::string & param) const - { - return _params.at(param)._raw_val; - } + std::string rawParamVal(const std::string & param) const; /** * Informs this object that values for this parameter set from the input file or from the command @@ -1008,6 +1068,25 @@ class InputParameters : public Parameters */ std::vector paramAliases(const std::string & param_name) const; + /** + * @return The hit node that represents the syntax responsible for creating + * these parameters, if any + */ + const hit::Node * getHitNode() const { return _hit_node; } + /** + * Sets the hit node that represents the syntax responsible for creating + * these parameters + * + * Is protected to be called by only the ActionFactory, Builder, and Factory + * via the SetHitNodeKey. + */ + void setHitNode(const hit::Node & node, const SetHitNodeKey) { _hit_node = &node; } + + /** + * @return Whether or not finalize() has been called + */ + bool isFinalized() const { return _finalized; } + private: // Private constructor so that InputParameters can only be created in certain places. InputParameters(); @@ -1037,7 +1116,7 @@ class InputParameters : public Parameters const std::string & docstring, const std::string & removal_date); - static void callMooseErrorHelper(const MooseObject & object, const std::string & error); + static void callMooseErrorHelper(const MooseBase & moose_base, const std::string & error); struct Metadata { @@ -1071,12 +1150,8 @@ class InputParameters : public Parameters std::set _reserved_values; /// If non-empty, this parameter is deprecated. std::string _deprecation_message; - /// original location of parameter (i.e. filename,linenum) - used for nice error messages. - std::string _input_location; - /// full HIT path of the parameter from the input file - used for nice error messages. - std::string _param_fullpath; - /// raw token text for a parameter - usually only set for filepath type params. - std::string _raw_val; + /// Original location of parameter node; used for error messages + const hit::Node * _hit_node; /// True if the parameters is controllable bool _controllable = false; /// Controllable execute flag restriction @@ -1191,6 +1266,12 @@ class InputParameters : public Parameters /// names std::multimap _new_to_old_names; + /// The hit node representing the syntax that created these parameters, if any + const hit::Node * _hit_node; + + /// Whether or not we've called finalize() on these parameters yet + bool _finalized; + // These are the only objects allowed to _create_ InputParameters friend InputParameters emptyInputParameters(); friend class InputParameterWarehouse; @@ -1813,12 +1894,13 @@ void InputParameters::setParamHelper(const std::string & MooseFunctorName & l_value, const int & r_value); +// TODO: pass MooseBase here instead and use it in objects template const T & InputParameters::getParamHelper(const std::string & name_in, const InputParameters & pars, const T *, - const MooseObject * moose_object /* = nullptr */) + const MooseBase * moose_base /* = nullptr */) { const auto name = pars.checkForRename(name_in); @@ -1826,8 +1908,8 @@ InputParameters::getParamHelper(const std::string & name_in, { std::stringstream err; err << "The parameter \"" << name << "\" is being retrieved before being set."; - if (moose_object) - callMooseErrorHelper(*moose_object, err.str()); + if (moose_base) + callMooseErrorHelper(*moose_base, err.str()); else mooseError(err.str()); } @@ -1843,14 +1925,14 @@ const MooseEnum & InputParameters::getParamHelper(const std::string & name, const InputParameters & pars, const MooseEnum *, - const MooseObject * moose_object /* = nullptr */); + const MooseBase * moose_base /* = nullptr */); template <> const MultiMooseEnum & InputParameters::getParamHelper(const std::string & name, const InputParameters & pars, const MultiMooseEnum *, - const MooseObject * moose_object /* = nullptr */); + const MooseBase * moose_base /* = nullptr */); template std::vector> diff --git a/framework/include/utils/MooseTypes.h b/framework/include/utils/MooseTypes.h index 8f83c00ef05e..431afa17fb12 100644 --- a/framework/include/utils/MooseTypes.h +++ b/framework/include/utils/MooseTypes.h @@ -955,18 +955,22 @@ struct enable_bitmask_operators // Instantiate new Types -/// This type is for expected (i.e. input) file names or paths that your simulation needs. If -/// relative paths are assigned to this type, they are treated/modified to be relative to the -/// location of the simulation's main input file's directory. It can be used to trigger open file -/// dialogs in the GUI. +/// This type is for expected (i.e. input) file names or paths that your simulation needs. +/// If relative types are assigned to this type, they are replaced with an absolute path +/// that is relative to the context of the parameter (usually the input file). DerivativeStringClass(FileName); -/// This type is for expected filenames where the extension is unwanted, it can be used to trigger open file dialogs in the GUI +/// Similar to FileName but without an extension DerivativeStringClass(FileNameNoExtension); -/// This type is for expected filenames that should be relative (don't set the absolute path under the hood) +/// This type is for expected filenames that should be relative and will not have their +/// values set to absolute paths like FileName DerivativeStringClass(RelativeFileName); +/// This type is for files used in the DataFileInterface, which enables searching of files +/// within the registered data directory +DerivativeStringClass(DataFileName); + /// This type is similar to "FileName", but is used to further filter file dialogs on known file mesh types DerivativeStringClass(MeshFileName); diff --git a/framework/src/actions/Action.C b/framework/src/actions/Action.C index 451e549b278a..4e03c005d870 100644 --- a/framework/src/actions/Action.C +++ b/framework/src/actions/Action.C @@ -18,6 +18,7 @@ #include "DisplacedProblem.h" #include "RelationshipManager.h" #include "InputParameterWarehouse.h" +#include "ActionFactory.h" InputParameters Action::validParams() @@ -40,12 +41,12 @@ Action::validParams() } Action::Action(const InputParameters & parameters) - : MooseBase( - parameters.get("action_type"), - parameters.get("_action_name"), - *parameters.getCheckedPointerParam("_moose_app", "In Action constructor")), - MooseBaseParameterInterface(parameters, this), - MooseBaseErrorInterface(this), + : MooseBase(parameters.get("action_type"), + parameters.get("_action_name"), + *parameters.getCheckedPointerParam("_moose_app", "In Action constructor"), + parameters), + MooseBaseParameterInterface(*this, parameters), + MooseBaseErrorInterface(static_cast(*this)), MeshMetaDataInterface( *parameters.getCheckedPointerParam("_moose_app", "In Action constructor")), PerfGraphInterface( @@ -74,6 +75,8 @@ Action::Action(const InputParameters & parameters) _problem(_awh.problemBase()), _act_timer(registerTimedSection("act", 4)) { + if (_app.getActionFactory().currentlyConstructing() != ¶meters) + mooseError("This object was not constructed using the ActionFactory, which is not supported."); } void @@ -152,3 +155,24 @@ Action::addRelationshipManagers(Moose::RelationshipManagerType input_rm_type, return added; } + +void +Action::associateWithParameter(const std::string & param_name, InputParameters & params) const +{ + associateWithParameter(parameters(), param_name, params); +} + +void +Action::associateWithParameter(const InputParameters & from_params, + const std::string & param_name, + InputParameters & params) const +{ + const auto to_hit_node = params.getHitNode(); + if (!to_hit_node || to_hit_node->isRoot()) + { + if (const auto hit_node = from_params.getHitNode(param_name)) + params.setHitNode(*hit_node, {}); + else if (const auto hit_node = from_params.getHitNode()) + params.setHitNode(*hit_node, {}); + } +} diff --git a/framework/src/actions/ActionFactory.C b/framework/src/actions/ActionFactory.C index 0c9c2e0a94be..424548a725a2 100644 --- a/framework/src/actions/ActionFactory.C +++ b/framework/src/actions/ActionFactory.C @@ -49,10 +49,22 @@ ActionFactory::create(const std::string & action, action + incoming_parser_params.get("task") + full_action_name; // Create the actual parameters object that the object will reference InputParameters & action_params = _app.getInputParameterWarehouse().addInputParameters( - unique_action_name, incoming_parser_params); - - // Check to make sure that all required parameters are supplied - action_params.checkParams(action_name); + unique_action_name, incoming_parser_params, 0, {}); + + if (!action_params.getHitNode()) + { + // If we currently are in an action, that means that we're creating an + // action from within an action. Associate the action creating this one + // with the new action's parameters so that errors can be associated with it + if (const auto hit_node = _app.getCurrentActionHitNode()) + action_params.setHitNode(*hit_node, {}); + // Don't have one, so just use the root + else + action_params.setHitNode(*_app.parser().root(), {}); + } + + // Check and finalize the parameters + action_params.finalize(action_name); iters = _name_to_build_info.equal_range(action); BuildInfo * build_info = &(iters.first->second); @@ -61,10 +73,14 @@ ActionFactory::create(const std::string & action, std::string("Unable to find buildable Action from supplied InputParameters Object for ") + action_name); - // Add the name to the parameters and create the object + // Add the name to the parameters action_params.set("_action_name") = action_name; action_params.set("_unique_action_name") = unique_action_name; + + // Create the object + _currently_constructing.push_back(&action_params); std::shared_ptr action_obj = build_info->_obj_pointer->buildAction(action_params); + _currently_constructing.pop_back(); if (action_params.get("task") == "") action_obj->appendTask(build_info->_task); @@ -150,6 +166,13 @@ ActionFactory::getTasksByAction(const std::string & action) const return tasks; } + +const InputParameters * +ActionFactory::currentlyConstructing() const +{ + return _currently_constructing.size() ? _currently_constructing.back() : nullptr; +} + FileLineInfo ActionFactory::getLineInfo(const std::string & name, const std::string & task) const { diff --git a/framework/src/actions/ActionWarehouse.C b/framework/src/actions/ActionWarehouse.C index df0e9624cedf..5465c44727c2 100644 --- a/framework/src/actions/ActionWarehouse.C +++ b/framework/src/actions/ActionWarehouse.C @@ -33,6 +33,7 @@ ActionWarehouse::ActionWarehouse(MooseApp & app, Syntax & syntax, ActionFactory _show_action_dependencies(false), _show_actions(false), _show_parser(false), + _current_action(nullptr), _mesh(nullptr), _displaced_mesh(nullptr) { @@ -366,9 +367,10 @@ ActionWarehouse::executeActionsWithAction(const std::string & task) // Set the current task name _current_task = task; - for (_act_iter = actionBlocksWithActionBegin(task); _act_iter != actionBlocksWithActionEnd(task); - ++_act_iter) + for (auto it = actionBlocksWithActionBegin(task); it != actionBlocksWithActionEnd(task); ++it) { + _current_action = *it; + if (_show_actions) { MemoryUtils::Stats stats; @@ -377,14 +379,16 @@ ActionWarehouse::executeActionsWithAction(const std::string & task) MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes); _console << "[DBG][ACT] " << "TASK (" << COLOR_YELLOW << std::setw(24) << task << COLOR_DEFAULT << ") " - << "TYPE (" << COLOR_YELLOW << std::setw(32) << (*_act_iter)->type() << COLOR_DEFAULT - << ") " - << "NAME (" << COLOR_YELLOW << std::setw(16) << (*_act_iter)->name() << COLOR_DEFAULT - << ") Memory usage " << usage << "MB" << std::endl; + << "TYPE (" << COLOR_YELLOW << std::setw(32) << _current_action->type() + << COLOR_DEFAULT << ") " + << "NAME (" << COLOR_YELLOW << std::setw(16) << _current_action->name() + << COLOR_DEFAULT << ") Memory usage " << usage << "MB" << std::endl; } - (*_act_iter)->timedAct(); + _current_action->timedAct(); } + + _current_action = nullptr; } void @@ -445,7 +449,7 @@ ActionWarehouse::problem() std::string ActionWarehouse::getCurrentActionName() const { - return (*_act_iter)->parameters().blockFullpath(); + return getCurrentAction()->parameters().getHitNode()->fullpath(); } const std::string & diff --git a/framework/src/actions/AddVariableAction.C b/framework/src/actions/AddVariableAction.C index 96f3931f72be..9e5a2fa0ef91 100644 --- a/framework/src/actions/AddVariableAction.C +++ b/framework/src/actions/AddVariableAction.C @@ -175,6 +175,9 @@ AddVariableAction::createInitialConditionAction() InputParameters action_params = _action_factory.getValidParams("AddOutputAction"); action_params.set("awh") = &_awh; + // Associate all action and initial condition errors with "initial_condition" + associateWithParameter("initial_condition", action_params); + bool is_vector = (_fe_type.family == LAGRANGE_VEC || _fe_type.family == NEDELEC_ONE || _fe_type.family == MONOMIAL_VEC || _fe_type.family == RAVIART_THOMAS); diff --git a/framework/src/actions/CommonOutputAction.C b/framework/src/actions/CommonOutputAction.C index e27edc512a0b..81fa33bb9cf3 100644 --- a/framework/src/actions/CommonOutputAction.C +++ b/framework/src/actions/CommonOutputAction.C @@ -172,7 +172,7 @@ CommonOutputAction::act() // Create the actions for the short-cut methods #ifdef LIBMESH_HAVE_EXODUS_API if (getParam("exodus")) - create("Exodus"); + create("Exodus", "exodus"); #else if (getParam("exodus")) mooseWarning("Exodus output requested but not enabled through libMesh"); @@ -180,7 +180,7 @@ CommonOutputAction::act() #ifdef LIBMESH_HAVE_NEMESIS_API if (getParam("nemesis")) - create("Nemesis"); + create("Nemesis", "nemesis"); #else if (getParam("nemesis")) mooseWarning("Nemesis output requested but not enabled through libMesh"); @@ -188,59 +188,91 @@ CommonOutputAction::act() // Only create a Console if screen output was not created if (getParam("console") && !hasConsole()) - create("Console"); + create("Console", "console"); if (getParam("csv")) - create("CSV"); + create("CSV", "csv"); if (getParam("xml")) - create("XMLOutput"); + create("XMLOutput", "xml"); if (getParam("json")) - create("JSON"); + create("JSON", "json"); #ifdef LIBMESH_HAVE_VTK if (getParam("vtk")) - create("VTK"); + create("VTK", "vtk"); #else if (getParam("vtk")) mooseWarning("VTK output requested but not enabled through libMesh"); #endif if (getParam("xda")) - create("XDA"); + create("XDA", "xda"); if (getParam("xdr")) - create("XDR"); + create("XDR", "xdr"); if (getParam("checkpoint")) - create("Checkpoint"); + create("Checkpoint", "checkpoint"); if (getParam("gmv")) - create("GMV"); + create("GMV", "gmv"); if (getParam("tecplot")) - create("Tecplot"); + create("Tecplot", "tecplot"); if (getParam("gnuplot")) - create("Gnuplot"); + create("Gnuplot", "gnuplot"); if (getParam("solution_history")) - create("SolutionHistory"); + create("SolutionHistory", "solution_history"); if (getParam("progress")) - create("Progress"); + create("Progress", "progress"); if (getParam("dofmap")) - create("DOFMap"); - - if (getParam("controls") || _app.getParam("show_controls")) - create("ControlOutput"); - - if (!_app.getParam("no_timing") && - (getParam("perf_graph") || getParam("print_perf_log") || - _app.getParam("timing"))) - create("PerfGraphOutput"); + create("DOFMap", "dofmap"); + + { + std::optional from_param_name; + const InputParameters * from_params = nullptr; + if (getParam("controls")) + { + from_param_name = "controls"; + from_params = ¶meters(); + } + else if (_app.getParam("show_controls")) + { + from_param_name = "show_controls"; + from_params = &_app.parameters(); + } + if (from_param_name) + create("ControlOutput", *from_param_name, from_params); + } + + if (!_app.getParam("no_timing")) + { + std::optional from_param_name; + const InputParameters * from_params = nullptr; + if (getParam("perf_graph")) + { + from_param_name = "perf_graph"; + from_params = ¶meters(); + } + else if (getParam("print_perf_log")) + { + from_param_name = "print_perf_log"; + from_params = ¶meters(); + } + else if (_app.getParam("timing")) + { + from_param_name = "show_controls"; + from_params = &_app.parameters(); + } + if (from_param_name) + create("PerfGraphOutput", *from_param_name, from_params); + } if (!_app.getParam("no_timing") && getParam("perf_graph_live")) perfGraph().setLivePrintActive(true); @@ -271,17 +303,30 @@ CommonOutputAction::act() } void -CommonOutputAction::create(std::string object_type) +CommonOutputAction::create(std::string object_type, + const std::optional & param_name, + const InputParameters * const from_params /* = nullptr */) { + // Create our copy of the parameters + auto params = _action_params; + + // Associate all action output object errors with param_name + // If from_params is specified, it means to associate it with parameters other than parameters() + if (param_name) + { + const InputParameters & associated_params = from_params ? *from_params : parameters(); + associateWithParameter(associated_params, *param_name, params); + } + // Set the 'type =' parameters for the desired object - _action_params.set("type") = object_type; + params.set("type") = object_type; // Create the complete object name (uses lower case of type) std::transform(object_type.begin(), object_type.end(), object_type.begin(), ::tolower); // Create the action std::shared_ptr action = std::static_pointer_cast( - _action_factory.create("AddOutputAction", object_type, _action_params)); + _action_factory.create("AddOutputAction", object_type, params)); // Set flag indicating that the object to be created was created with short-cut syntax action->getObjectParams().set("_built_by_moose") = true; diff --git a/framework/src/actions/CreateExecutionerAction.C b/framework/src/actions/CreateExecutionerAction.C index 18616e62c844..447d28921f39 100644 --- a/framework/src/actions/CreateExecutionerAction.C +++ b/framework/src/actions/CreateExecutionerAction.C @@ -75,6 +75,9 @@ CreateExecutionerAction::setupAutoPreconditioning() InputParameters params = _action_factory.getValidParams("SetupPreconditionerAction"); params.set("type") = "SMP"; + // Associate errors with "solve_type" + associateWithParameter(_moose_object_pars, "solve_type", params); + // Create the Action that will build the Preconditioner object std::shared_ptr ptr = _action_factory.create("SetupPreconditionerAction", "_moose_auto", params); diff --git a/framework/src/actions/ReadExecutorParamsAction.C b/framework/src/actions/ReadExecutorParamsAction.C index 122e2e4fdc92..db7088191eed 100644 --- a/framework/src/actions/ReadExecutorParamsAction.C +++ b/framework/src/actions/ReadExecutorParamsAction.C @@ -60,6 +60,9 @@ ReadExecutorParamsAction::setupAutoPreconditioning() InputParameters params = _action_factory.getValidParams("SetupPreconditionerAction"); params.set("type") = "SMP"; + // Associate errors with "solve_type" + associateWithParameter(_moose_object_pars, "solve_type", params); + // Create the Action that will build the Preconditioner object std::shared_ptr ptr = _action_factory.create("SetupPreconditionerAction", "_moose_auto", params); diff --git a/framework/src/base/AppFactory.C b/framework/src/base/AppFactory.C index 6c35ef60798b..0b6a5f768ac4 100644 --- a/framework/src/base/AppFactory.C +++ b/framework/src/base/AppFactory.C @@ -136,7 +136,7 @@ AppFactory::createShared(const std::string & app_type, parameters.set("_type") = app_type; // Check to make sure that all required parameters are supplied - parameters.checkParams(""); + parameters.finalize(""); auto comm = std::make_shared(comm_world_in); diff --git a/framework/src/base/Factory.C b/framework/src/base/Factory.C index 4b9b4f370b71..4fdd370b1fe5 100644 --- a/framework/src/base/Factory.C +++ b/framework/src/base/Factory.C @@ -82,88 +82,50 @@ Factory::getValidParams(const std::string & obj_name) const return params; } -std::shared_ptr -Factory::create(const std::string & obj_name, - const std::string & name, - const InputParameters & parameters, - THREAD_ID tid /* =0 */, - bool print_deprecated /* =true */) +std::unique_ptr +Factory::createUnique(const std::string & obj_name, + const std::string & name, + const InputParameters & parameters, + THREAD_ID tid /* =0 */, + bool print_deprecated /* =true */) { if (print_deprecated) mooseDeprecated("Factory::create() is deprecated, please use Factory::create() instead"); - // Pointer to the object constructor - const auto it = _name_to_object.find(obj_name); - - // Check if the object is registered - if (it == _name_to_object.end()) - reportUnregisteredError(obj_name); - - // Print out deprecated message, if it exists - deprecatedMessage(obj_name); - - // Create the actual parameters object that the object will reference - InputParameters & params = - _app.getInputParameterWarehouse().addInputParameters(name, parameters, tid); - - // Set the _type parameter - params.set("_type") = obj_name; - - // Check to make sure that all required parameters are supplied - params.checkParams(name); - - // register type name as constructed - _constructed_types.insert(obj_name); - - // add FEProblem pointers to object's params object - if (_app.actionWarehouse().problemBase()) - _app.actionWarehouse().problemBase()->setInputParametersFEProblem(params); + // Build the parameters that are stored in the InputParameterWarehouse for this + // object, set a few other things and do a little error checking + auto & warehouse_params = initialize(obj_name, name, parameters, tid); // call the function pointer to build the object - auto obj = it->second->build(params); + _currently_constructing.push_back(&warehouse_params); + auto obj = _name_to_object.at(obj_name)->build(warehouse_params); + _currently_constructing.pop_back(); - auto fep = std::dynamic_pointer_cast(obj); - if (fep) - _app.actionWarehouse().problemBase() = fep; + finalize(obj_name, *obj); - // Make sure no unexpected parameters were added by the object's constructor or by the action - // initiating this create call. All parameters modified by the constructor must have already - // been specified in the object's validParams function. - InputParameters orig_params = getValidParams(obj_name); - if (orig_params.n_parameters() != parameters.n_parameters()) - { - std::set orig, populated; - for (const auto & it : orig_params) - orig.emplace(it.first); - for (const auto & it : parameters) - populated.emplace(it.first); + return obj; +} - std::set diff; - std::set_difference(populated.begin(), - populated.end(), - orig.begin(), - orig.end(), - std::inserter(diff, diff.begin())); +std::shared_ptr +Factory::create(const std::string & obj_name, + const std::string & name, + const InputParameters & parameters, + THREAD_ID tid /* =0 */, + bool print_deprecated /* =true */) +{ + std::shared_ptr object = + createUnique(obj_name, name, parameters, tid, print_deprecated); - if (!diff.empty()) - { - std::stringstream ss; - for (const auto & name : diff) - ss << ", " << name; - mooseError("attempted to set unregistered parameter(s) for ", - obj_name, - " object:\n ", - ss.str().substr(2)); - } - } + if (auto fep = std::dynamic_pointer_cast(object)) + _app.actionWarehouse().problemBase() = fep; - return obj; + return object; } void Factory::releaseSharedObjects(const MooseObject & moose_object, THREAD_ID tid) { - _app.getInputParameterWarehouse().removeInputParameters(moose_object, tid); + _app.getInputParameterWarehouse().removeInputParameters(moose_object, tid, {}); } void @@ -287,6 +249,12 @@ Factory::getConstructedObjects() const return list; } +const InputParameters * +Factory::currentlyConstructing() const +{ + return _currently_constructing.size() ? _currently_constructing.back() : nullptr; +} + FileLineInfo Factory::getLineInfo(const std::string & name) const { @@ -308,3 +276,80 @@ Factory::associatedClassName(const std::string & name) const else return it->second; } + +InputParameters & +Factory::initialize(const std::string & type, + const std::string & name, + const InputParameters & from_params, + const THREAD_ID tid) +{ + // Pointer to the object constructor + const auto it = _name_to_object.find(type); + + // Check if the object is registered + if (it == _name_to_object.end()) + reportUnregisteredError(type); + + // Print out deprecated message, if it exists + deprecatedMessage(type); + + // Create the actual parameters object that the object will reference + InputParameters & params = + _app.getInputParameterWarehouse().addInputParameters(name, from_params, tid, {}); + + // Add the hit node from the action if it isn't set already (it might be set + // already because someone had a better option than just the action) + // If it isn't set, it typically means that this object was created by a + // non-MooseObjectAction Action + if (!params.getHitNode() || params.getHitNode()->isRoot()) + if (const auto hit_node = _app.getCurrentActionHitNode()) + params.setHitNode(*hit_node, {}); + + // Set the _type parameter + params.set("_type") = type; + + // Check to make sure that all required parameters are supplied + params.finalize(name); + + // register type name as constructed + _constructed_types.insert(type); + + // add FEProblem pointers to object's params object + if (_app.actionWarehouse().problemBase()) + _app.actionWarehouse().problemBase()->setInputParametersFEProblem(params); + + return params; +} + +void +Factory::finalize(const std::string & type, const MooseObject & object) +{ + // Make sure no unexpected parameters were added by the object's constructor or by the action + // initiating this create call. All parameters modified by the constructor must have already + // been specified in the object's validParams function. + InputParameters orig_params = getValidParams(type); + const auto & object_params = object.parameters(); + if (orig_params.n_parameters() != object_params.n_parameters()) + { + std::set orig, populated; + for (const auto & it : orig_params) + orig.emplace(it.first); + for (const auto & it : object_params) + populated.emplace(it.first); + + std::set diff; + std::set_difference(populated.begin(), + populated.end(), + orig.begin(), + orig.end(), + std::inserter(diff, diff.begin())); + + if (!diff.empty()) + { + std::stringstream ss; + for (const auto & name : diff) + ss << ", " << name; + object.mooseError("Attempted to set unregistered parameter(s):\n ", ss.str().substr(2)); + } + } +} diff --git a/framework/src/base/MooseApp.C b/framework/src/base/MooseApp.C index a0a3bcfba150..5533e167a978 100644 --- a/framework/src/base/MooseApp.C +++ b/framework/src/base/MooseApp.C @@ -360,9 +360,11 @@ MooseApp::MooseApp(InputParameters parameters) PerfGraphInterface(*this, "MooseApp"), ParallelObject(*parameters.get>( "_comm")), // Can't call getParam() before pars is set - _name(parameters.get("_app_name")), + MooseBase(parameters.get("_type"), + parameters.get("_app_name"), + *this, + _pars), _pars(parameters), - _type(getParam("_type")), _comm(getParam>("_comm")), _file_base_set_by_user(false), _output_position_set(false), @@ -1046,14 +1048,6 @@ MooseApp::setupOptions() Moose::out << std::flush; } -const std::string & -MooseApp::type() const -{ - if (_parser && _parser->getAppType().size()) - mooseAssert(_parser->getAppType() == _type, "Should be equivalent"); - return _type; -} - const std::vector & MooseApp::getInputFileNames() const { @@ -1348,11 +1342,11 @@ MooseApp::addExecutorParams(const std::string & type, _executor_params[name] = std::make_pair(type, std::make_unique(params)); } -Moose::Builder & +Parser & MooseApp::parser() { - mooseDeprecated("MooseApp::parser() is deprecated, use MooseApp::builder() instead."); - return _builder; + mooseAssert(_parser, "Not set"); + return *_parser; } void @@ -2415,6 +2409,14 @@ MooseApp::restartFolderBase(const std::filesystem::path & folder_base) const return RestartableDataIO::restartableDataFolder(folder); } +const hit::Node * +MooseApp::getCurrentActionHitNode() const +{ + if (const auto action = _action_warehouse.getCurrentAction()) + return action->parameters().getHitNode(); + return nullptr; +} + bool MooseApp::hasRMClone(const RelationshipManager & template_rm, const MeshBase & mesh) const { diff --git a/framework/src/base/MooseBase.C b/framework/src/base/MooseBase.C new file mode 100644 index 000000000000..986332efffeb --- /dev/null +++ b/framework/src/base/MooseBase.C @@ -0,0 +1,56 @@ +//* 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 + +#include "MooseBase.h" + +#include "MooseError.h" +#include "InputParameters.h" +#include "MooseApp.h" + +#include "parse.h" + +MooseBase::MooseBase(const std::string & type, + const std::string & name, + MooseApp & app, + const InputParameters & params) + : _app(app), _type(type), _name(name), _params(params) +{ +} + +std::string +MooseBase::typeAndName() const +{ + return type() + std::string(" \"") + name() + std::string("\""); +} + +[[noreturn]] void +MooseBase::callMooseError(std::string msg, const bool with_prefix) const +{ + _app.getOutputWarehouse().mooseConsole(); + const std::string prefix = _app.isUltimateMaster() ? "" : _app.name(); + if (with_prefix) + msg = errorPrefix("error") + msg; + moose::internal::mooseErrorRaw(msg, prefix); +} + +std::string +MooseBase::errorPrefix(const std::string & error_type) const +{ + std::stringstream oss; + if (const auto node = _params.getHitNode()) + if (!node->isRoot()) + oss << node->fileLocation() << ":\n"; + oss << "The following " << error_type << " occurred in the "; + if (const auto base_ptr = _params.getBase()) + oss << *base_ptr; + else + oss << "object"; + oss << " '" << name() << "' of type " << type() << ".\n\n"; + return oss.str(); +} diff --git a/framework/src/base/MooseBaseErrorInterface.C b/framework/src/base/MooseBaseErrorInterface.C index 86a0b265e931..33b89621cadb 100644 --- a/framework/src/base/MooseBaseErrorInterface.C +++ b/framework/src/base/MooseBaseErrorInterface.C @@ -11,21 +11,9 @@ #include "MooseBase.h" #include "MooseApp.h" -std::string -MooseBaseErrorInterface::errorPrefix(const std::string & error_type) const -{ - std::stringstream oss; - oss << "The following " << error_type << " occurred in the object \"" << _moose_base->name() - << "\", of type \"" << _moose_base->type() << "\".\n\n"; - return oss.str(); -} +#include "parse.h" -[[noreturn]] void -callMooseErrorRaw(std::string & msg, MooseApp * app) +MooseBaseErrorInterface::MooseBaseErrorInterface(const MooseBase & base) + : ConsoleStreamInterface(base.getMooseApp()), _moose_base(base) { - app->getOutputWarehouse().mooseConsole(); - std::string prefix; - if (!app->isUltimateMaster()) - prefix = app->name(); - moose::internal::mooseErrorRaw(msg, prefix); } diff --git a/framework/src/base/MooseBaseParameterInterface.C b/framework/src/base/MooseBaseParameterInterface.C index 74203eafef92..af3743ecedeb 100644 --- a/framework/src/base/MooseBaseParameterInterface.C +++ b/framework/src/base/MooseBaseParameterInterface.C @@ -7,12 +7,9 @@ //* Licensed under LGPL 2.1, please see LICENSE for details //* https://www.gnu.org/licenses/lgpl-2.1.html -// MOOSE includes #include "MooseBaseParameterInterface.h" -#include "MooseObjectParameterName.h" + #include "MooseApp.h" -#include "MooseUtils.h" -#include "MooseBase.h" #include "InputParameterWarehouse.h" std::string @@ -21,13 +18,15 @@ paramErrorPrefix(const InputParameters & params, const std::string & param) return params.errorPrefix(param); } -MooseBaseParameterInterface::MooseBaseParameterInterface(const InputParameters & parameters, - const MooseBase * const base) +MooseBaseParameterInterface::MooseBaseParameterInterface(const MooseBase & base, + const InputParameters & parameters) : _pars(parameters), - _factory(base->getMooseApp().getFactory()), - _action_factory(base->getMooseApp().getActionFactory()), + _factory(base.getMooseApp().getFactory()), + _action_factory(base.getMooseApp().getActionFactory()), _moose_base(base) { + // This enforces that we call finalizeParams (checkParams() and setting file paths) + mooseAssert(_pars.isFinalized(), "Params are not finalized"); } void @@ -39,7 +38,7 @@ MooseBaseParameterInterface::connectControllableParams(const std::string & param MooseObjectParameterName primary_name(uniqueName(), parameter); const auto base_type = _factory.getValidParams(object_type).get("_moose_base"); MooseObjectParameterName secondary_name(base_type, object_name, object_parameter); - _moose_base->getMooseApp().getInputParameterWarehouse().addControllableParameterConnection( + _moose_base.getMooseApp().getInputParameterWarehouse().addControllableParameterConnection( primary_name, secondary_name); const auto & tags = _pars.get>("control_tags"); @@ -47,18 +46,9 @@ MooseBaseParameterInterface::connectControllableParams(const std::string & param { if (!tag.empty()) { - MooseObjectParameterName tagged_name(tag, _moose_base->name(), parameter); - _moose_base->getMooseApp().getInputParameterWarehouse().addControllableParameterConnection( + MooseObjectParameterName tagged_name(tag, _moose_base.name(), parameter); + _moose_base.getMooseApp().getInputParameterWarehouse().addControllableParameterConnection( tagged_name, secondary_name); } } } - -std::string -MooseBaseParameterInterface::objectErrorPrefix(const std::string & error_type) const -{ - std::stringstream oss; - oss << "The following " << error_type << " occurred in the class \"" << _moose_base->name() - << "\", of type \"" << _moose_base->type() << "\".\n\n"; - return oss.str(); -} diff --git a/framework/src/base/MooseObject.C b/framework/src/base/MooseObject.C index 1378885aec1b..5a59d51a4499 100644 --- a/framework/src/base/MooseObject.C +++ b/framework/src/base/MooseObject.C @@ -11,6 +11,7 @@ #include "MooseObject.h" #include "MooseApp.h" #include "MooseUtils.h" +#include "Factory.h" class FEProblem; class FEProblemBase; @@ -47,11 +48,15 @@ MooseObject::validParams() MooseObject::MooseObject(const InputParameters & parameters) : MooseBase(parameters.get("_type"), parameters.get("_object_name"), - *parameters.getCheckedPointerParam("_moose_app")), - MooseBaseParameterInterface(parameters, this), - MooseBaseErrorInterface(this), + *parameters.getCheckedPointerParam("_moose_app"), + parameters), + MooseBaseParameterInterface(*this, parameters), + MooseBaseErrorInterface(static_cast(*this)), ParallelObject(*parameters.getCheckedPointerParam("_moose_app")), DataFileInterface(*this), _enabled(getParam("enable")) { + if (Registry::isRegisteredObj(type()) && _app.getFactory().currentlyConstructing() != ¶meters) + mooseError( + "This registered object was not constructed using the Factory, which is not supported."); } diff --git a/framework/src/base/MooseServer.C b/framework/src/base/MooseServer.C index 2c99182e17f8..e15616b57df2 100644 --- a/framework/src/base/MooseServer.C +++ b/framework/src/base/MooseServer.C @@ -58,7 +58,8 @@ MooseServer::parseDocumentForDiagnostics(wasp::DataArray & diagnosticsList) pcrecpp::RE("(.*://)(.*)").Replace("\\2", &parse_file_path); // copy parent application parameters and modify to set up input check - InputParameters app_params = _moose_app.parameters(); + InputParameters app_params = AppFactory::instance().getValidParams(_moose_app.type()); + app_params.applyParameters(_moose_app.parameters()); app_params.set("check_input") = true; app_params.set("error_unused") = true; app_params.set("error") = true; @@ -66,8 +67,7 @@ MooseServer::parseDocumentForDiagnostics(wasp::DataArray & diagnosticsList) app_params.set("disable_perf_graph_live") = true; app_params.set>("_parser") = std::make_shared(parse_file_path, document_text); - - app_params.remove("language_server"); + app_params.set>("_command_line") = _moose_app.commandLine(); // turn output off so input check application does not affect messages std::streambuf * cached_output_buffer = Moose::out.rdbuf(nullptr); diff --git a/framework/src/constraints/AutomaticMortarGeneration.C b/framework/src/constraints/AutomaticMortarGeneration.C index 464ac0a1cafc..73087c20458e 100644 --- a/framework/src/constraints/AutomaticMortarGeneration.C +++ b/framework/src/constraints/AutomaticMortarGeneration.C @@ -258,6 +258,7 @@ AutomaticMortarGeneration::initOutput() std::to_string(_primary_secondary_boundary_id_pairs.front().first) + std::to_string(_primary_secondary_boundary_id_pairs.front().second) + "_" + (_on_displaced ? "displaced" : "undisplaced"); + _output_params->finalize("MortarNodalGeometryOutput"); _app.getOutputWarehouse().addOutput(std::make_shared(*_output_params)); } diff --git a/framework/src/interfaces/DataFileInterface.C b/framework/src/interfaces/DataFileInterface.C index 5b2e56cf4a93..730f8ee83b0b 100644 --- a/framework/src/interfaces/DataFileInterface.C +++ b/framework/src/interfaces/DataFileInterface.C @@ -12,6 +12,8 @@ #include "MooseObject.h" #include "Action.h" +#include + template DataFileInterface::DataFileInterface(const T & parent) : _parent(parent) { @@ -21,18 +23,29 @@ template std::string DataFileInterface::getDataFileName(const std::string & param) const { - /// - relative to the input file directory + // The path from the parameters, which has not been modified because it is a DataFileName + const auto & value = _parent.template getParam(param); + if (value.empty()) + _parent.paramInfo(param, "Data file name is empty"); + + const std::filesystem::path value_path = std::filesystem::path(std::string(value)); + + // If the file is absolute, we should reference that directly and don't need to add + // any info beacuse this is not ambiguous + if (value_path.is_absolute() && MooseUtils::checkFileReadable(value, false, false, false)) + return value; + + // Look relative to the input file + const auto base = _parent.parameters().getParamFileBase(param); + const std::string relative_to_context = std::filesystem::absolute(base / value_path).c_str(); + if (MooseUtils::checkFileReadable(relative_to_context, false, false, false)) { - const auto & absolute_path = _parent.template getParam(param); - if (MooseUtils::checkFileReadable(absolute_path, false, false, false)) - { - _parent.paramInfo(param, "Data file '", absolute_path, "' found relative to the input file."); - return absolute_path; - } + _parent.paramInfo(param, "Data file '", value, "' found relative to the input file."); + return relative_to_context; } - const auto & relative_path = _parent.parameters().rawParamVal(param); - return getDataFileNameByName(relative_path, ¶m); + // Isn't absolute and couldn't find relative to the input file, so search the data + return getDataFileNameByName(value, ¶m); } template diff --git a/framework/src/mesh/AnnularMesh.C b/framework/src/mesh/AnnularMesh.C index af6b8708ad39..d0eccd1d7c57 100644 --- a/framework/src/mesh/AnnularMesh.C +++ b/framework/src/mesh/AnnularMesh.C @@ -9,6 +9,8 @@ #include "AnnularMesh.h" +#include "MooseApp.h" + #include "libmesh/face_quad4.h" #include "libmesh/face_tri3.h" @@ -153,7 +155,7 @@ AnnularMesh::getMaxInDimension(unsigned int component) const std::unique_ptr AnnularMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/ConcentricCircleMesh.C b/framework/src/mesh/ConcentricCircleMesh.C index 5915ecbf4a7c..78bb831aa7bf 100644 --- a/framework/src/mesh/ConcentricCircleMesh.C +++ b/framework/src/mesh/ConcentricCircleMesh.C @@ -10,6 +10,7 @@ #include "ConcentricCircleMesh.h" #include "libmesh/face_quad4.h" #include "MooseMesh.h" +#include "MooseApp.h" #include "libmesh/mesh_modification.h" #include "libmesh/serial_mesh.h" #include "libmesh/boundary_info.h" @@ -95,6 +96,12 @@ ConcentricCircleMesh::ConcentricCircleMesh(const InputParameters & parameters) mooseError("The pitch / 2 must be larger than any radii."); } +std::unique_ptr +ConcentricCircleMesh::safeClone() const +{ + return _app.getFactory().copyConstruct(*this); +} + void ConcentricCircleMesh::buildMesh() { diff --git a/framework/src/mesh/FileMesh.C b/framework/src/mesh/FileMesh.C index 128a754e43b0..e4cd77da1ca7 100644 --- a/framework/src/mesh/FileMesh.C +++ b/framework/src/mesh/FileMesh.C @@ -52,7 +52,7 @@ FileMesh::~FileMesh() {} std::unique_ptr FileMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/GeneratedMesh.C b/framework/src/mesh/GeneratedMesh.C index 6206d5d69e29..daa5d0e07278 100644 --- a/framework/src/mesh/GeneratedMesh.C +++ b/framework/src/mesh/GeneratedMesh.C @@ -9,6 +9,8 @@ #include "GeneratedMesh.h" +#include "MooseApp.h" + #include "libmesh/mesh_generation.h" #include "libmesh/string_to_enum.h" #include "libmesh/periodic_boundaries.h" @@ -150,7 +152,7 @@ GeneratedMesh::getMaxInDimension(unsigned int component) const std::unique_ptr GeneratedMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/ImageMesh.C b/framework/src/mesh/ImageMesh.C index 0986fbcf6392..bab4d4b441cc 100644 --- a/framework/src/mesh/ImageMesh.C +++ b/framework/src/mesh/ImageMesh.C @@ -58,7 +58,7 @@ ImageMesh::ImageMesh(const ImageMesh & other_mesh) std::unique_ptr ImageMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/MeshGeneratorMesh.C b/framework/src/mesh/MeshGeneratorMesh.C index ee79db77b223..6f9d5de6f1e1 100644 --- a/framework/src/mesh/MeshGeneratorMesh.C +++ b/framework/src/mesh/MeshGeneratorMesh.C @@ -10,6 +10,7 @@ #include "MeshGeneratorMesh.h" #include "MeshGeneratorSystem.h" +#include "MooseApp.h" #include "libmesh/face_quad4.h" #include "libmesh/face_tri3.h" @@ -37,7 +38,7 @@ MeshGeneratorMesh::MeshGeneratorMesh(const InputParameters & parameters) : Moose std::unique_ptr MeshGeneratorMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/PatternedMesh.C b/framework/src/mesh/PatternedMesh.C index 24c7d2fffede..d113d7155bd5 100644 --- a/framework/src/mesh/PatternedMesh.C +++ b/framework/src/mesh/PatternedMesh.C @@ -10,6 +10,7 @@ #include "PatternedMesh.h" #include "Parser.h" #include "InputParameters.h" +#include "MooseApp.h" #include "libmesh/mesh_modification.h" #include "libmesh/serial_mesh.h" @@ -79,7 +80,7 @@ PatternedMesh::PatternedMesh(const PatternedMesh & other_mesh) std::unique_ptr PatternedMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/RinglebMesh.C b/framework/src/mesh/RinglebMesh.C index ee2701ca3e64..3a11c1e0c190 100644 --- a/framework/src/mesh/RinglebMesh.C +++ b/framework/src/mesh/RinglebMesh.C @@ -9,6 +9,8 @@ #include "RinglebMesh.h" +#include "MooseApp.h" + #include "libmesh/face_quad4.h" #include "libmesh/face_tri3.h" #include "libmesh/mesh_modification.h" @@ -64,7 +66,7 @@ RinglebMesh::RinglebMesh(const InputParameters & parameters) std::unique_ptr RinglebMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } std::vector diff --git a/framework/src/mesh/SpiralAnnularMesh.C b/framework/src/mesh/SpiralAnnularMesh.C index 845836890557..829d74685dd4 100644 --- a/framework/src/mesh/SpiralAnnularMesh.C +++ b/framework/src/mesh/SpiralAnnularMesh.C @@ -9,6 +9,8 @@ #include "SpiralAnnularMesh.h" +#include "MooseApp.h" + #include "libmesh/face_quad4.h" #include "libmesh/face_tri3.h" @@ -65,7 +67,7 @@ SpiralAnnularMesh::SpiralAnnularMesh(const InputParameters & parameters) std::unique_ptr SpiralAnnularMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/StitchedMesh.C b/framework/src/mesh/StitchedMesh.C index c966205f8686..e904412f24fc 100644 --- a/framework/src/mesh/StitchedMesh.C +++ b/framework/src/mesh/StitchedMesh.C @@ -11,6 +11,8 @@ #include "Parser.h" #include "InputParameters.h" +#include "MooseApp.h" + #include "libmesh/mesh_modification.h" #include "libmesh/serial_mesh.h" #include "libmesh/exodusII_io.h" @@ -74,7 +76,7 @@ StitchedMesh::StitchedMesh(const StitchedMesh & other_mesh) std::unique_ptr StitchedMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/framework/src/mesh/TiledMesh.C b/framework/src/mesh/TiledMesh.C index d7f97ea3a989..0dfd20ddcb8d 100644 --- a/framework/src/mesh/TiledMesh.C +++ b/framework/src/mesh/TiledMesh.C @@ -10,6 +10,7 @@ #include "TiledMesh.h" #include "Parser.h" #include "InputParameters.h" +#include "MooseApp.h" #include "libmesh/mesh_modification.h" #include "libmesh/serial_mesh.h" @@ -79,7 +80,7 @@ TiledMesh::TiledMesh(const TiledMesh & other_mesh) std::unique_ptr TiledMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } std::string diff --git a/framework/src/outputs/OversampleOutput.C b/framework/src/outputs/OversampleOutput.C index f143fab07b99..4569430b07f6 100644 --- a/framework/src/outputs/OversampleOutput.C +++ b/framework/src/outputs/OversampleOutput.C @@ -11,7 +11,6 @@ #include "OversampleOutput.h" #include "FEProblem.h" #include "DisplacedProblem.h" -#include "FileMesh.h" #include "MooseApp.h" #include "libmesh/distributed_mesh.h" @@ -270,13 +269,11 @@ OversampleOutput::cloneMesh() // Create the new mesh from a file if (isParamValid("file")) { - InputParameters mesh_params = emptyInputParameters(); - mesh_params += _mesh_ptr->parameters(); - mesh_params.set("file") = getParam("file"); + InputParameters mesh_params = _app.getFactory().getValidParams("FileMesh"); + mesh_params.applyParameters(parameters(), {}, true); mesh_params.set("nemesis") = false; - mesh_params.set("skip_partitioning") = false; - mesh_params.set("_object_name") = "output_problem_mesh"; - _cloned_mesh_ptr = std::make_unique(mesh_params); + _cloned_mesh_ptr = + _app.getFactory().createUnique("FileMesh", "output_problem_mesh", mesh_params); _cloned_mesh_ptr->allowRecovery(false); // We actually want to reread the initial mesh _cloned_mesh_ptr->init(); _cloned_mesh_ptr->prepare(/*mesh_to_clone=*/nullptr); diff --git a/framework/src/parser/Builder.C b/framework/src/parser/Builder.C index 3150d74c1b1c..74b992ae20ed 100644 --- a/framework/src/parser/Builder.C +++ b/framework/src/parser/Builder.C @@ -258,16 +258,14 @@ Builder::walkRaw(std::string /*fullpath*/, std::string /*nodepath*/, hit::Node * hit::errormsg(n, _syntax.deprecatedActionSyntaxMessage(registered_identifier))); params = _action_factory.getValidParams(it->second._action); - params.set("awh") = &_action_wh; + params.setHitNode(*n, {}); extractParams(curr_identifier, params); // Add the parsed syntax to the parameters object for consumption by the Action params.set("task") = it->second._task; params.set("registered_identifier") = registered_identifier; - params.blockLocation() = n->filename() + ":" + std::to_string(n->line()); - params.blockFullpath() = n->fullpath(); if (!(params.have_parameter("isObjectAction") && params.get("isObjectAction"))) params.set>("control_tags") @@ -283,11 +281,10 @@ Builder::walkRaw(std::string /*fullpath*/, std::string /*nodepath*/, hit::Node * std::dynamic_pointer_cast(action_obj); if (object_action) { - object_action->getObjectParams().blockLocation() = params.blockLocation(); - object_action->getObjectParams().blockFullpath() = params.blockFullpath(); - extractParams(curr_identifier, object_action->getObjectParams()); - object_action->getObjectParams() - .set>("control_tags") + auto & object_params = object_action->getObjectParams(); + object_params.setHitNode(*n, {}); + extractParams(curr_identifier, object_params); + object_params.set>("control_tags") .push_back(MooseUtils::baseName(curr_identifier)); } } @@ -953,8 +950,7 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) auto node = root()->find(full_name); if (node && node->type() == hit::NodeType::Field) { - p.inputLocation(param_name) = node->filename() + ":" + std::to_string(node->line()); - p.paramFullpath(param_name) = full_name; + p.setHitNode(param_name, *node, {}); p.set_attributes(param_name, false); // Check if we have already printed the deprecated param message. // If we haven't, add it to the tracker, and print it. @@ -972,8 +968,7 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) node = root()->find(full_name); if (node) { - p.inputLocation(param_name) = node->filename() + ":" + std::to_string(node->line()); - p.paramFullpath(param_name) = full_name; + p.setHitNode(param_name, *node, {}); p.set_attributes(param_name, false); _extracted_vars.insert( full_name); // Keep track of all variables extracted from the input file @@ -1009,14 +1004,6 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) dynamic_cast *>(par), \ in_global, \ global_params_block) -#define setfpath(ptype) \ - else if (par->type() == demangle(typeid(ptype).name())) \ - setFilePathParam(full_name, \ - short_name, \ - dynamic_cast *>(par), \ - p, \ - in_global, \ - global_params_block) #define setvector(ptype, base) \ else if (par->type() == demangle(typeid(std::vector).name())) \ setVectorParameter( \ @@ -1033,15 +1020,6 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) dynamic_cast> *>(par), \ in_global, \ global_params_block) -#define setvectorfpath(ptype) \ - else if (par->type() == demangle(typeid(std::vector).name())) \ - setVectorFilePathParam( \ - full_name, \ - short_name, \ - dynamic_cast> *>(par), \ - p, \ - in_global, \ - global_params_block) #define setvectorvector(ptype) \ else if (par->type() == demangle(typeid(std::vector>).name())) \ setDoubleIndexParameter( \ @@ -1084,10 +1062,11 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) setscalar(string, string); setscalar(SubdomainName, string); setscalar(BoundaryName, string); - setfpath(FileName); - setfpath(MeshFileName); + setscalar(FileName, string); + setscalar(MeshFileName, string); + setscalar(FileNameNoExtension, string); setscalar(RelativeFileName, string); - setfpath(FileNameNoExtension); + setscalar(DataFileName, string); setscalar(PhysicsName, string); setscalar(OutFileBase, string); setscalar(VariableName, string); @@ -1154,10 +1133,11 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) setvector(MooseEnum, MooseEnum); setvector(string, string); - setvectorfpath(FileName); - setvectorfpath(FileNameNoExtension); + setvector(FileName, string); + setvector(FileNameNoExtension, string); setvector(RelativeFileName, string); - setvectorfpath(MeshFileName); + setvector(DataFileName, string); + setvector(MeshFileName, string); setvector(SubdomainName, string); setvector(BoundaryName, string); setvector(NonlinearVariableName, string); @@ -1214,6 +1194,7 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) setvectorvector(string); setvectorvector(FileName); setvectorvector(FileNameNoExtension); + setvectorvector(DataFileName); setvectorvector(MeshFileName); setvectorvector(SubdomainName); setvectorvector(BoundaryName); @@ -1253,6 +1234,7 @@ Builder::extractParams(const std::string & prefix, InputParameters & p) setvectorvectorvector(string); setvectorvectorvector(FileName); setvectorvectorvector(FileNameNoExtension); + setvectorvectorvector(DataFileName); setvectorvectorvector(MeshFileName); setvectorvectorvector(SubdomainName); setvectorvectorvector(BoundaryName); @@ -1422,32 +1404,6 @@ Builder::setScalarParameter(const std::string & full_name, } } -template -void -Builder::setFilePathParam(const std::string & full_name, - const std::string & short_name, - InputParameters::Parameter * param, - InputParameters & params, - bool in_global, - GlobalParamsAction * global_block) -{ - std::string prefix; - std::string postfix = root()->param(full_name); - auto input_filename = getPrimaryFileName(false); - size_t pos = input_filename.find_last_of('/'); - if (pos != std::string::npos && postfix[0] != '/' && !postfix.empty()) - prefix = input_filename.substr(0, pos + 1); - - params.rawParamVal(short_name) = postfix; - param->set() = prefix + postfix; - - if (in_global) - { - global_block->remove(short_name); - global_block->setScalarParam(short_name) = param->get(); - } -} - template void Builder::setScalarValueTypeParameter(const std::string & full_name, @@ -1601,45 +1557,6 @@ Builder::setMapParameter(const std::string & full_name, } } -template -void -Builder::setVectorFilePathParam(const std::string & full_name, - const std::string & short_name, - InputParameters::Parameter> * param, - InputParameters & params, - bool in_global, - GlobalParamsAction * global_block) -{ - std::vector vec; - std::vector rawvec; - auto input_filename = getPrimaryFileName(false); - if (root()->find(full_name)) - { - auto tmp = root()->param>(full_name); - params.rawParamVal(short_name) = root()->param(full_name); - for (auto val : tmp) - { - std::string prefix; - std::string postfix = val; - size_t pos = input_filename.find_last_of('/'); - if (pos != std::string::npos && postfix[0] != '/') - prefix = input_filename.substr(0, pos + 1); - rawvec.push_back(postfix); - vec.push_back(prefix + postfix); - } - } - - param->set() = vec; - - if (in_global) - { - global_block->remove(short_name); - global_block->setVectorParam(short_name).resize(param->get().size()); - for (unsigned int i = 0; i < vec.size(); ++i) - global_block->setVectorParam(short_name)[i] = param->get()[i]; - } -} - template void Builder::setDoubleIndexParameter(const std::string & full_name, diff --git a/framework/src/parser/Parser.C b/framework/src/parser/Parser.C index 8ded8960d411..0b12c14e1629 100644 --- a/framework/src/parser/Parser.C +++ b/framework/src/parser/Parser.C @@ -151,16 +151,19 @@ UnitsConversionEvaler::eval(hit::Field * n, return ss.str(); } -Parser::Parser(const std::vector & input_filenames) - : _root(nullptr), _input_filenames(input_filenames), _input_text(), _app_type(std::string()) +Parser::Parser(const std::vector & input_filenames, + const std::optional> & input_text) + : _root(nullptr), + _input_filenames(input_filenames), + _input_text(input_text), + _app_type(std::string()) { } Parser::Parser(const std::string & input_filename, const std::optional & input_text) - : _root(nullptr), - _input_filenames({input_filename}), - _input_text(input_text), - _app_type(std::string()) + : Parser(std::vector{input_filename}, + input_text ? std::optional>({*input_text}) + : std::optional>()) { } @@ -290,9 +293,8 @@ Parser::parse() { _root.reset(); - if (_input_text) - mooseAssert(getInputFileNames().size() == 1, - "Should have only one filename with text provided"); + if (_input_text && _input_text->size() != getInputFileNames().size()) + mooseError("Input text is not the same size as the input filenames"); if (getInputFileNames().size() > 1) mooseInfo("Merging inputs ", Moose::stringify(getInputFileNames())); @@ -309,16 +311,17 @@ Parser::parse() std::getenv("MOOSE_RELATIVE_FILEPATHS") ? std::getenv("MOOSE_RELATIVE_FILEPATHS") : "false"; const auto use_real_paths = use_rel_paths_str == "0" || use_rel_paths_str == "false"; - for (const auto & input_filename : getInputFileNames()) + for (const auto i : index_range(getInputFileNames())) { + const auto & input_filename = getInputFileNames()[i]; const auto corrected_filename = use_real_paths ? MooseUtils::realpath(input_filename) : input_filename; // Parse the input text string if provided, otherwise read file from disk std::string input; std::string errmsg; - if (_input_text.has_value()) - input = _input_text.value(); + if (_input_text) + input = (*_input_text)[i]; else { MooseUtils::checkFileReadable(corrected_filename, true); diff --git a/framework/src/partitioner/BlockWeightedPartitioner.C b/framework/src/partitioner/BlockWeightedPartitioner.C index 2f6118253b61..67be332714f7 100644 --- a/framework/src/partitioner/BlockWeightedPartitioner.C +++ b/framework/src/partitioner/BlockWeightedPartitioner.C @@ -9,6 +9,7 @@ #include "BlockWeightedPartitioner.h" #include "MooseMeshUtils.h" +#include "MooseApp.h" #include "libmesh/elem.h" @@ -48,7 +49,7 @@ BlockWeightedPartitioner::BlockWeightedPartitioner(const InputParameters & param std::unique_ptr BlockWeightedPartitioner::clone() const { - return std::make_unique(_pars); + return _app.getFactory().clone(*this); } void diff --git a/framework/src/partitioner/GridPartitioner.C b/framework/src/partitioner/GridPartitioner.C index 2aefea3bed13..40903a3d9d40 100644 --- a/framework/src/partitioner/GridPartitioner.C +++ b/framework/src/partitioner/GridPartitioner.C @@ -48,7 +48,7 @@ GridPartitioner::~GridPartitioner() {} std::unique_ptr GridPartitioner::clone() const { - return std::make_unique(_pars); + return _app.getFactory().clone(*this); } void diff --git a/framework/src/partitioner/HierarchicalGridPartitioner.C b/framework/src/partitioner/HierarchicalGridPartitioner.C index c168a15e2d30..ca21d5b24d81 100644 --- a/framework/src/partitioner/HierarchicalGridPartitioner.C +++ b/framework/src/partitioner/HierarchicalGridPartitioner.C @@ -65,7 +65,7 @@ HierarchicalGridPartitioner::~HierarchicalGridPartitioner() {} std::unique_ptr HierarchicalGridPartitioner::clone() const { - return std::make_unique(_pars); + return _app.getFactory().clone(*this); } void diff --git a/framework/src/partitioner/LibmeshPartitioner.C b/framework/src/partitioner/LibmeshPartitioner.C index 41be89a66b88..739b644bd74f 100644 --- a/framework/src/partitioner/LibmeshPartitioner.C +++ b/framework/src/partitioner/LibmeshPartitioner.C @@ -9,7 +9,9 @@ #include "LibmeshPartitioner.h" +#include "MooseApp.h" #include "MooseMeshUtils.h" + #include "libmesh/linear_partitioner.h" #include "libmesh/centroid_partitioner.h" #include "libmesh/parmetis_partitioner.h" @@ -129,7 +131,7 @@ LibmeshPartitioner::clone() const return std::make_unique(); case 4: // subdomain_partitioner - return std::make_unique(parameters()); + return _app.getFactory().clone(*this); } // this cannot happen but I need to trick the compiler into // believing me diff --git a/framework/src/partitioner/PetscExternalPartitioner.C b/framework/src/partitioner/PetscExternalPartitioner.C index b61dc2bbe5b7..302870ad551b 100644 --- a/framework/src/partitioner/PetscExternalPartitioner.C +++ b/framework/src/partitioner/PetscExternalPartitioner.C @@ -65,7 +65,7 @@ PetscExternalPartitioner::PetscExternalPartitioner(const InputParameters & param std::unique_ptr PetscExternalPartitioner::clone() const { - return std::make_unique(_pars); + return _app.getFactory().clone(*this); } void diff --git a/framework/src/partitioner/RandomPartitioner.C b/framework/src/partitioner/RandomPartitioner.C index 2eb1b21a8adc..4b51d499b1e8 100644 --- a/framework/src/partitioner/RandomPartitioner.C +++ b/framework/src/partitioner/RandomPartitioner.C @@ -40,7 +40,7 @@ RandomPartitioner::~RandomPartitioner() {} std::unique_ptr RandomPartitioner::clone() const { - return std::make_unique(_pars); + return _app.getFactory().clone(*this); } void diff --git a/framework/src/partitioner/SingleRankPartitioner.C b/framework/src/partitioner/SingleRankPartitioner.C index e7155b50db80..8bd8c07ebfed 100644 --- a/framework/src/partitioner/SingleRankPartitioner.C +++ b/framework/src/partitioner/SingleRankPartitioner.C @@ -9,6 +9,8 @@ #include "SingleRankPartitioner.h" +#include "MooseApp.h" + #include "libmesh/elem.h" registerMooseObject("MooseApp", SingleRankPartitioner); @@ -35,7 +37,7 @@ SingleRankPartitioner::SingleRankPartitioner(const InputParameters & params) std::unique_ptr SingleRankPartitioner::clone() const { - return std::make_unique(_pars); + return _app.getFactory().clone(*this); } void diff --git a/framework/src/problems/FEProblemBase.C b/framework/src/problems/FEProblemBase.C index c19e25553b78..60df51347c6d 100644 --- a/framework/src/problems/FEProblemBase.C +++ b/framework/src/problems/FEProblemBase.C @@ -3805,7 +3805,7 @@ FEProblemBase::addReporter(const std::string & type, addUserObject(type, name, parameters); } -void +std::vector> FEProblemBase::addUserObject(const std::string & user_object_name, const std::string & name, InputParameters & parameters) @@ -3875,6 +3875,8 @@ FEProblemBase::addUserObject(const std::string & user_object_name, if (_displaced_problem) _displaced_problem->addFunctor(name, *functor, tid); } + + return uos; } const UserObject & @@ -5426,6 +5428,7 @@ FEProblemBase::addAnyRedistributers() redistribute_params.set("rm_type") = Moose::RelationshipManagerType::GEOMETRIC; redistribute_params.set("use_displaced_mesh") = use_displaced_mesh; + redistribute_params.setHitNode(*parameters().getHitNode(), {}); std::shared_ptr redistributer = _factory.create( diff --git a/framework/src/relationshipmanagers/AugmentSparsityOnInterface.C b/framework/src/relationshipmanagers/AugmentSparsityOnInterface.C index 19766d1f9026..ba2b8ca6ff75 100644 --- a/framework/src/relationshipmanagers/AugmentSparsityOnInterface.C +++ b/framework/src/relationshipmanagers/AugmentSparsityOnInterface.C @@ -398,3 +398,9 @@ AugmentSparsityOnInterface::operator>=(const RelationshipManager & other) const } return false; } + +std::unique_ptr +AugmentSparsityOnInterface::clone() const +{ + return _app.getFactory().copyConstruct(*this); +} diff --git a/framework/src/relationshipmanagers/ElementPointNeighborLayers.C b/framework/src/relationshipmanagers/ElementPointNeighborLayers.C index 820f1125fa77..8190433b5e07 100644 --- a/framework/src/relationshipmanagers/ElementPointNeighborLayers.C +++ b/framework/src/relationshipmanagers/ElementPointNeighborLayers.C @@ -44,7 +44,7 @@ ElementPointNeighborLayers::ElementPointNeighborLayers(const ElementPointNeighbo std::unique_ptr ElementPointNeighborLayers::clone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } std::string diff --git a/framework/src/relationshipmanagers/ElementSideNeighborLayers.C b/framework/src/relationshipmanagers/ElementSideNeighborLayers.C index b8bbc8d23cd7..65d3b6c9b64b 100644 --- a/framework/src/relationshipmanagers/ElementSideNeighborLayers.C +++ b/framework/src/relationshipmanagers/ElementSideNeighborLayers.C @@ -57,7 +57,7 @@ ElementSideNeighborLayers::ElementSideNeighborLayers(const ElementSideNeighborLa std::unique_ptr ElementSideNeighborLayers::clone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } std::string diff --git a/framework/src/relationshipmanagers/GhostEverything.C b/framework/src/relationshipmanagers/GhostEverything.C index 9fc08fc9570f..43b49a84252c 100644 --- a/framework/src/relationshipmanagers/GhostEverything.C +++ b/framework/src/relationshipmanagers/GhostEverything.C @@ -61,3 +61,9 @@ GhostEverything::operator>=(const RelationshipManager & other) const { return dynamic_cast(&other); } + +std::unique_ptr +GhostEverything::clone() const +{ + return _app.getFactory().copyConstruct(*this); +} diff --git a/framework/src/relationshipmanagers/GhostHigherDLowerDPointNeighbors.C b/framework/src/relationshipmanagers/GhostHigherDLowerDPointNeighbors.C index be64b1480b52..3d3bb9d46435 100644 --- a/framework/src/relationshipmanagers/GhostHigherDLowerDPointNeighbors.C +++ b/framework/src/relationshipmanagers/GhostHigherDLowerDPointNeighbors.C @@ -94,3 +94,9 @@ GhostHigherDLowerDPointNeighbors::operator>=(const RelationshipManager & other) return dynamic_cast(&other) || dynamic_cast(&other); } + +std::unique_ptr +GhostHigherDLowerDPointNeighbors::clone() const +{ + return _app.getFactory().copyConstruct(*this); +} diff --git a/framework/src/relationshipmanagers/GhostLowerDElems.C b/framework/src/relationshipmanagers/GhostLowerDElems.C index 200df39a70d5..b3ccf0ac05aa 100644 --- a/framework/src/relationshipmanagers/GhostLowerDElems.C +++ b/framework/src/relationshipmanagers/GhostLowerDElems.C @@ -76,3 +76,9 @@ GhostLowerDElems::operator>=(const RelationshipManager & other) const { return dynamic_cast(&other); } + +std::unique_ptr +GhostLowerDElems::clone() const +{ + return _app.getFactory().copyConstruct(*this); +} diff --git a/framework/src/relationshipmanagers/ProxyRelationshipManager.C b/framework/src/relationshipmanagers/ProxyRelationshipManager.C index 8b89181b3d29..3c83a06186ca 100644 --- a/framework/src/relationshipmanagers/ProxyRelationshipManager.C +++ b/framework/src/relationshipmanagers/ProxyRelationshipManager.C @@ -111,3 +111,9 @@ ProxyRelationshipManager::operator>=(const RelationshipManager & /*rhs*/) const // There isn't a need to determine these because only the correct ones will be added return false; } + +std::unique_ptr +ProxyRelationshipManager::clone() const +{ + return _app.getFactory().copyConstruct(*this); +} diff --git a/framework/src/relationshipmanagers/RedistributeProperties.C b/framework/src/relationshipmanagers/RedistributeProperties.C index bfb1b8b85493..82d08310d800 100644 --- a/framework/src/relationshipmanagers/RedistributeProperties.C +++ b/framework/src/relationshipmanagers/RedistributeProperties.C @@ -39,7 +39,7 @@ RedistributeProperties::operator()(const MeshBase::const_element_iterator &, std::unique_ptr RedistributeProperties::clone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } std::string diff --git a/framework/src/utils/InputParameterWarehouse.C b/framework/src/utils/InputParameterWarehouse.C index 98ed56782a95..7b95856ba09e 100644 --- a/framework/src/utils/InputParameterWarehouse.C +++ b/framework/src/utils/InputParameterWarehouse.C @@ -19,7 +19,8 @@ InputParameterWarehouse::InputParameterWarehouse() InputParameters & InputParameterWarehouse::addInputParameters(const std::string & name, const InputParameters & parameters, - THREAD_ID tid /* =0 */) + THREAD_ID tid, + const AddRemoveParamsKey) { // Error if the name contains "::" if (name.find("::") != std::string::npos) @@ -105,7 +106,9 @@ InputParameterWarehouse::addInputParameters(const std::string & name, } void -InputParameterWarehouse::removeInputParameters(const MooseObject & moose_object, THREAD_ID tid) +InputParameterWarehouse::removeInputParameters(const MooseObject & moose_object, + THREAD_ID tid, + const AddRemoveParamsKey) { auto moose_object_name_string = moose_object.parameters().get("_unique_name"); MooseObjectName moose_object_name(moose_object_name_string); diff --git a/framework/src/utils/InputParameters.C b/framework/src/utils/InputParameters.C index 27b7c862eee5..1b512f00b318 100644 --- a/framework/src/utils/InputParameters.C +++ b/framework/src/utils/InputParameters.C @@ -21,8 +21,10 @@ #include "libmesh/simple_range.h" #include "pcrecpp.h" +#include "parse.h" #include +#include InputParameters emptyInputParameters() @@ -36,7 +38,9 @@ InputParameters::InputParameters() _collapse_nesting(false), _moose_object_syntax_visibility(true), _show_deprecated_message(true), - _allow_copy(true) + _allow_copy(true), + _hit_node(nullptr), + _finalized(false) { } @@ -70,6 +74,8 @@ InputParameters::clear() _block_location = ""; _old_to_new_name_and_dep.clear(); _new_to_old_names.clear(); + _hit_node = nullptr; + _finalized = false; } void @@ -168,6 +174,8 @@ InputParameters::operator=(const InputParameters & rhs) _block_location = rhs._block_location; _old_to_new_name_and_dep = rhs._old_to_new_name_and_dep; _new_to_old_names = rhs._new_to_old_names; + _hit_node = rhs._hit_node; + _finalized = rhs._finalized; return *this; } @@ -460,6 +468,14 @@ InputParameters::registerBase(const std::string & value) _params["_moose_base"]._is_private = true; } +std::optional +InputParameters::getBase() const +{ + if (have_parameter("_moose_base")) + return get("_moose_base"); + return {}; +} + void InputParameters::registerSystemAttributeName(const std::string & value) { @@ -604,6 +620,82 @@ InputParameters::checkParams(const std::string & parsing_syntax) mooseError(oss.str()); } +void +InputParameters::finalize(const std::string & parsing_syntax) +{ + mooseAssert(!isFinalized(), "Already finalized"); + + checkParams(parsing_syntax); + + // Helper for setting the absolute paths for each set file name parameter + const auto set_absolute_path = [this](const std::string & param_name, auto & value) + { + // We don't need to set a path if nothing is there + if (value.empty()) + return; + + std::filesystem::path value_path = std::string(value); + // Is already absolute, nothing to do + if (value_path.is_absolute()) + return; + + // The base by which to make things relative to + const auto file_base = getParamFileBase(param_name); + value = std::filesystem::absolute(file_base / value_path).c_str(); + }; + + // Set the absolute path for each file name typed parameter + for (const auto & [param_name, param_value] : *this) + { +#define set_if_filename(type) \ + else if (auto type_value = dynamic_cast *>(param_value.get())) \ + set_absolute_path(param_name, type_value->set()); \ + else if (auto type_values = dynamic_cast> *>( \ + param_value.get())) for (auto & value : type_values->set()) \ + set_absolute_path(param_name, value) + + if (false) + ; + // Note that we explicitly skip DataFileName here because we do not want absolute + // file paths for data files, as they're searched in the data directories + set_if_filename(FileName); + set_if_filename(FileNameNoExtension); + set_if_filename(MeshFileName); +#undef set_if_filename + } + + _finalized = true; +} + +std::filesystem::path +InputParameters::getParamFileBase(const std::string & param_name) const +{ + mooseAssert(!have_parameter("_app_name"), + "Not currently setup to work with app FileName parameters"); + + // Context from the individual parameter + const hit::Node * hit_node = getHitNode(param_name); + // Context from the parameters + if (!hit_node) + hit_node = getHitNode(); + // No hit node, so use the cwd (no input files) + if (!hit_node) + return std::filesystem::current_path(); + + // Find any context that isn't command line arguments + while (hit_node && hit_node->filename() == "CLI_ARGS") + hit_node = hit_node->parent(); + + // Failed to find a node up the tree that isn't a command line argument + if (!hit_node) + mooseError( + errorPrefix(param_name), + " Parameter was set via a command-line argument and does not have sufficient context for " + "determining a file path."); + + return std::filesystem::absolute(std::filesystem::path(hit_node->filename()).parent_path()); +} + bool InputParameters::isRangeChecked(const std::string & param_name) const { @@ -828,6 +920,10 @@ InputParameters::applyParameters(const InputParameters & common, const std::vector & exclude, const bool allow_private) { + // If we're applying all of the things, also associate the top level hit node + if (exclude.empty() && !getHitNode() && common.getHitNode()) + setHitNode(*common.getHitNode(), {}); + // Loop through the common parameters for (const auto & it : common) { @@ -954,6 +1050,10 @@ InputParameters::applyParameter(const InputParameters & common, set_attributes(local_name, false); _params[local_name]._set_by_add_param = libmesh_map_find(common._params, common_name)._set_by_add_param; + // Keep track of where this param came from if we can. This will enable us to + // produce param errors from objects created within an action that link to + // the parameter in the action + at(local_name)._hit_node = common.getHitNode(common_name); } // Enable deprecated message printing @@ -1214,7 +1314,7 @@ const MooseEnum & InputParameters::getParamHelper(const std::string & name_in, const InputParameters & pars, const MooseEnum *, - const MooseObject * /* = nullptr */) + const MooseBase * /* = nullptr */) { const auto name = pars.checkForRename(name_in); return pars.get(name); @@ -1225,7 +1325,7 @@ const MultiMooseEnum & InputParameters::getParamHelper(const std::string & name_in, const InputParameters & pars, const MultiMooseEnum *, - const MooseObject * /* = nullptr */) + const MooseBase * /* = nullptr */) { const auto name = pars.checkForRename(name_in); return pars.get(name); @@ -1249,6 +1349,53 @@ InputParameters::reservedValues(const std::string & name_in) const return it->second._reserved_values; } +std::string +InputParameters::blockLocation() const +{ + if (const auto hit_node = getHitNode()) + return hit_node->fileLocation(/* with_column = */ false); + return ""; +} + +std::string +InputParameters::blockFullpath() const +{ + if (const auto hit_node = getHitNode()) + return hit_node->fullpath(); + return ""; +} + +const hit::Node * +InputParameters::getHitNode(const std::string & param) const +{ + return at(param)._hit_node; +} + +void +InputParameters::setHitNode(const std::string & param, + const hit::Node & node, + const InputParameters::SetParamHitNodeKey) +{ + mooseAssert(node.type() == hit::NodeType::Field, "Must be a field"); + at(param)._hit_node = &node; +} + +std::string +InputParameters::inputLocation(const std::string & param) const +{ + if (const auto hit_node = getHitNode(param)) + return hit_node->fileLocation(/* with_column = */ false); + return ""; +} + +std::string +InputParameters::paramFullpath(const std::string & param) const +{ + if (const auto hit_node = getHitNode(param)) + return hit_node->fullpath(); + return ""; +} + void InputParameters::checkParamName(const std::string & name) const { @@ -1314,6 +1461,14 @@ InputParameters::errorPrefix(const std::string & param) const return prefix; } +std::string +InputParameters::rawParamVal(const std::string & param) const +{ + if (const auto hit_node = getHitNode(param)) + return hit_node->strVal(); + return ""; +} + std::string InputParameters::varName(const std::string & var_param_name, const std::string & moose_object_with_var_param_name) const @@ -1452,7 +1607,7 @@ InputParameters::paramAliases(const std::string & param_name) const } void -InputParameters::callMooseErrorHelper(const MooseObject & object, const std::string & error) +InputParameters::callMooseErrorHelper(const MooseBase & moose_base, const std::string & error) { - object.mooseError(error); + moose_base.callMooseError(error, true); } diff --git a/framework/src/utils/MooseTypes.C b/framework/src/utils/MooseTypes.C index fb5154b81afb..a8279294d6c7 100644 --- a/framework/src/utils/MooseTypes.C +++ b/framework/src/utils/MooseTypes.C @@ -46,6 +46,7 @@ const TagName PREVIOUS_NL_SOLUTION_TAG = "U_PREVIOUS_NL_NEWTON"; DerivativeStringToJSON(FileName); DerivativeStringToJSON(FileNameNoExtension); DerivativeStringToJSON(RelativeFileName); +DerivativeStringToJSON(DataFileName); DerivativeStringToJSON(MeshFileName); DerivativeStringToJSON(OutFileBase); DerivativeStringToJSON(NonlinearVariableName); diff --git a/modules/external_petsc_solver/src/mesh/PETScDMDAMesh.C b/modules/external_petsc_solver/src/mesh/PETScDMDAMesh.C index 25b8b335c389..d1d12fdaf23c 100644 --- a/modules/external_petsc_solver/src/mesh/PETScDMDAMesh.C +++ b/modules/external_petsc_solver/src/mesh/PETScDMDAMesh.C @@ -57,7 +57,7 @@ PETScDMDAMesh::PETScDMDAMesh(const InputParameters & parameters) : MooseMesh(par std::unique_ptr PETScDMDAMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } inline dof_id_type diff --git a/modules/fluid_properties/unit/src/TabulatedBicubicFluidPropertiesTest.C b/modules/fluid_properties/unit/src/TabulatedBicubicFluidPropertiesTest.C index a240384d5b51..2e701268e77d 100644 --- a/modules/fluid_properties/unit/src/TabulatedBicubicFluidPropertiesTest.C +++ b/modules/fluid_properties/unit/src/TabulatedBicubicFluidPropertiesTest.C @@ -24,10 +24,8 @@ TEST_F(TabulatedBicubicFluidPropertiesTest, unorderedData) } catch (const std::exception & err) { - std::size_t pos = - std::string(err.what()) - .find("The column data for temperature is not monotonically increasing in " - "data/csv/unordered_fluid_props.csv"); + std::size_t pos = std::string(err.what()) + .find("The column data for temperature is not monotonically increasing"); ASSERT_TRUE(pos != std::string::npos); } } @@ -60,8 +58,7 @@ TEST_F(TabulatedBicubicFluidPropertiesTest, missingColumn) catch (const std::exception & err) { std::size_t pos = std::string(err.what()) - .find("No temperature data read in " - "data/csv/missing_col_fluid_props.csv. A " + .find("data/csv/missing_col_fluid_props.csv. A " "column named temperature must be present"); ASSERT_TRUE(pos != std::string::npos); } @@ -78,7 +75,7 @@ TEST_F(TabulatedBicubicFluidPropertiesTest, unknownColumn) catch (const std::exception & err) { std::size_t pos = std::string(err.what()) - .find("unknown read in data/csv/unknown_fluid_props.csv is not one of " + .find("data/csv/unknown_fluid_props.csv is not one of " "the properties that TabulatedFluidProperties understands"); ASSERT_TRUE(pos != std::string::npos); } @@ -95,7 +92,7 @@ TEST_F(TabulatedBicubicFluidPropertiesTest, missingData) catch (const std::exception & err) { std::size_t pos = std::string(err.what()) - .find("The number of rows in data/csv/missing_data_fluid_props.csv " + .find("data/csv/missing_data_fluid_props.csv " "is not equal to the number of unique pressure values 3 multiplied " "by the number of unique temperature values 3"); ASSERT_TRUE(pos != std::string::npos); diff --git a/modules/optimization/src/actions/OptimizationAction.C b/modules/optimization/src/actions/OptimizationAction.C index 89761f5bbf39..bdedd4bbb415 100644 --- a/modules/optimization/src/actions/OptimizationAction.C +++ b/modules/optimization/src/actions/OptimizationAction.C @@ -47,6 +47,9 @@ OptimizationAction::act() InputParameters action_params = _action_factory.getValidParams("SetupMeshAction"); action_params.set("type") = "GeneratedMesh"; + // Associate errors with "solve_type" + associateWithParameter("auto_create_mesh", action_params); + // Create The Action auto action = std::static_pointer_cast( _action_factory.create("SetupMeshAction", "Mesh", action_params)); @@ -67,6 +70,9 @@ OptimizationAction::act() // Build the Action parameters InputParameters action_params = _action_factory.getValidParams("CreateProblemAction"); + // Associate errors with "solve_type" + associateWithParameter("auto_create_problem", action_params); + // Create the action auto action = std::static_pointer_cast( _action_factory.create("CreateProblemAction", "Problem", action_params)); diff --git a/modules/peridynamics/src/mesh/PeridynamicsMesh.C b/modules/peridynamics/src/mesh/PeridynamicsMesh.C index 538589f7210f..c0dac2809a98 100644 --- a/modules/peridynamics/src/mesh/PeridynamicsMesh.C +++ b/modules/peridynamics/src/mesh/PeridynamicsMesh.C @@ -104,7 +104,7 @@ PeridynamicsMesh::PeridynamicsMesh(const InputParameters & parameters) std::unique_ptr PeridynamicsMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/modules/ray_tracing/include/base/RayTracingObject.h b/modules/ray_tracing/include/base/RayTracingObject.h index 3f849296c40c..343656241812 100644 --- a/modules/ray_tracing/include/base/RayTracingObject.h +++ b/modules/ray_tracing/include/base/RayTracingObject.h @@ -148,5 +148,4 @@ RayTracingObject::getStudy() usingFunctionInterfaceMembers; \ usingPostprocessorInterfaceMembers; \ usingTransientInterfaceMembers; \ - using RayTracingObject::currentRay; \ - using RayTracingObject::errorPrefix + using RayTracingObject::currentRay diff --git a/modules/ray_tracing/test/tests/base/ray_tracing_object/tests b/modules/ray_tracing/test/tests/base/ray_tracing_object/tests index 35ba377ed299..23143366fe1a 100644 --- a/modules/ray_tracing/test/tests/base/ray_tracing_object/tests +++ b/modules/ray_tracing/test/tests/base/ray_tracing_object/tests @@ -10,7 +10,7 @@ input = 'errors.i' cli_args = 'RayKernels/test/get_study_bad=true RayKernels/test/study=study' allow_test_objects = true - expect_err = '\(RayKernels/test/study\):.*Supplied study of type RayTracingStudyTest is not the required study type RepeatableRayStudy' + expect_err = 'Supplied study of type RayTracingStudyTest is not the required study type RepeatableRayStudy' detail = 'the study is provided via param and is of the wrong type' [] [get_study_bad_default] @@ -18,7 +18,7 @@ input = 'errors.i' cli_args = 'RayKernels/test/get_study_bad=true' allow_test_objects = true - expect_err = 'The following error occurred in the object "test", of type "RayTracingObjectTest"..*Supplied study of type RayTracingStudyTest is not the required study type RepeatableRayStudy' + expect_err = 'Supplied study of type RayTracingStudyTest is not the required study type RepeatableRayStudy' detail = 'the study is provided by default and is of the wrong type' [] [] diff --git a/modules/solid_mechanics/src/materials/LAROMANCEStressUpdateBase.C b/modules/solid_mechanics/src/materials/LAROMANCEStressUpdateBase.C index 5fa8c059f8d9..c40197f1f4c2 100644 --- a/modules/solid_mechanics/src/materials/LAROMANCEStressUpdateBase.C +++ b/modules/solid_mechanics/src/materials/LAROMANCEStressUpdateBase.C @@ -151,7 +151,7 @@ LAROMANCEStressUpdateBaseTempl::validParams() params.addParam("stress_unit", "Pa", "unit of stress"); // use std::string here to avoid automatic absolute path expansion - params.addParam("model", "LaRomance model JSON datafile"); + params.addParam("model", "LaRomance model JSON datafile"); params.addParam("export_model", "Write LaRomance model to JSON datafile"); params.addParamNamesToGroup( @@ -1396,7 +1396,7 @@ LAROMANCEStressUpdateBaseTempl::checkJSONKey(const std::string & key) if (!this->isParamValid("model")) this->paramError("model", "Specify a JSON data filename."); - const auto model_file_name = this->_pars.rawParamVal("model"); + const auto model_file_name = this->template getParam("model"); if (_json.empty()) this->paramError("model", "The specified JSON data file '", model_file_name, "' is empty."); if (!_json.contains(key)) diff --git a/modules/stochastic_tools/src/actions/StochasticToolsAction.C b/modules/stochastic_tools/src/actions/StochasticToolsAction.C index bb0fe687034b..896a3984101d 100644 --- a/modules/stochastic_tools/src/actions/StochasticToolsAction.C +++ b/modules/stochastic_tools/src/actions/StochasticToolsAction.C @@ -52,6 +52,9 @@ StochasticToolsAction::act() InputParameters action_params = _action_factory.getValidParams("SetupMeshAction"); action_params.set("type") = "GeneratedMesh"; + // Associate errors with "auto_create_mesh" + associateWithParameter("auto_create_mesh", action_params); + // Create The Action auto action = std::static_pointer_cast( _action_factory.create("SetupMeshAction", "Mesh", action_params)); @@ -93,6 +96,9 @@ StochasticToolsAction::act() // Build the Action parameters InputParameters action_params = _action_factory.getValidParams("CreateProblemAction"); + // Associate errors with "auto_create_problem" + associateWithParameter("auto_create_problem", action_params); + // Create the action auto action = std::static_pointer_cast( _action_factory.create("CreateProblemAction", "Problem", action_params)); @@ -116,6 +122,9 @@ StochasticToolsAction::act() InputParameters action_params = _action_factory.getValidParams("CreateExecutionerAction"); action_params.set("type") = "Steady"; + // Associate errors with "auto_create_executioner" + associateWithParameter("auto_create_executioner", action_params); + // Create the action auto action = std::static_pointer_cast( _action_factory.create("CreateExecutionerAction", "Executioner", action_params)); diff --git a/modules/thermal_hydraulics/src/actions/AddIterationCountPostprocessorsAction.C b/modules/thermal_hydraulics/src/actions/AddIterationCountPostprocessorsAction.C index 06c90e0e1a78..f39e259d50ad 100644 --- a/modules/thermal_hydraulics/src/actions/AddIterationCountPostprocessorsAction.C +++ b/modules/thermal_hydraulics/src/actions/AddIterationCountPostprocessorsAction.C @@ -48,6 +48,7 @@ AddIterationCountPostprocessorsAction::act() { const std::string class_name = "AddPostprocessorAction"; InputParameters action_params = _action_factory.getValidParams(class_name); + associateWithParameter("count_iterations", action_params); action_params.set("type") = it_per_step_class_names[i]; auto action = std::static_pointer_cast( _action_factory.create(class_name, it_per_step_names[i], action_params)); @@ -57,6 +58,7 @@ AddIterationCountPostprocessorsAction::act() { const std::string class_name = "AddPostprocessorAction"; InputParameters action_params = _action_factory.getValidParams(class_name); + associateWithParameter("count_iterations", action_params); action_params.set("type") = "CumulativeValuePostprocessor"; auto action = std::static_pointer_cast( _action_factory.create(class_name, total_it_names[i], action_params)); diff --git a/modules/thermal_hydraulics/src/base/THMMesh.C b/modules/thermal_hydraulics/src/base/THMMesh.C index fae6022d3469..7e275ed70bad 100644 --- a/modules/thermal_hydraulics/src/base/THMMesh.C +++ b/modules/thermal_hydraulics/src/base/THMMesh.C @@ -63,7 +63,7 @@ THMMesh::effectiveSpatialDimension() const std::unique_ptr THMMesh::safeClone() const { - return std::make_unique(*this); + return _app.getFactory().copyConstruct(*this); } void diff --git a/modules/thermal_hydraulics/src/relationshipmanagers/AugmentSparsityBetweenElements.C b/modules/thermal_hydraulics/src/relationshipmanagers/AugmentSparsityBetweenElements.C index f0ee790921ba..740884bac43d 100644 --- a/modules/thermal_hydraulics/src/relationshipmanagers/AugmentSparsityBetweenElements.C +++ b/modules/thermal_hydraulics/src/relationshipmanagers/AugmentSparsityBetweenElements.C @@ -38,7 +38,7 @@ AugmentSparsityBetweenElements::AugmentSparsityBetweenElements( std::unique_ptr AugmentSparsityBetweenElements::clone() const { - return std::make_unique(*this); + return _app.getFactory().clone(*this); } void diff --git a/test/src/partitioner/PartitionerWeightTest.C b/test/src/partitioner/PartitionerWeightTest.C index cf22ff77eb1e..64a2e3e61003 100644 --- a/test/src/partitioner/PartitionerWeightTest.C +++ b/test/src/partitioner/PartitionerWeightTest.C @@ -9,6 +9,8 @@ #include "PartitionerWeightTest.h" +#include "MooseApp.h" + #include "libmesh/elem.h" registerMooseObject("MooseTestApp", PartitionerWeightTest); @@ -31,7 +33,7 @@ PartitionerWeightTest::PartitionerWeightTest(const InputParameters & params) std::unique_ptr PartitionerWeightTest::clone() const { - return std::make_unique(_pars); + return _app.getFactory().clone(*this); } dof_id_type diff --git a/test/src/userobjects/DataFileNameTest.C b/test/src/userobjects/DataFileNameTest.C index 3a9430ddc159..f405d50e9e4f 100644 --- a/test/src/userobjects/DataFileNameTest.C +++ b/test/src/userobjects/DataFileNameTest.C @@ -15,7 +15,7 @@ InputParameters DataFileNameTest::validParams() { InputParameters params = GeneralUserObject::validParams(); - params.addRequiredParam("data_file", "Data file to look up"); + params.addRequiredParam("data_file", "Data file to look up"); return params; } diff --git a/test/tests/time_steppers/time_stepper_system/tests b/test/tests/time_steppers/time_stepper_system/tests index 0cf816716428..231868fc4b65 100644 --- a/test/tests/time_steppers/time_stepper_system/tests +++ b/test/tests/time_steppers/time_stepper_system/tests @@ -71,7 +71,7 @@ type = RunException input = 'lower_bound.i' cli_args = 'Executioner/TimeSteppers/lower_bound=FooDT' - expect_err = "lower_bound: Failed to find a timestepper with the name 'FooDT'" + expect_err = "Failed to find a timestepper with the name 'FooDT'" detail ="time stepper name(s) provided for lower_bound dosen't exist," [] @@ -79,7 +79,7 @@ type = RunException input = 'active_timesteppers.i' cli_args = "Controls/c1/disable_objects='TimeStepper::ConstDT2 TimeStepper::ConstDT1'" - expect_err = "The following error occurred in the object \"CompositionDT\", of type \"CompositionDT\".[.\n]\sNo TimeStepper\(s\) are currently active to compute a timestep" + expect_err = "No TimeStepper\(s\) are currently active to compute a timestep" detail ='no time steppers are active to compute a timestep,' [] @@ -94,7 +94,7 @@ type = RunException input = 'testRejectStep.i' allow_test_objects = True - expect_err = "The following warning occurred in the object \"(.*?)\", of type \"(.*?)\".\n\nrejectStep\(\) calls from TestSourceStepper" + expect_err = "rejectStep\(\) calls from TestSourceStepper" detail = 'the corresponding rejectStep() function is called when solve fails' [] [] diff --git a/test/tests/variables/optionally_coupled/tests b/test/tests/variables/optionally_coupled/tests index 5180b221981b..973a7aed05d7 100644 --- a/test/tests/variables/optionally_coupled/tests +++ b/test/tests/variables/optionally_coupled/tests @@ -77,7 +77,7 @@ type = 'RunException' input = 'optionally_coupled.i' cli_args = 'Kernels/wrong_index/type=CoupledForceWrongIndex Kernels/wrong_index/variable=u' - expect_err = 'v: component 2 is out of range for this variable \(max 1\)' + expect_err = 'component 2 is out of range for this variable \(max 1\)' detail = "accessed by name or" [] @@ -87,7 +87,7 @@ input = 'optionally_coupled.i' cli_args = 'Kernels/wrong_index/type=CoupledForceWrongIndex Kernels/wrong_index/variable=u ' 'Kernels/wrong_index/access_value=false' - expect_err = 'v: component 2 is out of range for this variable \(max 1\)' + expect_err = 'component 2 is out of range for this variable \(max 1\)' detail = "accessed by index." [] diff --git a/unit/files/InputParametersTest/simple_input.i b/unit/files/InputParametersTest/simple_input.i new file mode 100644 index 000000000000..bff312109e71 --- /dev/null +++ b/unit/files/InputParametersTest/simple_input.i @@ -0,0 +1,3 @@ +[object] + file = ../foo +[] diff --git a/unit/include/JSONReaderTest.h b/unit/include/JSONReaderTest.h new file mode 100644 index 000000000000..e72552d385a9 --- /dev/null +++ b/unit/include/JSONReaderTest.h @@ -0,0 +1,18 @@ +//* 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 + +#include "MooseObjectUnitTest.h" + +class JSONReaderTest : public MooseObjectUnitTest +{ +public: + JSONReaderTest() : MooseObjectUnitTest("MooseUnitApp") {} +}; diff --git a/unit/include/ParsedFunctionTest.h b/unit/include/ParsedFunctionTest.h index 684ffe7936ab..0bda1c44093e 100644 --- a/unit/include/ParsedFunctionTest.h +++ b/unit/include/ParsedFunctionTest.h @@ -9,55 +9,21 @@ #pragma once -#include "gtest_include.h" +#include "MooseObjectUnitTest.h" -#include "InputParameters.h" -#include "MooseParsedFunction.h" -#include "FEProblem.h" -#include "MooseUnitApp.h" -#include "AppFactory.h" -#include "GeneratedMesh.h" #include "MooseParsedFunctionWrapper.h" -#include "MooseMain.h" -class ParsedFunctionTest : public ::testing::Test -{ -protected: - void SetUp() - { - const char * argv[2] = {"foo", "\0"}; - - _app = Moose::createMooseApp("MooseUnitApp", 1, (char **)argv); - - _factory = &_app->getFactory(); +class MooseParsedFunction; - InputParameters mesh_params = _factory->getValidParams("GeneratedMesh"); - mesh_params.set("dim") = "3"; - mesh_params.set("_object_name") = "mesh"; - mesh_params.set("_type") = "GneratedMesh"; - mesh_params.set("nx") = 2; - mesh_params.set("ny") = 2; - mesh_params.set("nz") = 2; - mesh_params.set("parallel_type") = "REPLICATED"; - - _mesh = std::make_unique(mesh_params); - _mesh->setMeshBase(_mesh->buildMeshBaseObject()); - _mesh->buildMesh(); - - InputParameters problem_params = _factory->getValidParams("FEProblem"); - problem_params.set("mesh") = _mesh.get(); - problem_params.set("_object_name") = "FEProblem"; - problem_params.set("_type") = "FEProblem"; - _fe_problem = std::make_unique(problem_params); - } +class ParsedFunctionTest : public MooseObjectUnitTest +{ +public: + ParsedFunctionTest() : MooseObjectUnitTest("MooseUnitApp") {} - ParsedFunction * fptr(MooseParsedFunction & f) - { - return f._function_ptr->_function_ptr.get(); - } +protected: + ParsedFunction * fptr(MooseParsedFunction & f); + InputParameters getParams(); + MooseParsedFunction & buildFunction(InputParameters & params); - std::shared_ptr _app; - std::unique_ptr _mesh; - std::unique_ptr _fe_problem; - Factory * _factory; + unsigned int function_index = 0; }; diff --git a/unit/include/PositionsTest.h b/unit/include/PositionsTest.h new file mode 100644 index 000000000000..1949bbd4b6a3 --- /dev/null +++ b/unit/include/PositionsTest.h @@ -0,0 +1,18 @@ +//* 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 + +#include "MooseObjectUnitTest.h" + +class PositionsTest : public MooseObjectUnitTest +{ +public: + PositionsTest() : MooseObjectUnitTest("MooseUnitApp") {} +}; diff --git a/unit/include/TimesTest.h b/unit/include/TimesTest.h new file mode 100644 index 000000000000..45209854541b --- /dev/null +++ b/unit/include/TimesTest.h @@ -0,0 +1,18 @@ +//* 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 + +#include "MooseObjectUnitTest.h" + +class TimesTest : public MooseObjectUnitTest +{ +public: + TimesTest() : MooseObjectUnitTest("MooseUnitApp") {} +}; diff --git a/unit/src/InputParameterWarehouseTest.C b/unit/src/InputParameterWarehouseTest.C index e6e46e250d89..c0c4d1ec0e70 100644 --- a/unit/src/InputParameterWarehouseTest.C +++ b/unit/src/InputParameterWarehouseTest.C @@ -7,11 +7,10 @@ //* Licensed under LGPL 2.1, please see LICENSE for details //* https://www.gnu.org/licenses/lgpl-2.1.html -#include "gtest/gtest.h" #include "InputParameterWarehouse.h" #include "InputParameters.h" -TEST(InputParameterWarehouse, getControllableItems) +TEST(InputParameterWarehouseTest, getControllableItems) { // One item { @@ -21,7 +20,7 @@ TEST(InputParameterWarehouse, getControllableItems) in_params.declareControllable("control"); InputParameterWarehouse wh; - const InputParameters & params = wh.addInputParameters("Object", in_params); + const InputParameters & params = wh.addInputParameters("Object", in_params, 0, {}); MooseObjectParameterName name("Base", "Object", "control"); auto items = wh.getControllableItems(name); @@ -47,7 +46,7 @@ TEST(InputParameterWarehouse, getControllableItems) in_params.declareControllable("control control2"); InputParameterWarehouse wh; - const InputParameters & params = wh.addInputParameters("Object", in_params); + const InputParameters & params = wh.addInputParameters("Object", in_params, 0, {}); MooseObjectParameterName name("Base", "Object", "*"); auto items = wh.getControllableItems(name); @@ -70,7 +69,7 @@ TEST(InputParameterWarehouse, getControllableItems) } } -TEST(InputParameterWarehouse, getControllableParameter) +TEST(InputParameterWarehouseTest, getControllableParameter) { InputParameters in_params = emptyInputParameters(); in_params.addPrivateParam("_moose_base", "Base"); @@ -80,7 +79,7 @@ TEST(InputParameterWarehouse, getControllableParameter) in_params.declareControllable("control control2"); InputParameterWarehouse wh; - const InputParameters & params = wh.addInputParameters("Object", in_params); + const InputParameters & params = wh.addInputParameters("Object", in_params, 0, {}); MooseObjectParameterName name("Base", "Object", "*"); auto cp = wh.getControllableParameter(name); @@ -97,7 +96,7 @@ TEST(InputParameterWarehouse, getControllableParameter) EXPECT_EQ(params.get("control2"), 2009); } -TEST(InputParameterWarehouse, getControllableParameterValues) +TEST(InputParameterWarehouseTest, getControllableParameterValues) { InputParameters in_params = emptyInputParameters(); in_params.addPrivateParam("_moose_base", "Base"); @@ -105,7 +104,7 @@ TEST(InputParameterWarehouse, getControllableParameterValues) in_params.declareControllable("control"); InputParameterWarehouse wh; - wh.addInputParameters("Object", in_params); + wh.addInputParameters("Object", in_params, 0, {}); MooseObjectParameterName name("Base", "Object", "*"); std::vector values = wh.getControllableParameterValues(name); @@ -114,7 +113,7 @@ TEST(InputParameterWarehouse, getControllableParameterValues) EXPECT_EQ(values, std::vector(1, 2011)); } -TEST(InputParameterWarehouse, emptyControllableParameterValues) +TEST(InputParameterWarehouseTest, emptyControllableParameterValues) { InputParameters in_params = emptyInputParameters(); in_params.addPrivateParam("_moose_base", "Base"); @@ -122,7 +121,7 @@ TEST(InputParameterWarehouse, emptyControllableParameterValues) in_params.declareControllable("control"); InputParameterWarehouse wh; - wh.addInputParameters("Object", in_params); + wh.addInputParameters("Object", in_params, 0, {}); MooseObjectParameterName name("Base", "Object", "asdf"); std::vector values = wh.getControllableParameterValues(name); @@ -130,7 +129,7 @@ TEST(InputParameterWarehouse, emptyControllableParameterValues) ASSERT_TRUE(values.empty()); } -TEST(InputParameterWarehouse, addControllableParameterConnection) +TEST(InputParameterWarehouseTest, addControllableParameterConnection) { // One-to-one { @@ -140,9 +139,9 @@ TEST(InputParameterWarehouse, addControllableParameterConnection) in_params.declareControllable("control"); InputParameterWarehouse wh; - const InputParameters & params0 = wh.addInputParameters("Object0", in_params); + const InputParameters & params0 = wh.addInputParameters("Object0", in_params, 0, {}); in_params.set("control") = 1954; - const InputParameters & params1 = wh.addInputParameters("Object1", in_params); + const InputParameters & params1 = wh.addInputParameters("Object1", in_params, 0, {}); MooseObjectParameterName name0("Base", "Object0", "control"); MooseObjectParameterName name1("Base", "Object1", "control"); @@ -170,13 +169,13 @@ TEST(InputParameterWarehouse, addControllableParameterConnection) in_params.declareControllable("control"); InputParameterWarehouse wh; - const InputParameters & params0 = wh.addInputParameters("Object0", in_params); + const InputParameters & params0 = wh.addInputParameters("Object0", in_params, 0, {}); in_params.set("control") = 2011; in_params.set("_moose_base") = "Base2"; - const InputParameters & params1 = wh.addInputParameters("Object1", in_params); + const InputParameters & params1 = wh.addInputParameters("Object1", in_params, 0, {}); in_params.set("control") = 2013; - const InputParameters & params2 = wh.addInputParameters("Object2", in_params); + const InputParameters & params2 = wh.addInputParameters("Object2", in_params, 0, {}); MooseObjectParameterName name0("Base", "Object0", "control"); MooseObjectParameterName name1("Base2", "*", "control"); @@ -209,13 +208,13 @@ TEST(InputParameterWarehouse, addControllableParameterConnection) in_params.declareControllable("control"); InputParameterWarehouse wh; - const InputParameters & params0 = wh.addInputParameters("Object0", in_params); + const InputParameters & params0 = wh.addInputParameters("Object0", in_params, 0, {}); in_params.set("control") = 2011; in_params.set("_moose_base") = "Base2"; - const InputParameters & params1 = wh.addInputParameters("Object1", in_params); + const InputParameters & params1 = wh.addInputParameters("Object1", in_params, 0, {}); in_params.set("control") = 2013; - const InputParameters & params2 = wh.addInputParameters("Object2", in_params); + const InputParameters & params2 = wh.addInputParameters("Object2", in_params, 0, {}); MooseObjectParameterName name0("Base", "Object0", "control"); MooseObjectParameterName name1("Base2", "Object1", "control"); @@ -275,15 +274,15 @@ TEST(InputParameterWarehouse, addControllableParameterConnection) in_params.declareControllable("control"); InputParameterWarehouse wh; - const InputParameters & params0 = wh.addInputParameters("Object0", in_params); + const InputParameters & params0 = wh.addInputParameters("Object0", in_params, 0, {}); in_params.addParam("control", 1954, ""); - const InputParameters & params1 = wh.addInputParameters("Object1", in_params); + const InputParameters & params1 = wh.addInputParameters("Object1", in_params, 0, {}); in_params.set("control") = 2011; in_params.set("_moose_base") = "Base2"; - const InputParameters & params2 = wh.addInputParameters("Object2", in_params); + const InputParameters & params2 = wh.addInputParameters("Object2", in_params, 0, {}); in_params.set("control") = 2013; - const InputParameters & params3 = wh.addInputParameters("Object3", in_params); + const InputParameters & params3 = wh.addInputParameters("Object3", in_params, 0, {}); MooseObjectParameterName name0("Base", "Object0", "control"); MooseObjectParameterName name1("Base", "Object1", "control"); @@ -395,7 +394,7 @@ TEST(InputParameterWarehouse, addControllableParameterConnection) } } -TEST(InputParameterWarehouse, addControllableParameterAlias) +TEST(InputParameterWarehouseTest, addControllableParameterAlias) { InputParameters in_params = emptyInputParameters(); in_params.addPrivateParam("_moose_base", "Base"); @@ -403,7 +402,7 @@ TEST(InputParameterWarehouse, addControllableParameterAlias) in_params.declareControllable("control"); InputParameterWarehouse wh; - const InputParameters & params = wh.addInputParameters("Object", in_params); + const InputParameters & params = wh.addInputParameters("Object", in_params, 0, {}); MooseObjectParameterName alias("not", "a", "param"); MooseObjectParameterName secondary("Base", "Object", "control"); diff --git a/unit/src/InputParametersTest.C b/unit/src/InputParametersTest.C index 19364b7aadd4..35f32eebb12f 100644 --- a/unit/src/InputParametersTest.C +++ b/unit/src/InputParametersTest.C @@ -7,14 +7,15 @@ //* Licensed under LGPL 2.1, please see LICENSE for details //* https://www.gnu.org/licenses/lgpl-2.1.html -// MOOSE includes +#include "gtest/gtest.h" + #include "InputParameters.h" #include "MooseEnum.h" #include "MultiMooseEnum.h" #include "Conversion.h" -#include "gtest/gtest.h" +#include "Parser.h" -TEST(InputParameters, checkControlParamPrivateError) +TEST(InputParametersTest, checkControlParamPrivateError) { try { @@ -35,7 +36,7 @@ TEST(InputParameters, checkControlParamPrivateError) // This tests for the bug https://github.com/idaholab/moose/issues/8586. // It makes sure that range-checked input file parameters comparison functions // do absolute floating point comparisons instead of using a default epsilon. -TEST(InputParameters, checkRangeCheckedParam) +TEST(InputParametersTest, checkRangeCheckedParam) { try { @@ -52,7 +53,7 @@ TEST(InputParameters, checkRangeCheckedParam) } } -TEST(InputParameters, checkControlParamTypeError) +TEST(InputParametersTest, checkControlParamTypeError) { try { @@ -70,7 +71,7 @@ TEST(InputParameters, checkControlParamTypeError) } } -TEST(InputParameters, checkControlParamValidError) +TEST(InputParametersTest, checkControlParamValidError) { try { @@ -87,7 +88,7 @@ TEST(InputParameters, checkControlParamValidError) } } -TEST(InputParameters, checkSuppressedError) +TEST(InputParametersTest, checkSuppressedError) { try { @@ -103,7 +104,7 @@ TEST(InputParameters, checkSuppressedError) } } -TEST(InputParameters, checkSuppressingControllableParam) +TEST(InputParametersTest, checkSuppressingControllableParam) { InputParameters params = emptyInputParameters(); params.addParam("b", "Controllable boolean"); @@ -115,7 +116,7 @@ TEST(InputParameters, checkSuppressingControllableParam) ASSERT_TRUE(params.isControllable("b") == false); } -TEST(InputParameters, checkSetDocString) +TEST(InputParametersTest, checkSetDocString) { InputParameters params = emptyInputParameters(); params.addParam("little_guy", "What about that little guy?"); @@ -126,7 +127,7 @@ TEST(InputParameters, checkSetDocString) << "retrieved doc string has unexpected value '" << params.getDocString("little_guy") << "'"; } -TEST(InputParameters, checkSetDocStringError) +TEST(InputParametersTest, checkSetDocStringError) { try { @@ -161,14 +162,14 @@ testBadParamName(const std::string & name) } /// Just make sure we don't allow invalid parameter names -TEST(InputParameters, checkParamName) +TEST(InputParametersTest, checkParamName) { testBadParamName("p 0"); testBadParamName("p-0"); testBadParamName("p!0"); } -TEST(InputParameters, applyParameter) +TEST(InputParametersTest, applyParameter) { InputParameters p1 = emptyInputParameters(); p1.addParam("enum", MultiMooseEnum("foo=0 bar=1", "foo"), "testing"); @@ -183,7 +184,7 @@ TEST(InputParameters, applyParameter) EXPECT_TRUE(p1.get("enum").contains("bar")); } -TEST(InputParameters, applyParametersVector) +TEST(InputParametersTest, applyParametersVector) { MooseEnum types("foo bar"); @@ -204,7 +205,7 @@ TEST(InputParameters, applyParametersVector) EXPECT_TRUE(p1.get>("enum")[0] == "bar"); } -TEST(InputParameters, applyParameters) +TEST(InputParametersTest, applyParameters) { // First enum InputParameters p1 = emptyInputParameters(); @@ -241,7 +242,7 @@ TEST(InputParameters, applyParameters) EXPECT_TRUE(p1.get("enum").contains("foo")); } -TEST(InputParameters, applyParametersPrivateOverride) +TEST(InputParametersTest, applyParametersPrivateOverride) { InputParameters p1 = emptyInputParameters(); p1.addPrivateParam("_flag", true); @@ -255,7 +256,7 @@ TEST(InputParameters, applyParametersPrivateOverride) EXPECT_FALSE(p1.get("_flag")); } -TEST(InputParameters, makeParamRequired) +TEST(InputParametersTest, makeParamRequired) { InputParameters params = emptyInputParameters(); params.addParam("good_param", "documentation"); @@ -295,7 +296,7 @@ TEST(InputParameters, makeParamRequired) } } -TEST(InputParameters, setPPandVofPP) +TEST(InputParametersTest, setPPandVofPP) { // programmatically set default value of PPName parameter InputParameters p1 = emptyInputParameters(); @@ -325,7 +326,7 @@ TEST(InputParameters, setPPandVofPP) // EXPECT_EQ(p1.getDefaultPostprocessorValue("pp_name"), 1); } -TEST(InputParameters, getPairs) +TEST(InputParametersTest, getPairs) { std::vector num_words{"zero", "one", "two", "three"}; @@ -342,7 +343,7 @@ TEST(InputParameters, getPairs) } } -TEST(InputParameters, getMultiMooseEnumPairs) +TEST(InputParametersTest, getMultiMooseEnumPairs) { std::vector v1{"zero", "one", "two", "three"}; auto s1 = Moose::stringify(v1, " "); @@ -362,7 +363,7 @@ TEST(InputParameters, getMultiMooseEnumPairs) } } -TEST(InputParameters, getPairLength) +TEST(InputParametersTest, getPairLength) { std::vector num_words{"zero", "one", "two"}; @@ -386,7 +387,7 @@ TEST(InputParameters, getPairLength) } } -TEST(InputParameters, getControllablePairs) +TEST(InputParametersTest, getControllablePairs) { std::vector num_words{"zero", "one", "two", "three"}; @@ -412,7 +413,7 @@ TEST(InputParameters, getControllablePairs) } } -TEST(InputParameters, getParamList) +TEST(InputParametersTest, getParamList) { std::vector num_words{"zero", "one", "two", "three"}; @@ -424,7 +425,7 @@ TEST(InputParameters, getParamList) EXPECT_EQ(p.getParametersList(), param_list); } -TEST(InputParameters, transferParameters) +TEST(InputParametersTest, transferParameters) { // Add parameters of various types to p1 InputParameters p1 = emptyInputParameters(); @@ -531,7 +532,7 @@ TEST(InputParameters, transferParameters) EXPECT_EQ(p1.getDocString("od3b"), p2.getDocString("od3b")); } -TEST(InputParameters, noDefaultValueError) +TEST(InputParametersTest, noDefaultValueError) { InputParameters params = emptyInputParameters(); params.addParam("dummy_real", "a dummy real"); @@ -565,3 +566,182 @@ TEST(InputParameters, noDefaultValueError) << "Failed with unexpected error message: " << msg; } } + +TEST(InputParametersTest, fileNames) +{ + // Walker that kind-of does what the Builder does: walks parameters and sets input + // parameters. In this case, we only care about the objects that we've declared + // and their "file" parameter. + // + // I chose to do this like this because it means that these tests don't rely + // on an application at all, so we're relying on the basic capability + class ExtractWalker : public hit::Walker + { + public: + ExtractWalker(std::map> & object_params) + : _object_params(object_params) + { + } + virtual void walk(const std::string &, const std::string &, hit::Node * n) override + { + if (auto it = _object_params.find(n->path()); it != _object_params.end()) + { + auto & params = *it->second; + params.setHitNode(*n, {}); + if (const auto node = n->find("file")) + { + params.setHitNode("file", *node, {}); + params.set_attributes("file", false); + params.set("file") = node->strVal(); + } + } + } + + private: + std::map> & _object_params; + }; + + // Runs a test. + // inputs: map of filename -> input text + // expected_values: map of object name -> the relative path we expect + // cli_args: any cli args to add + auto run_test = [](const std::map & inputs, + const std::map & expected_values, + const std::vector & cli_args = {}) + { + std::vector filenames, input_text; + for (const auto & [filename, text] : inputs) + { + filenames.push_back(filename); + input_text.push_back(text); + } + + // Parse the inputs + Parser parser(filenames, input_text); + parser.parse(); + + // Merge in the command line arguments, if any + std::string cli_hit; + for (const auto & value : cli_args) + cli_hit += value + "\n"; + if (cli_hit.size()) + { + auto cli_root = hit::parse("CLI_ARGS", cli_hit); + hit::explode(cli_root); + hit::merge(cli_root, parser.root()); + delete cli_root; + } + + // Define the parameters that we care about + InputParameters base_params = emptyInputParameters(); + base_params.addParam("file", "file name"); + + // Initialize the params for each object + std::map> object_params; + for (const auto & object_values_pair : expected_values) + { + const auto & object_name = object_values_pair.first; + auto params = std::make_unique(base_params); + object_params.emplace(object_name, std::move(params)); + } + + // Fill the object parameters from the input + ExtractWalker ew(object_params); + parser.root()->walk(&ew, hit::NodeType::Section); + + // Finalize the parameters, which sets the filep aths + for (auto & name_params_pair : object_params) + name_params_pair.second->finalize(""); + + // Check all of the values that we expect + for (const auto & [object_name, expected_value] : expected_values) + { + const auto & params = *object_params.at(object_name); + const std::string file = params.get("file"); + const std::filesystem::path file_path(file); + + if (file.size()) + { + EXPECT_TRUE(file_path.is_absolute()); + } + if (expected_value.size()) + { + const auto relative = std::string(std::filesystem::proximate(file)); + EXPECT_EQ(relative, expected_value); + } + else + { + EXPECT_TRUE(file.empty()); + } + } + }; + + const auto include_files_path = std::filesystem::path(std::string(__FILE__)).parent_path() / + std::filesystem::path("../files/InputParametersTest"); + const auto include_file = [&include_files_path](const auto & filename) + { return std::string((include_files_path / std::filesystem::path(filename)).c_str()); }; + const auto relative_include_file = [&include_files_path](const auto & filename) + { + return std::string( + std::filesystem::proximate(include_files_path / std::filesystem::path(filename)).c_str()); + }; + + // const std::filesystem + // One input file, same directory + // main.i: + // [object1] + // file = value + // [] + // + // object1: + // file: ./value + run_test({{"main.i", "object1/file=value"}}, {{"object1", "value"}}); + + // Three input files: cwd, behind a directory, and ahead a directory + // main.i: + // main/file=main + // ../behind.i: + // behind/file=behind + // ahead/ahead.i: + // ahead/file=ahead + // + // main: ./main + // behind: ../behind/behind + // ahead: ./ahead/ahead + run_test({{"main.i", "main/file=main"}, + {"../behind.i", "behind/file=behind"}, + {"ahead/ahead.i", "ahead/file=ahead"}}, + {{"main", "main"}, {"behind", "../behind"}, {"ahead", "ahead/ahead"}}); + + // Two input files in different directories, with no file parameters. But, one + // of the input files (in a different directory) has the section only for the object + // that takes file parameters. The file is then applied via command line arguments + // and the context should be taken from the parent section (defined in the input + // in another folder) + // main.i: + // unused=unused + // ./ahead/ahead.i: + // [object] + // [] + // CLI args: + // object/file=foo + // + // object: ./ahead/foo + run_test({{"main.i", "unused=unused"}, {"./ahead/ahead.i", "[object][]"}}, + {{"object", "ahead/foo"}}, + {"object/file=foo"}); + + // Single input in a different directory with no contents, but will store the root + // in a different folder and all files should be applied to that folder + // ../../main.i: + // unused=unused + // CLI args: + // object/file=foo + // + // object: ../../foo + run_test({{"../../main.i", "unused=unused"}}, {{"object", "../../foo"}}, {"object/file=foo"}); + + // Input with an include in a different directory + run_test({{"../main.i", "!include " + include_file("simple_input.i")}}, + {{"object", relative_include_file("../foo")}}); +} diff --git a/unit/src/JSONReaderTest.C b/unit/src/JSONReaderTest.C index 651d15f4a272..a9c35000741b 100644 --- a/unit/src/JSONReaderTest.C +++ b/unit/src/JSONReaderTest.C @@ -8,38 +8,24 @@ //* https://www.gnu.org/licenses/lgpl-2.1.html #include "gtest/gtest.h" + +#include "JSONReaderTest.h" #include "JSONFileReader.h" -#include "AppFactory.h" -#include "Executioner.h" -#include "MooseMain.h" -TEST(JSONFileReader, errors) +TEST_F(JSONReaderTest, errors) { - // Create a minimal app that can create objects - const char * argv[2] = {"foo", "\0"}; - std::shared_ptr app = Moose::createMooseApp("MooseUnitApp", 1, (char **)argv); - const auto & factory = &app->getFactory(); - app->parameters().set("minimal") = true; - app->run(); - Executioner * exec = app->getExecutioner(); - FEProblemBase * fe_problem = &exec->feProblem(); - // JSONFileReader is uninitialized at construction, any other JSONFileReader with such // behavior would do - InputParameters params = factory->getValidParams("JSONFileReader"); - params.set("_fe_problem_base") = fe_problem; - params.set("_subproblem") = fe_problem; - params.set("_sys") = &fe_problem->getNonlinearSystemBase(0); - params.set("_object_name") = "test"; + InputParameters params = _factory.getValidParams("JSONFileReader"); params.set("_type") = "JSONFileReader"; params.set("filename") = "data/json/function_values.json"; - JSONFileReader JSONFileReader(params); + auto & reader = addObject("JSONFileReader", "test", params); // Scalar getters try { Real a; - JSONFileReader.getScalar("not_a_key", a); + reader.getScalar("not_a_key", a); FAIL() << "Missing the expected exception."; } catch (const std::exception & e) @@ -52,7 +38,7 @@ TEST(JSONFileReader, errors) try { Real a; - JSONFileReader.getScalar(std::vector(), a); + reader.getScalar(std::vector(), a); FAIL() << "Missing the expected exception."; } catch (const std::exception & e) @@ -66,7 +52,7 @@ TEST(JSONFileReader, errors) try { std::vector a; - JSONFileReader.getVector("not_a_key", a); + reader.getVector("not_a_key", a); FAIL() << "Missing the expected exception."; } catch (const std::exception & e) @@ -78,7 +64,7 @@ TEST(JSONFileReader, errors) try { std::vector a; - JSONFileReader.getVector(std::vector(), a); + reader.getVector(std::vector(), a); FAIL() << "Missing the expected exception."; } catch (const std::exception & e) @@ -89,38 +75,24 @@ TEST(JSONFileReader, errors) } } -TEST(JSONFileReader, getters) +TEST_F(JSONReaderTest, getters) { - // Create a minimal app that can create objects - const char * argv[2] = {"foo", "\0"}; - const auto & app = Moose::createMooseApp("MooseUnitApp", 1, (char **)argv); - const auto & factory = &app->getFactory(); - app->parameters().set("minimal") = true; - app->run(); - Executioner * exec = app->getExecutioner(); - FEProblemBase * fe_problem = &exec->feProblem(); - - InputParameters params = factory->getValidParams("JSONFileReader"); - params.set("_fe_problem_base") = fe_problem; - params.set("_subproblem") = fe_problem; - params.set("_object_name") = "test"; - params.set("_type") = "JSONFileReader"; + InputParameters params = _factory.getValidParams("JSONFileReader"); params.set("filename") = "data/json/function_values.json"; - params.set("_sys") = &fe_problem->getNonlinearSystemBase(0); - JSONFileReader JSONFileReader(params); + auto & reader = addObject("JSONFileReader", "test", params); // Test scalar getters Real from_json; - JSONFileReader.getScalar("direct_key", from_json); + reader.getScalar("direct_key", from_json); EXPECT_EQ(from_json, 3); - JSONFileReader.getScalar(std::vector({"the_data", "random_other_key"}), from_json); + reader.getScalar(std::vector({"the_data", "random_other_key"}), from_json); EXPECT_EQ(from_json, 2); // Test vector getters std::vector from_json_vec; - JSONFileReader.getVector("direct_vector_key", from_json_vec); + reader.getVector("direct_vector_key", from_json_vec); EXPECT_EQ(from_json_vec[2], 2); - JSONFileReader.getVector(std::vector({"the_data", "some_key", "some_other_key"}), - from_json_vec); + reader.getVector(std::vector({"the_data", "some_key", "some_other_key"}), + from_json_vec); EXPECT_EQ(from_json_vec[2], 7); } diff --git a/unit/src/MooseServerTest.C b/unit/src/MooseServerTest.C index 40011a1b6479..37ac031ceccd 100644 --- a/unit/src/MooseServerTest.C +++ b/unit/src/MooseServerTest.C @@ -542,7 +542,8 @@ TEST_F(MooseServerTest, DocumentOpenAndDiagnostics) wasp::DataObject diagnostics_notification; EXPECT_TRUE( - moose_server->handleDidOpenNotification(didopen_notification, diagnostics_notification)); + moose_server->handleDidOpenNotification(didopen_notification, diagnostics_notification)) + << moose_server->getErrors(); EXPECT_TRUE(moose_server->getErrors().empty()); diff --git a/unit/src/ParsedFunctionTest.C b/unit/src/ParsedFunctionTest.C index d5a2068984eb..9fd1f5e31e68 100644 --- a/unit/src/ParsedFunctionTest.C +++ b/unit/src/ParsedFunctionTest.C @@ -9,21 +9,43 @@ #include "ParsedFunctionTest.h" #include "MathFVUtils.h" +#include "MooseParsedFunction.h" #include "libmesh/fe_map.h" #include "libmesh/quadrature_gauss.h" -TEST_F(ParsedFunctionTest, basicConstructor) +ParsedFunction * +ParsedFunctionTest::fptr(MooseParsedFunction & f) { - InputParameters params = _factory->getValidParams("ParsedFunction"); + return f._function_ptr->_function_ptr.get(); +} + +InputParameters +ParsedFunctionTest::getParams() +{ + InputParameters params = _factory.getValidParams("ParsedFunction"); // test constructor with no additional variables params.set("_fe_problem") = _fe_problem.get(); params.set("_fe_problem_base") = _fe_problem.get(); - params.set("_subproblem") = _fe_problem.get(); + return params; +} + +MooseParsedFunction & +ParsedFunctionTest::buildFunction(InputParameters & params) +{ + const std::string name = "test" + std::to_string(function_index++); + _fe_problem->addFunction("ParsedFunction", name, params); + auto & f = _fe_problem->getFunction(name); + auto parsed_f = dynamic_cast(&f); + mooseAssert(parsed_f, "Failed to cast"); + return *parsed_f; +} + +TEST_F(ParsedFunctionTest, basicConstructor) +{ + auto params = getParams(); params.set("value") = std::string("x + 1.5*y + 2 * z + t/4"); - params.set("_object_name") = "test"; - params.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f(params); + auto & f = buildFunction(params); Moose::Functor f_wrapped(f); f.initialSetup(); EXPECT_EQ(f.value(4, Point(1, 2, 3)), 11); @@ -135,19 +157,13 @@ TEST_F(ParsedFunctionTest, advancedConstructor) std::vector one_var(1); one_var[0] = "q"; - InputParameters params = _factory->getValidParams("ParsedFunction"); - - params.set("_fe_problem") = _fe_problem.get(); - params.set("_fe_problem_base") = _fe_problem.get(); - params.set("_subproblem") = _fe_problem.get(); + auto params = getParams(); params.set("value") = "x + y + q"; params.set>("vars") = one_var; params.set>("vals") = std::vector(1, "-1"); // Dummy value, will be overwritten in test below - params.set("_object_name") = "test1"; - params.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f(params); + auto & f = buildFunction(params); f.initialSetup(); // Access address via pointer to MooseParsedFunctionWrapper that contains pointer to // libMesh::ParsedFunction @@ -161,18 +177,13 @@ TEST_F(ParsedFunctionTest, advancedConstructor) three_vars[1] = "w"; three_vars[2] = "r"; - InputParameters params2 = _factory->getValidParams("ParsedFunction"); - params2.set("_fe_problem") = _fe_problem.get(); - params2.set("_fe_problem_base") = _fe_problem.get(); - params2.set("_subproblem") = _fe_problem.get(); + auto params2 = getParams(); params2.set("value") = "r*x + y/w + q"; params2.set>("vars") = three_vars; params2.set>("vals") = std::vector(3, "-1"); // Dummy values, will be overwritten in test below - params2.set("_object_name") = "test2"; - params2.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f2(params2); + auto & f2 = buildFunction(params2); f2.initialSetup(); fptr(f2)->getVarAddress("q") = 4; fptr(f2)->getVarAddress("w") = 2; @@ -184,17 +195,12 @@ TEST_F(ParsedFunctionTest, advancedConstructor) std::vector one_val(1); one_val[0] = "2.5"; - InputParameters params3 = _factory->getValidParams("ParsedFunction"); - params3.set("_fe_problem") = _fe_problem.get(); - params3.set("_fe_problem_base") = _fe_problem.get(); - params3.set("_subproblem") = _fe_problem.get(); + auto params3 = getParams(); params3.set("value") = "q*x"; params3.set>("vars") = one_var; params3.set>("vals") = one_val; - params3.set("_object_name") = "test3"; - params3.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f3(params3); + auto & f3 = buildFunction(params3); f3.initialSetup(); EXPECT_EQ(f3.value(0, 2), 5); @@ -204,17 +210,12 @@ TEST_F(ParsedFunctionTest, advancedConstructor) three_vals[1] = "1"; three_vals[2] = "0"; - InputParameters params4 = _factory->getValidParams("ParsedFunction"); - params4.set("_fe_problem") = _fe_problem.get(); - params4.set("_fe_problem_base") = _fe_problem.get(); - params4.set("_subproblem") = _fe_problem.get(); + auto params4 = getParams(); params4.set("value") = "q*x + y/r + w"; params4.set>("vars") = three_vars; params4.set>("vals") = three_vals; - params4.set("_object_name") = "test4"; - params4.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f4(params4); + auto & f4 = buildFunction(params4); f4.initialSetup(); fptr(f4)->getVarAddress("r") = 2; EXPECT_EQ(f4.value(0, Point(2, 4)), 6); @@ -231,18 +232,13 @@ TEST_F(ParsedFunctionTest, testVariables) std::vector one_var(1); one_var[0] = "q"; - InputParameters params = _factory->getValidParams("ParsedFunction"); - params.set("_fe_problem") = _fe_problem.get(); - params.set("_fe_problem_base") = _fe_problem.get(); - params.set("_subproblem") = _fe_problem.get(); + auto params = getParams(); params.set("value") = "x + y + q"; params.set>("vars") = one_var; params.set>("vals") = std::vector(1, "-1"); // Dummy value, will be overwritten in test below - params.set("_object_name") = "test1"; - params.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f(params); + auto & f = buildFunction(params); f.initialSetup(); Real & q = fptr(f)->getVarAddress("q"); q = 4; @@ -261,18 +257,13 @@ TEST_F(ParsedFunctionTest, testVariables) three_vars[1] = "w"; three_vars[2] = "r"; - InputParameters params2 = _factory->getValidParams("ParsedFunction"); - params2.set("_fe_problem") = _fe_problem.get(); - params2.set("_fe_problem_base") = _fe_problem.get(); - params2.set("_subproblem") = _fe_problem.get(); + auto params2 = getParams(); params2.set("value") = "r*x + y/w + q"; params2.set>("vars") = three_vars; params2.set>("vals") = std::vector(3, "-1"); // Dummy values, will be overwritten in test below - params2.set("_object_name") = "test2"; - params2.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f2(params2); + auto & f2 = buildFunction(params2); f2.initialSetup(); Real & q2 = fptr(f2)->getVarAddress("q"); Real & w2 = fptr(f2)->getVarAddress("w"); @@ -295,27 +286,17 @@ TEST_F(ParsedFunctionTest, testConstants) { // this functions tests that pi and e get correctly substituted // it also tests built in functions of the function parser - InputParameters params = _factory->getValidParams("ParsedFunction"); - params.set("_object_name") = "test1"; - params.set("_fe_problem") = _fe_problem.get(); - params.set("_fe_problem_base") = _fe_problem.get(); - params.set("_subproblem") = _fe_problem.get(); + auto params = getParams(); params.set("value") = "log(e) + x"; - params.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f(params); + auto & f = buildFunction(params); f.initialSetup(); EXPECT_NEAR(2, f.value(0, 1), 0.0000001); - InputParameters params2 = _factory->getValidParams("ParsedFunction"); - params2.set("_object_name") = "test2"; - params2.set("_fe_problem") = _fe_problem.get(); - params2.set("_fe_problem_base") = _fe_problem.get(); - params2.set("_subproblem") = _fe_problem.get(); + auto params2 = getParams(); params2.set("value") = "sin(pi*x)"; - params2.set("_type") = "MooseParsedFunction"; - MooseParsedFunction f2(params2); + auto & f2 = buildFunction(params2); f2.initialSetup(); EXPECT_NEAR(0, f2.value(0, 1), 0.0000001); EXPECT_NEAR(1, f2.value(0, 0.5), 0.0000001); diff --git a/unit/src/PositionsTest.C b/unit/src/PositionsTest.C index 0fb6398a438b..2e4a9edca0e0 100644 --- a/unit/src/PositionsTest.C +++ b/unit/src/PositionsTest.C @@ -8,33 +8,17 @@ //* https://www.gnu.org/licenses/lgpl-2.1.html #include "gtest/gtest.h" -#include "MultiAppPositions.h" -#include "InputPositions.h" -#include "AppFactory.h" -#include "Executioner.h" -#include "MooseMain.h" -TEST(Positions, getUninitialized) -{ - // Create a minimal app that can create objects - const char * argv[2] = {"foo", "\0"}; - const auto & app = Moose::createMooseApp("MooseUnitApp", 1, (char **)argv); - const auto & factory = &app->getFactory(); - app->parameters().set("minimal") = true; - app->run(); - Executioner * exec = app->getExecutioner(); - FEProblemBase * fe_problem = &exec->feProblem(); +#include "PositionsTest.h" +#include "Positions.h" +TEST_F(PositionsTest, getUninitialized) +{ // MultiAppPositions is uninitialized at construction, any other Positions with such // behavior would do - InputParameters params = factory->getValidParams("MultiAppPositions"); - params.set("_fe_problem_base") = fe_problem; - params.set("_subproblem") = fe_problem; - params.set("_sys") = &fe_problem->getNonlinearSystemBase(0); + InputParameters params = _factory.getValidParams("MultiAppPositions"); params.set>("multiapps") = {"m1"}; - params.set("_object_name") = "test"; - params.set("_type") = "MultiAppPositions"; - MultiAppPositions positions(params); + auto & positions = addObject("MultiAppPositions", "test", params); try { @@ -81,26 +65,12 @@ TEST(Positions, getUninitialized) } } -TEST(Positions, getters) +TEST_F(PositionsTest, getters) { - // Create a minimal app that can create objects - const char * argv[2] = {"foo", "\0"}; - const auto & app = Moose::createMooseApp("MooseUnitApp", 1, (char **)argv); - const auto & factory = &app->getFactory(); - app->parameters().set("minimal") = true; - app->run(); - Executioner * exec = app->getExecutioner(); - FEProblemBase * fe_problem = &exec->feProblem(); - - InputParameters params = factory->getValidParams("InputPositions"); - params.set("_fe_problem_base") = fe_problem; - params.set("_subproblem") = fe_problem; - params.set("_sys") = &fe_problem->getNonlinearSystemBase(0); + InputParameters params = _factory.getValidParams("InputPositions"); params.set>("positions") = {Point(1, 0, 0), Point(0, 0, 1)}; - params.set("_object_name") = "test"; - params.set("_type") = "InputPositions"; params.set("auto_sort") = true; - InputPositions positions(params); + auto & positions = addObject("InputPositions", "test", params); // Test getters EXPECT_EQ(positions.getPositions(false)[0], Point(1, 0, 0)); diff --git a/unit/src/TimesTest.C b/unit/src/TimesTest.C index f8f75a6c8843..d7075aedc110 100644 --- a/unit/src/TimesTest.C +++ b/unit/src/TimesTest.C @@ -8,36 +8,20 @@ //* https://www.gnu.org/licenses/lgpl-2.1.html #include "gtest/gtest.h" -#include "InputTimes.h" -#include "SimulationTimes.h" -#include "AppFactory.h" -#include "Executioner.h" -#include "MooseMain.h" -TEST(Times, getUninitialized) -{ - // Create a minimal app that can create objects - const char * argv[2] = {"foo", "\0"}; - const auto & app = Moose::createMooseApp("MooseUnitApp", 1, (char **)argv); - const auto & factory = &app->getFactory(); - app->parameters().set("minimal") = true; - app->run(); - Executioner * exec = app->getExecutioner(); - FEProblemBase * fe_problem = &exec->feProblem(); +#include "TimesTest.h" +#include "Times.h" +TEST_F(TimesTest, getUninitialized) +{ // SimulationTimes is uninitialized at construction, any other Times with such // behavior would do - InputParameters params = factory->getValidParams("SimulationTimes"); - params.set("_fe_problem_base") = fe_problem; - params.set("_subproblem") = fe_problem; - params.set("_sys") = &fe_problem->getNonlinearSystemBase(0); - params.set("_object_name") = "test"; - params.set("_type") = "SimulationTimes"; - SimulationTimes Times(params); + InputParameters params = _factory.getValidParams("SimulationTimes"); + auto & times = addObject("SimulationTimes", "times", params); try { - Times.getTimes(); + times.getTimes(); FAIL() << "Missing the expected exception."; } catch (const std::exception & e) @@ -47,31 +31,17 @@ TEST(Times, getUninitialized) } } -TEST(Times, getters) +TEST_F(TimesTest, getters) { - // Create a minimal app that can create objects - const char * argv[2] = {"foo", "\0"}; - const auto & app = Moose::createMooseApp("MooseUnitApp", 1, (char **)argv); - const auto & factory = &app->getFactory(); - app->parameters().set("minimal") = true; - app->run(); - Executioner * exec = app->getExecutioner(); - FEProblemBase * fe_problem = &exec->feProblem(); - - InputParameters params = factory->getValidParams("InputTimes"); - params.set("_fe_problem_base") = fe_problem; - params.set("_subproblem") = fe_problem; - params.set("_sys") = &fe_problem->getNonlinearSystemBase(0); + InputParameters params = _factory.getValidParams("InputTimes"); params.set>("times") = {0.2, 0.8, 1.2}; - params.set("_object_name") = "test"; - params.set("_type") = "InputTimes"; - InputTimes Times(params); + auto & times = addObject("InputTimes", "times", params); // Test getters - EXPECT_EQ(Times.getTimes()[0], 0.2); - EXPECT_EQ(*Times.getUniqueTimes().begin(), 0.2); - EXPECT_EQ(Times.getTimeAtIndex(0), 0.2); - EXPECT_EQ(Times.getCurrentTime(), 1); - EXPECT_EQ(Times.getPreviousTime(1), 0.8); - EXPECT_EQ(Times.getNextTime(1), 1.2); + EXPECT_EQ(times.getTimes()[0], 0.2); + EXPECT_EQ(*times.getUniqueTimes().begin(), 0.2); + EXPECT_EQ(times.getTimeAtIndex(0), 0.2); + EXPECT_EQ(times.getCurrentTime(), 0); + EXPECT_EQ(times.getPreviousTime(1), 0.8); + EXPECT_EQ(times.getNextTime(1), 1.2); }