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  // We dont need a backtrace on this, this is user-facing
204  const auto current_show_trace = Moose::show_trace;
205  Moose::show_trace = false;
206 
207  // Get the current time
208  std::time_t now;
209  time(&now);
210 
211  // Get the stop time
212  std::time_t t_end = time_it->second;
213 
214  // Message storage
215  std::ostringstream msg;
216 
217  const auto name_it = _deprecated_name.find(obj_name);
218 
219  // Expired object
220  if (now > t_end)
221  {
222  msg << "***** Invalid Object: " << obj_name << " *****\n";
223  msg << "Expired on " << ctime(&t_end);
224 
225  // Append replacement object, if it exists
226  if (name_it != _deprecated_name.end())
227  msg << "Update your application using the '" << name_it->second << "' object";
228 
229  // Produce the error message
230  mooseDeprecationExpired(msg.str());
231  }
232 
233  // Expiring object
234  else
235  {
236  // Build the basic message
237  msg << "Deprecated Object: " << obj_name << "\n";
238  msg << "This object will be removed on " << ctime(&t_end);
239 
240  // Append replacement object, if it exists
241  if (name_it != _deprecated_name.end())
242  msg << "Replace " << obj_name << " with " << name_it->second;
243 
244  // Produce the error message
245  mooseDeprecated(msg.str());
246  }
247  Moose::show_trace = current_show_trace;
248 }
249 
250 void
251 Factory::reportUnregisteredError(const std::string & obj_name) const
252 {
253  std::ostringstream oss;
254  std::set<std::string> paths = _app.getLoadedLibraryPaths();
255 
256  oss << "A '" + obj_name + "' is not a registered object.\n";
257 
258  if (!paths.empty())
259  {
260  oss << "\nWe loaded objects from the following libraries and still couldn't find your "
261  "object:\n\t";
262  std::copy(paths.begin(), paths.end(), infix_ostream_iterator<std::string>(oss, "\n\t"));
263  oss << '\n';
264  }
265 
266  oss << "\nIf you are trying to find this object in a dynamically loaded library, make sure that\n"
267  "the library can be found either in your \"Problem/library_path\" parameter or in the\n"
268  "MOOSE_LIBRARY_PATH environment variable.";
269 
270  mooseError(oss.str());
271 }
272 
273 std::vector<std::string>
275 {
276  std::vector<std::string> list;
277  for (const auto & name : _constructed_types)
278  list.push_back(name);
279  return list;
280 }
281 
282 const InputParameters *
284 {
285  return _currently_constructing.size() ? _currently_constructing.back() : nullptr;
286 }
287 
289 Factory::getLineInfo(const std::string & name) const
290 {
291  return _name_to_line.getInfo(name);
292 }
293 
294 void
295 Factory::associateNameToClass(const std::string & name, const std::string & class_name)
296 {
297  _name_to_class[name] = class_name;
298 }
299 
300 std::string
301 Factory::associatedClassName(const std::string & name) const
302 {
303  auto it = _name_to_class.find(name);
304  if (it == _name_to_class.end())
305  return "";
306  else
307  return it->second;
308 }
309 
311 Factory::initialize(const std::string & type,
312  const std::string & name,
313  const InputParameters & from_params,
314  const THREAD_ID tid)
315 {
316  // Pointer to the object constructor
317  const auto it = _name_to_object.find(type);
318 
319  // Check if the object is registered
320  if (it == _name_to_object.end())
322 
323  // Print out deprecated message, if it exists
324  deprecatedMessage(type);
325 
326  // Create the actual parameters object that the object will reference
327  InputParameters & params =
328  _app.getInputParameterWarehouse().addInputParameters(name, from_params, tid, {});
329 
330  // Add the hit node from the action if it isn't set already (it might be set
331  // already because someone had a better option than just the action)
332  // If it isn't set, it typically means that this object was created by a
333  // non-MooseObjectAction Action
334  if (!params.getHitNode() || params.getHitNode()->isRoot())
335  if (const auto hit_node = _app.getCurrentActionHitNode())
336  params.setHitNode(*hit_node, {});
337 
338  // Set the type parameter
339  params.set<std::string>(MooseBase::type_param) = type;
340 
341  // Check to make sure that all required parameters are supplied
342  params.finalize(name);
343 
344  // register type name as constructed
345  _constructed_types.insert(type);
346 
347  // add FEProblem pointers to object's params object
349  _app.actionWarehouse().problemBase()->setInputParametersFEProblem(params);
350 
351  return params;
352 }
353 
354 void
355 Factory::finalize(const std::string & type, const MooseObject & object)
356 {
357  // Make sure no unexpected parameters were added by the object's constructor or by the action
358  // initiating this create call. All parameters modified by the constructor must have already
359  // been specified in the object's validParams function.
360  InputParameters orig_params = getValidParams(type);
361  const auto & object_params = object.parameters();
362  if (orig_params.n_parameters() != object_params.n_parameters())
363  {
364  std::set<std::string> orig, populated;
365  for (const auto & it : orig_params)
366  orig.emplace(it.first);
367  for (const auto & it : object_params)
368  populated.emplace(it.first);
369 
370  std::set<std::string> diff;
371  std::set_difference(populated.begin(),
372  populated.end(),
373  orig.begin(),
374  orig.end(),
375  std::inserter(diff, diff.begin()));
376 
377  if (!diff.empty())
378  {
379  std::stringstream ss;
380  for (const auto & name : diff)
381  ss << ", " << name;
382  object.mooseError("Attempted to set unregistered parameter(s):\n ", ss.str().substr(2));
383  }
384  }
385 }
386 
387 // Explicit instantiation for Factory::createTempl
388 template std::unique_ptr<MooseObject>
389 Factory::createTempl<std::unique_ptr<MooseObject>>(const std::string &,
390  const std::string &,
391  const InputParameters &,
392  const THREAD_ID,
393  const std::optional<std::string> &);
394 template std::shared_ptr<MooseObject>
395 Factory::createTempl<std::shared_ptr<MooseObject>>(const std::string &,
396  const std::string &,
397  const InputParameters &,
398  const THREAD_ID,
399  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:251
bool show_trace
Set to true (the default) to print the stack trace with error and warning messages - false to omit it...
Definition: Moose.C:800
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:323
InputParameterWarehouse & getInputParameterWarehouse()
Get the InputParameterWarehouse for MooseObjects.
Definition: MooseApp.C:2983
std::string associatedClassName(const std::string &name) const
Get the associated class name for an object name.
Definition: Factory.C:301
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
void mooseDeprecationExpired(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition: MooseError.h:382
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:103
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const hit::Node * getCurrentActionHitNode() const
Definition: MooseApp.C:3178
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:289
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:311
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:295
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:211
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition: MooseError.h:374
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:355
std::vector< std::string > getConstructedObjects() const
Get a list of all constructed Moose Object types.
Definition: Factory.C:274
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.
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:283
unsigned int THREAD_ID
Definition: MooseTypes.h:237
std::set< std::string > getLoadedLibraryPaths() const
Return the paths of loaded libraries.
Definition: MooseApp.C:2946