Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #pragma once
11 :
12 : #include "InputParameters.h"
13 :
14 : #include <string>
15 : #include <vector>
16 : #include <set>
17 : #include <map>
18 : #include <memory>
19 : #include <optional>
20 :
21 : #include "libmesh/utility.h"
22 :
23 : #ifdef MOOSE_UNIT_TEST
24 : #include <gtest/gtest.h>
25 : #endif
26 :
27 : #define combineNames1(X, Y) X##Y
28 : #define combineNames(X, Y) combineNames1(X, Y)
29 :
30 : /// This is provided as a convenience to globally set certain app names or labels used for
31 : /// objects/actions as allowable. While usually not needed, this macro can be useful for cases
32 : /// when your app/module code may be compiled with other apps without your objects being
33 : /// registered. Calling this multiple times with the same argument is safe.
34 : #define registerKnownLabel(X) \
35 : [[maybe_unused]] static char combineNames(dummy_var_for_known_label, __COUNTER__) = \
36 : Registry::addKnownLabel(X)
37 :
38 : /// add an Action to the registry with the given app name/label as being associated with the given
39 : /// task (quoted string). classname is the (unquoted) c++ class.
40 : #define registerMooseAction(app, classname, task) \
41 : [[maybe_unused]] static char combineNames(dummyvar_for_registering_action_##classname, \
42 : __COUNTER__) = \
43 : Registry::addAction<classname>({app, #classname, "", task, __FILE__, __LINE__, "", ""})
44 :
45 : /// Add a MooseObject to the registry with the given app name/label. classname is the (unquoted)
46 : /// c++ class. Each object/class should only be registered once.
47 : #define registerMooseObject(app, classname) \
48 : [[maybe_unused]] static char combineNames(dummyvar_for_registering_obj_##classname, \
49 : __COUNTER__) = \
50 : Registry::add<classname>({app, #classname, "", "", __FILE__, __LINE__, "", ""})
51 :
52 : #define registerADMooseObject(app, classname) registerMooseObject(app, classname)
53 :
54 : /// Add a MooseObject to the registry with the given app name/label under an alternate alias/name
55 : /// (quoted string) instead of the classname.
56 : #define registerMooseObjectAliased(app, classname, alias) \
57 : [[maybe_unused]] static char combineNames(dummyvar_for_registering_obj_##classname, \
58 : __COUNTER__) = \
59 : Registry::add<classname>({app, #classname, alias, "", __FILE__, __LINE__, "", ""})
60 :
61 : /// Add a deprecated MooseObject to the registry with the given app name/label. time is the time
62 : /// the object became/becomes deprecated in "mm/dd/yyyy HH:MM" format.
63 : #define registerMooseObjectDeprecated(app, classname, time) \
64 : [[maybe_unused]] static char combineNames(dummyvar_for_registering_obj_##classname, \
65 : __COUNTER__) = \
66 : Registry::add<classname>({app, #classname, "", "", __FILE__, __LINE__, time, ""})
67 :
68 : #define registerADMooseObjectDeprecated(app, classname, time) \
69 : registerMooseObjectDeprecated(app, classname, time)
70 :
71 : /// add a deprecated MooseObject to the registry that has been replaced by another
72 : /// object. time is the time the object became/becomes deprecated in "mm/dd/yyyy hh:mm" format.
73 : #define registerMooseObjectReplaced(app, classname, time, replacement) \
74 : [[maybe_unused]] static char combineNames(dummyvar_for_registering_obj_##classname, \
75 : __COUNTER__) = \
76 : Registry::add<classname>({app, #classname, "", "", __FILE__, __LINE__, time, #replacement})
77 :
78 : /// add a deprecated MooseObject orig_class to the registry that has been replaced by another
79 : /// object new_class with the same API. time is the time the object became/becomes deprecated in
80 : /// "mm/dd/yyyy hh:mm" format.
81 : /// A call to registerMooseObject is still required for the new class
82 : #define registerMooseObjectRenamed(app, orig_class, time, new_class) \
83 : [[maybe_unused]] static char combineNames(dummyvar_for_registering_obj_##orig_class, \
84 : __COUNTER__) = \
85 : Registry::add<new_class>( \
86 : {app, #new_class, #orig_class, #orig_class, __FILE__, __LINE__, time, #new_class})
87 :
88 : #define registerADMooseObjectRenamed(app, orig_class, time, new_class) \
89 : registerMooseObjectRenamed(app, orig_class, time, new_class)
90 :
91 : /// Register a non-MooseApp data file path (folder name must be data)
92 : #define registerNonAppDataFilePath(name, path) Registry::addDataFilePath(name, path, false)
93 : /// Register a non-MooseApp data file path (folder name must be data) with extra information
94 : #define registerNonAppDataFilePathWithInfo(name, path, info) \
95 : Registry::addDataFilePath(name, path, false, info)
96 : /// Register a data file path for an application. Uses the current file to register
97 : /// ../../data as a path. The app name must be the APPLICATION_NAME used to build
98 : /// the app (solid_mechanics instead of SolidMechanicsApp, for example)
99 : #define registerAppDataFilePath(app) Registry::addAppDataFilePath(app, __FILE__)
100 : /// Register a missing data file path (adds the data capability as missing)
101 : #define registerMissingDataFilePath(name, info) Registry::addMissingDataFilePath(name, info)
102 : /// Deprecated method; use registerAppDataFilePath instead
103 : #define registerDataFilePath() Registry::addDeprecatedAppDataFilePath(__FILE__)
104 :
105 : #define registerRepository(repo_name, repo_url) Registry::addRepository(repo_name, repo_url);
106 :
107 : class Factory;
108 : class ActionFactory;
109 : class MooseObject;
110 : class Action;
111 : struct RegistryEntryBase;
112 :
113 : /**
114 : * Holds details and meta-data info for a particular MooseObject or Action for use in the
115 : * use in the registry.
116 : */
117 : struct RegistryEntryData
118 : {
119 : /// label (usually app name - e.g. "YourAnimalApp") that the object or action is associated with.
120 : std::string _label;
121 : /// name of the c++ class for the object.
122 : std::string _classname;
123 : /// an alternate name to register the object to factories under.
124 : /// If unspecified, _classname is used.
125 : std::string _alias;
126 : /// name that the object will be registered to factories under. If unspecified, _alias is used.
127 : std::string _name;
128 : /// file path for the c++ file the object or action was added to the registry in.
129 : std::string _file;
130 : /// line number in the c++ file the object or action was added to the registry on.
131 : int _line;
132 : /// time in "mm/dd/yyyy HH:MM" format that the object is/becomes deprecated, blank otherwise.
133 : std::string _deprecated_time;
134 : /// class name for an object that replaces this object if deprecated, blank otherwise.
135 : std::string _replaced_by;
136 : };
137 :
138 : struct RegistryEntryBase : public RegistryEntryData
139 : {
140 106164273 : RegistryEntryBase(const RegistryEntryData & data) : RegistryEntryData(data) {}
141 0 : virtual ~RegistryEntryBase() {}
142 : /// proxy functions
143 : virtual std::unique_ptr<MooseObject> build(const InputParameters & parameters) = 0;
144 : virtual std::shared_ptr<MooseObject> buildShared(const InputParameters & parameters) = 0;
145 : virtual std::shared_ptr<Action> buildAction(const InputParameters & parameters) = 0;
146 : virtual InputParameters buildParameters() = 0;
147 : /// resolve the name from _classname, _alias, and _name
148 323833819 : std::string name() const
149 : {
150 323833819 : std::string name = _name;
151 323833819 : if (name.empty())
152 313684047 : name = _alias;
153 323833819 : if (name.empty())
154 310428092 : name = _classname;
155 323833819 : return name;
156 0 : }
157 : };
158 :
159 : template <typename T>
160 : struct RegistryEntry : public RegistryEntryBase
161 : {
162 : RegistryEntry(const RegistryEntryData & data);
163 : virtual std::unique_ptr<MooseObject> build(const InputParameters & parameters) override;
164 : virtual std::shared_ptr<MooseObject> buildShared(const InputParameters & parameters) override;
165 : virtual std::shared_ptr<Action> buildAction(const InputParameters & parameters) override;
166 : virtual InputParameters buildParameters() override;
167 : };
168 :
169 : /// The registry is used as a global singleton to collect information on all available MooseObject
170 : /// and Action classes for use in a moose app/simulation. It must be global because we want+need
171 : /// to be able to register objects in global scope during static initialization time before other
172 : /// parts of the moose app execution have started running. This allows us to distribute
173 : /// registration across all the files that define the actual classes being registered so we don't
174 : /// have to have any central location with a bajillion includes that makes (especially incremental)
175 : /// compiles slow. The registry collects the app, name, and other information for each objects and
176 : /// makes it available to the moose object and action factories and others for general use. All
177 : /// public functions in this class modify and return data from the global singleton.
178 : class Registry
179 : {
180 : public:
181 : /**
182 : * Get the global Registry singleton.
183 : */
184 : static Registry & getRegistry();
185 :
186 : /// Adds information on a MooseObject to the registry. The _build_ptr, _build_action_ptr, and
187 : /// _params_ptr objects of the info object should all be nullptr - these are set automatically by
188 : /// the add function itself using the templated type T.
189 : template <typename T>
190 93577948 : static char add(const RegistryEntryData & base_info)
191 : {
192 93577948 : const auto info = std::make_shared<RegistryEntry<T>>(base_info);
193 93577948 : getRegistry()._per_label_objects[info->_label].push_back(info);
194 280733844 : getRegistry()._type_to_classname[typeid(T).name()] = info->name();
195 93577948 : return 0;
196 93577948 : }
197 :
198 : /// Adds information on an Action object to the registry. The _build_ptr, _build_action_ptr, and
199 : /// _params_ptr objects of the info object should all be nullptr - these are set automatically by
200 : /// the addAction function itself using the templated type T.
201 : template <typename T>
202 12586325 : static char addAction(const RegistryEntryData & base_info)
203 : {
204 12586325 : const auto info = std::make_shared<RegistryEntry<T>>(base_info);
205 12586325 : getRegistry()._per_label_actions[info->_label].push_back(info);
206 25172650 : getRegistry()._type_to_classname[typeid(T).name()] = info->_classname;
207 12586325 : return 0;
208 12586325 : }
209 :
210 : template <typename T>
211 294 : static std::string getClassName()
212 : {
213 294 : return libmesh_map_find(getRegistry()._type_to_classname, typeid(T).name());
214 : }
215 :
216 : /// This registers all MooseObjects known to the registry that have the given label(s) with the
217 : /// factory f.
218 : static void registerObjectsTo(Factory & f, const std::set<std::string> & labels);
219 :
220 : /// This registers all Actions known to the registry that have the given label(s) with the
221 : /// factory f.
222 : static void registerActionsTo(ActionFactory & f, const std::set<std::string> & labels);
223 :
224 : /// addKnownLabel whitelists a label as valid for purposes of the checkLabels function.
225 : static char addKnownLabel(const std::string & label);
226 :
227 : /// register general search paths; "app" is whether or not the path is an app path
228 : static void addDataFilePath(const std::string & name,
229 : const std::string & in_tree_path,
230 : const bool app = true,
231 : const std::optional<std::string> & info = {});
232 : /// register search paths for an application (path determined relative to app_path);
233 : /// app_path should be passed as __FILE__ from the application source file
234 : static void addAppDataFilePath(const std::string & app_name, const std::string & app_path);
235 : /// register a data file path as missing, along with info about how it can be added
236 : static void addMissingDataFilePath(const std::string & name, const std::string & info);
237 : /// deprecated method; use addAppDataFilePath instead
238 : static void addDeprecatedAppDataFilePath(const std::string & app_path);
239 :
240 : /// register a repository
241 : static void addRepository(const std::string & repo_name, const std::string & repo_url);
242 :
243 : /// Register a citation (the full BibTeX \p bibtex text, identified by \p key) tied to the app
244 : /// \p app_name; emitted by --citations when any object registered to that app is constructed. The
245 : /// framework registers its paper under "MooseApp", so apps composed of MooseApp inherit it.
246 : static void
247 : addAppCitation(const std::string & app_name, const std::string & key, const std::string & bibtex);
248 :
249 : /// Returns a per-label keyed map of all MooseObjects in the registry.
250 42 : static const std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> & allObjects()
251 : {
252 42 : return getRegistry()._per_label_objects;
253 : }
254 : /// Returns a per-label keyed map of all Actions in the registry.
255 42 : static const std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> & allActions()
256 : {
257 42 : return getRegistry()._per_label_actions;
258 : }
259 :
260 : static const RegistryEntryBase & objData(const std::string & name);
261 :
262 : /**
263 : * \returns true if an object with the given name is registered
264 : */
265 2412095 : static bool isRegisteredObj(const std::string & name)
266 : {
267 2412095 : return getRegistry()._name_to_entry.count(name);
268 : }
269 :
270 : /// Returns a map of all registered data file paths (name -> path)
271 21700 : static const std::map<std::string, std::string> & getDataFilePaths()
272 : {
273 21700 : return getRegistry()._data_file_paths;
274 : }
275 : /**
276 : * Gets a data path for the registered name.
277 : *
278 : * Finds either the installed path or the in-tree path.
279 : */
280 : static std::string getDataFilePath(const std::string & name);
281 :
282 : /// Returns the repository URL associated with \p repo_name
283 : static const std::string & getRepositoryURL(const std::string & repo_name);
284 : /**
285 : * Returns a map of all registered repositories
286 : */
287 34 : static const std::map<std::string, std::string> & getRepos() { return getRegistry()._repos; }
288 :
289 : /// Returns the registered citations, keyed by app/module name and then by BibTeX key
290 : /// (app/module name -> (BibTeX key -> BibTeX entry text))
291 2 : static const std::map<std::string, std::map<std::string, std::string>> & getCitations()
292 : {
293 2 : return getRegistry()._app_citations;
294 : }
295 : /// Returns the citations (BibTeX key -> BibTeX entry text) tied to \p app_name, or an empty map
296 : /// if no citations are registered for it. Most apps/modules register none, so the empty result
297 : /// is a normal case: callers iterate over all constructed objects' labels and gather whatever
298 : /// citations exist.
299 : static const std::map<std::string, std::string> & getCitations(const std::string & app_name);
300 :
301 : /// returns the name() for a registered class
302 : template <typename T>
303 : static std::string getRegisteredName();
304 :
305 : ///@{ Don't allow creation through copy/move construction or assignment
306 : Registry(Registry const &) = delete;
307 : Registry & operator=(Registry const &) = delete;
308 :
309 : Registry(Registry &&) = delete;
310 : Registry & operator=(Registry &&) = delete;
311 : ///@}
312 :
313 : private:
314 : #ifdef MOOSE_UNIT_TEST
315 : /// Friends for unit testing
316 : ///@{
317 : friend class RegistryTest;
318 : friend class DataFileUtilsTest;
319 : FRIEND_TEST(RegistryTest, determineFilePath);
320 : FRIEND_TEST(RegistryTest, determineFilePathFailed);
321 : FRIEND_TEST(RegistryTest, appNameFromAppPath);
322 : FRIEND_TEST(RegistryTest, appNameFromAppPathFailed);
323 : FRIEND_TEST(RegistryTest, addDataFilePathCapability);
324 : ///@}
325 : #endif
326 :
327 55280 : Registry() {};
328 :
329 : /**
330 : * Manually set the data file paths.
331 : *
332 : * Used in unit testing.
333 : */
334 128 : static void setDataFilePaths(const std::map<std::string, std::string> & data_file_paths)
335 : {
336 128 : getRegistry()._data_file_paths = data_file_paths;
337 128 : }
338 : /**
339 : * Manually set the repos.
340 : *
341 : * Used in unit testing
342 : */
343 68 : static void setRepos(const std::map<std::string, std::string> & repos)
344 : {
345 68 : getRegistry()._repos = repos;
346 68 : }
347 :
348 : /// Internal helper for determing a root data file path (in-tree vs installed)
349 : static std::string determineDataFilePath(const std::string & name,
350 : const std::string & in_tree_path);
351 :
352 : /// Internal helper for getting an application name from its path, for example:
353 : /// /path/to/FooBarBazApp.C -> foo_bar_baz, for use in addDeprecatedAppDataFilePath
354 : static std::string appNameFromAppPath(const std::string & app_path);
355 :
356 : /// Check a data file path for valid characters
357 : static void checkDataFilePathName(const std::string & name);
358 :
359 : /// Add a data file path capability
360 : static void addDataFilePathCapability(const std::string & name,
361 : const std::optional<std::string> & path = {},
362 : const std::optional<std::string> & extra_info = {});
363 :
364 : std::map<std::string, std::shared_ptr<RegistryEntryBase>> _name_to_entry;
365 : std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> _per_label_objects;
366 : std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> _per_label_actions;
367 : std::set<std::string> _known_labels;
368 : /// Data file registry; name -> in-tree path
369 : std::map<std::string, std::string> _data_file_paths;
370 : /// Repository name -> repository URL; used for mooseDocumentedError
371 : std::map<std::string, std::string> _repos;
372 : std::map<std::string, std::string> _type_to_classname;
373 : /// App/module name -> (citation key -> BibTeX entry text) for that app
374 : std::map<std::string, std::map<std::string, std::string>> _app_citations;
375 : };
376 :
377 : template <typename T>
378 : std::string
379 : Registry::getRegisteredName()
380 : {
381 : mooseDeprecated("Use Registry::getClassName() instead.");
382 : return getClassName<T>();
383 : }
384 :
385 : template <typename T>
386 106164273 : RegistryEntry<T>::RegistryEntry(const RegistryEntryData & data) : RegistryEntryBase(data)
387 : {
388 : static_assert(std::is_base_of_v<MooseObject, T> || std::is_base_of_v<Action, T>,
389 : "Not derived from MooseObject or Action");
390 106164273 : }
391 :
392 : template <typename T>
393 : std::unique_ptr<MooseObject>
394 1987 : RegistryEntry<T>::build(const InputParameters & parameters)
395 : {
396 : if constexpr (std::is_base_of_v<MooseObject, T>)
397 1987 : return std::make_unique<T>(parameters);
398 0 : mooseError(MooseUtils::prettyCppType<T>(), " to be built is not a MooseObject.");
399 : }
400 : template <typename T>
401 : std::shared_ptr<MooseObject>
402 2123648 : RegistryEntry<T>::buildShared(const InputParameters & parameters)
403 : {
404 : if constexpr (std::is_base_of_v<MooseObject, T>)
405 2123648 : return std::make_shared<T>(parameters);
406 0 : mooseError(MooseUtils::prettyCppType<T>(), " to be built is not a MooseObject.");
407 : }
408 :
409 : template <typename T>
410 : std::shared_ptr<Action>
411 3418125 : RegistryEntry<T>::buildAction(const InputParameters & parameters)
412 : {
413 : if constexpr (!std::is_base_of_v<Action, T>)
414 0 : mooseError("The action to be built is not derived from Action.");
415 : else
416 3418125 : return std::make_shared<T>(parameters);
417 : }
418 :
419 : template <typename T>
420 : InputParameters
421 12943964 : RegistryEntry<T>::buildParameters()
422 : {
423 12943964 : auto params = T::validParams();
424 12943964 : return params;
425 : }
|