https://mooseframework.inl.gov
Factory.C
Go to the documentation of this file.
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 #include "Factory.h"
11 #include "Registry.h"
12 #include "InfixIterator.h"
14 #include "FEProblemBase.h"
15 // Just for testing...
16 #include "Diffusion.h"
17 
18 Factory::Factory(MooseApp & app) : _app(app) {}
19 
21 
22 void
23 Factory::reg(std::shared_ptr<RegistryEntryBase> obj)
24 {
25  const std::string obj_name = obj->name();
26  const std::string & label = obj->_label;
27  const std::string & deprecated_time = obj->_deprecated_time;
28  const std::string & replacement_name = obj->_replaced_by;
29  const std::string & file = obj->_file;
30  const int line = obj->_line;
31 
32  // do nothing if we have already added this exact object before
33  auto key = std::make_pair(label, obj_name);
34  if (_objects_by_label.find(key) != _objects_by_label.end())
35  return;
36 
37  /*
38  * If _registerable_objects has been set the user has requested that we only register some
39  * subset
40  * of the objects for a dynamically loaded application. The objects listed in *this*
41  * application's
42  * registerObjects() method will have already been registered before that member was set.
43  *
44  * If _registerable_objects is empty, the factory is unrestricted
45  */
46  if (_registerable_objects.empty() ||
47  _registerable_objects.find(obj_name) != _registerable_objects.end())
48  {
49  if (_name_to_object.find(obj_name) != _name_to_object.end())
50  mooseError("Object '" + obj_name + "' registered from multiple files: ",
51  file,
52  " and ",
53  _name_to_line.getInfo(obj_name).file());
54  _name_to_object[obj_name] = obj;
55  _objects_by_label.insert(key);
56  }
57  _name_to_line.addInfo(obj_name, file, line);
58 
59  if (!replacement_name.empty())
60  _deprecated_name[obj_name] = replacement_name;
61  if (!deprecated_time.empty())
62  _deprecated_time[obj_name] = parseTime(deprecated_time);
63 
64  // TODO: Possibly store and print information about objects that are skipped here?
65 }
66 
68 Factory::getValidParams(const std::string & obj_name) const
69 {
70  const auto it = _name_to_object.find(obj_name);
71 
72  // Check if the object is registered
73  if (it == _name_to_object.end())
74  reportUnregisteredError(obj_name);
75 
76  // Print out deprecated message, if it exists
77  deprecatedMessage(obj_name);
78 
79  // Return the parameters
80  auto params = it->second->buildParameters();
81  params.addPrivateParam(MooseBase::app_param, &_app);
82 
83  return params;
84 }
85 
86 template <class ptr_type>
87 ptr_type
88 Factory::createTempl(const std::string & obj_name,
89  const std::string & name,
90  const InputParameters & parameters,
91  const THREAD_ID tid,
92  const std::optional<std::string> & deprecated_method_name)
93 {
94  static_assert(std::is_same_v<ptr_type, std::unique_ptr<MooseObject>> ||
95  std::is_same_v<ptr_type, std::shared_ptr<MooseObject>>,
96  "Invalid ptr_type");
97 
98  if (deprecated_method_name)
99  {
100  const std::string name = "Factory::" + *deprecated_method_name;
101  mooseDeprecated(name + "() is deprecated, please use name" + "<T>() instead");
102  }
103 
104  // Build the parameters that are stored in the InputParameterWarehouse for this
105  // object, set a few other things and do a little error checking
106  auto & warehouse_params = initialize(obj_name, name, parameters, tid);
107 
108  // Mark that we're constructing this object
109  _currently_constructing.push_back(&warehouse_params);
110 
111  // Construct the object
112  auto & registry_entry = *_name_to_object.at(obj_name);
113  ptr_type obj;
114  if constexpr (std::is_same_v<ptr_type, std::unique_ptr<MooseObject>>)
115  obj = registry_entry.build(warehouse_params);
116  else
117  obj = registry_entry.buildShared(warehouse_params);
118 
119  // Done constructing the object
120  _currently_constructing.pop_back();
121 
122  finalize(obj_name, *obj);
123 
124  return obj;
125 }
126 
127 std::unique_ptr<MooseObject>
128 Factory::createUnique(const std::string & obj_name,
129  const std::string & name,
130  const InputParameters & parameters,
131  THREAD_ID tid /* =0 */,
132  bool print_deprecated /* =true */)
133 {
134  std::optional<std::string> deprecated_method_name;
135  if (print_deprecated)
136  deprecated_method_name = "createUnique";
137  return createTempl<std::unique_ptr<MooseObject>>(
138  obj_name, name, parameters, tid, deprecated_method_name);
139 }
140 
141 std::shared_ptr<MooseObject>
142 Factory::create(const std::string & obj_name,
143  const std::string & name,
144  const InputParameters & parameters,
145  THREAD_ID tid /* =0 */,
146  bool print_deprecated /* =true */)
147 {
148  std::optional<std::string> deprecated_method_name;
149  if (print_deprecated)
150  deprecated_method_name = "create";
151  return createTempl<std::shared_ptr<MooseObject>>(
152  obj_name, name, parameters, tid, deprecated_method_name);
153 }
154 
155 void
157 {
158  _app.getInputParameterWarehouse().removeInputParameters(moose_object, tid, {});
159 }
160 
161 void
162 Factory::restrictRegisterableObjects(const std::vector<std::string> & names)
163 {
164  _registerable_objects.insert(names.begin(), names.end());
165 }
166 
167 std::time_t
168 Factory::parseTime(const std::string t_str)
169 {
170  // The string must be a certain length to be valid
171  if (t_str.size() != 16)
172  mooseError("The deprecated time not formatted correctly; it must be given as mm/dd/yyyy HH:MM");
173 
174  // Store the time, the time must be specified as: mm/dd/yyyy HH:MM
175  std::time_t t_end;
176  struct tm * t_end_info;
177  time(&t_end);
178  t_end_info = localtime(&t_end);
179  t_end_info->tm_mon = std::atoi(t_str.substr(0, 2).c_str()) - 1;
180  t_end_info->tm_mday = std::atoi(t_str.substr(3, 2).c_str());
181  t_end_info->tm_year = std::atoi(t_str.substr(6, 4).c_str()) - 1900;
182  t_end_info->tm_hour = std::atoi(t_str.substr(11, 2).c_str()) + 1;
183  t_end_info->tm_min = std::atoi(t_str.substr(14, 2).c_str());
184  t_end_info->tm_sec = 0;
185  t_end = mktime(t_end_info);
186  return t_end;
187 }
188 
189 void
190 Factory::deprecatedMessage(const std::string obj_name) const
191 {
192  const auto time_it = _deprecated_time.find(obj_name);
193 
194  // If the object is not deprecated return
195  if (time_it == _deprecated_time.end())
196  return;
197 
198  // If the message has already been printed, return
199  if (_deprecated_types.count(obj_name))
200  return;
201  _deprecated_types.emplace(obj_name);
202 
203  // Get the current time
204  std::time_t now;
205  time(&now);
206 
207  // Get the stop time
208  std::time_t t_end = time_it->second;
209 
210  // Message storage
211  std::ostringstream msg;
212 
213  const auto name_it = _deprecated_name.find(obj_name);
214 
215  // Expired object
216  if (now > t_end)
217  {
218  msg << "***** Invalid Object: " << obj_name << " *****\n";
219  msg << "Expired on " << ctime(&t_end);
220 
221  // Append replacement object, if it exists
222  if (name_it != _deprecated_name.end())
223  msg << "Update your application using the '" << name_it->second << "' object";
224 
225  // Produce the error message
227  }
228 
229  // Expiring object
230  else
231  {
232  // Build the basic message
233  msg << "Deprecated Object: " << obj_name << "\n";
234  msg << "This object will be removed on " << ctime(&t_end);
235 
236  // Append replacement object, if it exists
237  if (name_it != _deprecated_name.end())
238  msg << "Replace " << obj_name << " with " << name_it->second;
239 
240  // Produce the error message
241  mooseDeprecatedNoTrace(msg.str());
242  }
243 }
244 
245 void
246 Factory::reportUnregisteredError(const std::string & obj_name) const
247 {
248  std::ostringstream oss;
249  std::set<std::string> paths = _app.getLoadedLibraryPaths();
250 
251  oss << "A '" + obj_name + "' is not a registered object.\n";
252 
253  if (!paths.empty())
254  {
255  oss << "\nWe loaded objects from the following libraries and still couldn't find your "
256  "object:\n\t";
257  std::copy(paths.begin(), paths.end(), infix_ostream_iterator<std::string>(oss, "\n\t"));
258  oss << '\n';
259  }
260 
261  oss << "\nIf you are trying to find this object in a dynamically loaded library, make sure that\n"
262  "the library can be found either in your \"Problem/library_path\" parameter or in the\n"
263  "MOOSE_LIBRARY_PATH environment variable.";
264 
265  mooseError(oss.str());
266 }
267 
268 std::vector<std::string>
270 {
271  std::vector<std::string> list;
272  for (const auto & name : _constructed_types)
273  list.push_back(name);
274  return list;
275 }
276 
277 const InputParameters *
279 {
280  return _currently_constructing.size() ? _currently_constructing.back() : nullptr;
281 }
282 
284 Factory::getLineInfo(const std::string & name) const
285 {
286  return _name_to_line.getInfo(name);
287 }
288 
289 void
290 Factory::associateNameToClass(const std::string & name, const std::string & class_name)
291 {
292  _name_to_class[name] = class_name;
293 }
294 
295 std::string
296 Factory::associatedClassName(const std::string & name) const
297 {
298  auto it = _name_to_class.find(name);
299  if (it == _name_to_class.end())
300  return "";
301  else
302  return it->second;
303 }
304 
306 Factory::initialize(const std::string & type,
307  const std::string & name,
308  const InputParameters & from_params,
309  const THREAD_ID tid)
310 {
311  // Pointer to the object constructor
312  const auto it = _name_to_object.find(type);
313 
314  // Check if the object is registered
315  if (it == _name_to_object.end())
317 
318  // Print out deprecated message, if it exists
319  deprecatedMessage(type);
320 
321  // Create the actual parameters object that the object will reference
322  InputParameters & params =
323  _app.getInputParameterWarehouse().addInputParameters(name, from_params, tid, {});
324 
325  // Add the hit node from the action if it isn't set already (it might be set
326  // already because someone had a better option than just the action)
327  // If it isn't set, it typically means that this object was created by a
328  // non-MooseObjectAction Action
329  if (!params.getHitNode() || params.getHitNode()->isRoot())
330  if (const auto hit_node = _app.getCurrentActionHitNode())
331  params.setHitNode(*hit_node, {});
332 
333  // Set the type parameter
334  params.set<std::string>(MooseBase::type_param) = type;
335 
336  // Check to make sure that all required parameters are supplied
337  params.finalize(name);
338 
339  // register type name as constructed
340  _constructed_types.insert(type);
341 
342  // add FEProblem pointers to object's params object
344  _app.actionWarehouse().problemBase()->setInputParametersFEProblem(params);
345 
346  return params;
347 }
348 
349 void
350 Factory::finalize(const std::string & type, const MooseObject & object)
351 {
352  // Make sure no unexpected parameters were added by the object's constructor or by the action
353  // initiating this create call. All parameters modified by the constructor must have already
354  // been specified in the object's validParams function.
355  InputParameters orig_params = getValidParams(type);
356  const auto & object_params = object.parameters();
357  if (orig_params.n_parameters() != object_params.n_parameters())
358  {
359  std::set<std::string> orig, populated;
360  for (const auto & it : orig_params)
361  orig.emplace(it.first);
362  for (const auto & it : object_params)
363  populated.emplace(it.first);
364 
365  std::set<std::string> diff;
366  std::set_difference(populated.begin(),
367  populated.end(),
368  orig.begin(),
369  orig.end(),
370  std::inserter(diff, diff.begin()));
371 
372  if (!diff.empty())
373  {
374  std::stringstream ss;
375  for (const auto & name : diff)
376  ss << ", " << name;
377  object.mooseError("Attempted to set unregistered parameter(s):\n ", ss.str().substr(2));
378  }
379  }
380 }
381 
382 // Explicit instantiation for Factory::createTempl
383 template std::unique_ptr<MooseObject>
384 Factory::createTempl<std::unique_ptr<MooseObject>>(const std::string &,
385  const std::string &,
386  const InputParameters &,
387  const THREAD_ID,
388  const std::optional<std::string> &);
389 template std::shared_ptr<MooseObject>
390 Factory::createTempl<std::shared_ptr<MooseObject>>(const std::string &,
391  const std::string &,
392  const InputParameters &,
393  const THREAD_ID,
394  const std::optional<std::string> &);
std::set< std::pair< std::string, std::string > > _objects_by_label
set<label/appname, objectname> used to track if an object previously added is being added again - whi...
Definition: Factory.h:275
std::string name(const ElemQuality q)
void restrictRegisterableObjects(const std::vector< std::string > &names)
Calling this object with a non-empty vector will cause this factory to ignore registrations from any ...
Definition: Factory.C:162
void reportUnregisteredError(const std::string &obj_name) const
Prints error information when an object is not registered.
Definition: Factory.C:246
const hit::Node * getHitNode(const std::string &param) const
static const std::string app_param
The name of the parameter that contains the MooseApp.
Definition: MooseBase.h:59
std::set< std::string > _deprecated_types
Set of deprecated object types that have been printed.
Definition: Factory.h:270
MooseApp & _app
Reference to the application.
Definition: Factory.h:247
static const std::string type_param
The name of the parameter that contains the object type.
Definition: MooseBase.h:53
Factory(MooseApp &app)
Definition: Factory.C:18
std::time_t parseTime(std::string)
Parse time string (mm/dd/yyyy HH:MM)
Definition: Factory.C:168
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
InputParameterWarehouse & getInputParameterWarehouse()
Get the InputParameterWarehouse for MooseObjects.
Definition: MooseApp.C:2594
std::string associatedClassName(const std::string &name) const
Get the associated class name for an object name.
Definition: Factory.C:296
FileLineInfoMap _name_to_line
Definition: Factory.h:252
InputParameters & addInputParameters(const std::string &name, const InputParameters &parameters, THREAD_ID tid, const AddRemoveParamsKey)
Method for adding a new InputParameters object.
virtual ~Factory()
Definition: Factory.C:20
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
std::shared_ptr< MooseObject > create(const std::string &obj_name, const std::string &name, const InputParameters &parameters, THREAD_ID tid=0, bool print_deprecated=true)
Definition: Factory.C:142
InputParameters getValidParams(const std::string &name) const
Get valid parameters for the object.
Definition: Factory.C:68
Base class for MOOSE-based applications.
Definition: MooseApp.h:108
void mooseDeprecationExpiredNoTrace(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition: MooseError.h:392
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const hit::Node * getCurrentActionHitNode() const
Definition: MooseApp.C:2789
void finalize(const std::string &parsing_syntax)
Finalizes the parameters, which must be done before constructing any objects with these parameters (t...
FileLineInfo getInfo(const std::string &key0) const
Get file/line info for a key.
Definition: FileLineInfo.C:76
void addInfo(const std::string &key0, const std::string &file, int line)
Associate a key with file/line info.
Definition: FileLineInfo.C:35
FileLineInfo getLineInfo(const std::string &name) const
Gets file and line information where an object was initially registered.
Definition: Factory.C:284
std::shared_ptr< FEProblemBase > & problemBase()
void deprecatedMessage(const std::string obj_name) const
Show the appropriate message for deprecated objects.
Definition: Factory.C:190
InputParameters & initialize(const std::string &type, const std::string &name, const InputParameters &from_params, const THREAD_ID tid)
Initializes the data structures and the parameters (in the InputParameterWarehouse) for the object wi...
Definition: Factory.C:306
std::map< std::string, std::time_t > _deprecated_time
Storage for deprecated object expiration dates.
Definition: Factory.h:258
void reg(std::shared_ptr< RegistryEntryBase > obj)
Definition: Factory.C:23
void associateNameToClass(const std::string &name, const std::string &class_name)
Associates an object name with a class name.
Definition: Factory.C:290
ptr_type createTempl(const std::string &obj_name, const std::string &name, const InputParameters &parameters, const THREAD_ID tid, const std::optional< std::string > &deprecated_method_name)
Internal method for creating a MooseObject, either as a shared_ptr or as a unique_ptr.
Definition: Factory.C:88
std::set< std::string > _registerable_objects
The list of objects that may be registered.
Definition: Factory.h:264
void removeInputParameters(const MooseObject &moose_object, THREAD_ID tid, const AddRemoveParamsKey)
Allows for the deletion and cleanup of an object while the simulation is running. ...
Every object that can be built by the factory should be derived from this class.
Definition: MooseObject.h:28
ActionWarehouse & actionWarehouse()
Return a writable reference to the ActionWarehouse associated with this app.
Definition: MooseApp.h:216
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition: MooseError.h:363
std::vector< const InputParameters * > _currently_constructing
The object&#39;s parameters that are currently being constructed (if any).
Definition: Factory.h:280
std::map< std::string, std::string > _deprecated_name
Storage for the deprecated objects that have replacements.
Definition: Factory.h:261
Holds file and line information.
Definition: FileLineInfo.h:18
std::map< std::string, std::string > _name_to_class
Object name to class name association.
Definition: Factory.h:255
void releaseSharedObjects(const MooseObject &moose_object, THREAD_ID tid=0)
Releases any shared resources created as a side effect of creating an object through the Factory::cre...
Definition: Factory.C:156
std::map< std::string, std::shared_ptr< RegistryEntryBase > > _name_to_object
Storage for pointers to the object registry entry.
Definition: Factory.h:250
std::string file() const
Definition: FileLineInfo.C:29
void finalize(const std::string &type, const MooseObject &object)
Finalizes the creaction of object of type type.
Definition: Factory.C:350
std::vector< std::string > getConstructedObjects() const
Get a list of all constructed Moose Object types.
Definition: Factory.C:269
std::set< std::string > _constructed_types
Constructed Moose Object types.
Definition: Factory.h:267
void setHitNode(const std::string &param, const hit::Node &node, const SetParamHitNodeKey)
Sets the hit node associated with the parameter param to node.
void mooseDeprecatedNoTrace(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition: MooseError.h:373
std::size_t n_parameters() const
std::unique_ptr< MooseObject > createUnique(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) - THIS METHOD IS DEPRECATED (Use create<T>()) ...
Definition: Factory.C:128
const InputParameters * currentlyConstructing() const
Definition: Factory.C:278
unsigned int THREAD_ID
Definition: MooseTypes.h:237
std::set< std::string > getLoadedLibraryPaths() const
Return the paths of loaded libraries.
Definition: MooseApp.C:2557