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 : #include "Factory.h"
11 : #include "Registry.h"
12 : #include "InfixIterator.h"
13 : #include "InputParameterWarehouse.h"
14 : #include "FEProblemBase.h"
15 : // Just for testing...
16 : #include "Diffusion.h"
17 :
18 70055 : Factory::Factory(MooseApp & app) : _app(app) {}
19 :
20 64287 : Factory::~Factory() {}
21 :
22 : void
23 109442464 : Factory::reg(std::shared_ptr<RegistryEntryBase> obj)
24 : {
25 109442464 : const std::string obj_name = obj->name();
26 109442464 : const std::string & label = obj->_label;
27 109442464 : const std::string & deprecated_time = obj->_deprecated_time;
28 109442464 : const std::string & replacement_name = obj->_replaced_by;
29 109442464 : const std::string & file = obj->_file;
30 109442464 : const int line = obj->_line;
31 :
32 : // do nothing if we have already added this exact object before
33 109442464 : auto key = std::make_pair(label, obj_name);
34 109442464 : if (_objects_by_label.find(key) != _objects_by_label.end())
35 3 : 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 109443001 : if (_registerable_objects.empty() ||
47 109443001 : _registerable_objects.find(obj_name) != _registerable_objects.end())
48 : {
49 109441924 : if (_name_to_object.find(obj_name) != _name_to_object.end())
50 0 : mooseError("Object '" + obj_name + "' registered from multiple files: ",
51 : file,
52 : " and ",
53 0 : _name_to_line.getInfo(obj_name).file());
54 109441924 : _name_to_object[obj_name] = obj;
55 109441924 : _objects_by_label.insert(key);
56 : }
57 109442461 : _name_to_line.addInfo(obj_name, file, line);
58 :
59 109442461 : if (!replacement_name.empty())
60 3712474 : _deprecated_name[obj_name] = replacement_name;
61 109442461 : if (!deprecated_time.empty())
62 4342168 : _deprecated_time[obj_name] = parseTime(deprecated_time);
63 :
64 : // TODO: Possibly store and print information about objects that are skipped here?
65 109442467 : }
66 :
67 : InputParameters
68 4545762 : Factory::getValidParams(const std::string & obj_name) const
69 : {
70 4545762 : const auto it = _name_to_object.find(obj_name);
71 :
72 : // Check if the object is registered
73 4545762 : if (it == _name_to_object.end())
74 19 : reportUnregisteredError(obj_name);
75 :
76 : // Print out deprecated message, if it exists
77 4545743 : deprecatedMessage(obj_name);
78 :
79 : // Return the parameters
80 4545739 : auto params = it->second->buildParameters();
81 4545739 : params.addPrivateParam(MooseBase::app_param, &_app);
82 :
83 9091478 : return params;
84 0 : }
85 :
86 : template <class ptr_type>
87 : ptr_type
88 2191615 : 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 2191615 : if (deprecated_method_name)
99 : {
100 0 : const std::string name = "Factory::" + *deprecated_method_name;
101 0 : mooseDeprecated(name + "() is deprecated, please use name" + "<T>() instead");
102 0 : }
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 2191615 : auto & warehouse_params = initialize(obj_name, name, parameters, tid);
107 :
108 : // Mark that we're constructing this object
109 2191575 : _currently_constructing.push_back(&warehouse_params);
110 :
111 : // Construct the object
112 2191575 : auto & registry_entry = *_name_to_object.at(obj_name);
113 2191575 : ptr_type obj;
114 : if constexpr (std::is_same_v<ptr_type, std::unique_ptr<MooseObject>>)
115 1956 : obj = registry_entry.build(warehouse_params);
116 : else
117 2189619 : obj = registry_entry.buildShared(warehouse_params);
118 :
119 : // Done constructing the object
120 2189820 : _currently_constructing.pop_back();
121 :
122 2189820 : finalize(obj_name, *obj);
123 :
124 2189820 : return obj;
125 12 : }
126 :
127 : std::unique_ptr<MooseObject>
128 1956 : 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 1956 : std::optional<std::string> deprecated_method_name;
135 1956 : if (print_deprecated)
136 0 : deprecated_method_name = "createUnique";
137 : return createTempl<std::unique_ptr<MooseObject>>(
138 3900 : obj_name, name, parameters, tid, deprecated_method_name);
139 1944 : }
140 :
141 : std::shared_ptr<MooseObject>
142 2189659 : 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 2189659 : std::optional<std::string> deprecated_method_name;
149 2189659 : if (print_deprecated)
150 0 : deprecated_method_name = "create";
151 : return createTempl<std::shared_ptr<MooseObject>>(
152 4377535 : obj_name, name, parameters, tid, deprecated_method_name);
153 2187900 : }
154 :
155 : void
156 500540 : Factory::releaseSharedObjects(const MooseObject & moose_object, THREAD_ID tid)
157 : {
158 500540 : _app.getInputParameterWarehouse().removeInputParameters(moose_object, tid, {});
159 500540 : }
160 :
161 : void
162 2 : Factory::restrictRegisterableObjects(const std::vector<std::string> & names)
163 : {
164 2 : _registerable_objects.insert(names.begin(), names.end());
165 2 : }
166 :
167 : std::time_t
168 4342168 : Factory::parseTime(const std::string t_str)
169 : {
170 : // The string must be a certain length to be valid
171 4342168 : if (t_str.size() != 16)
172 0 : 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 4342168 : time(&t_end);
178 4342168 : t_end_info = localtime(&t_end);
179 4342168 : t_end_info->tm_mon = std::atoi(t_str.substr(0, 2).c_str()) - 1;
180 4342168 : t_end_info->tm_mday = std::atoi(t_str.substr(3, 2).c_str());
181 4342168 : t_end_info->tm_year = std::atoi(t_str.substr(6, 4).c_str()) - 1900;
182 4342168 : t_end_info->tm_hour = std::atoi(t_str.substr(11, 2).c_str()) + 1;
183 4342168 : t_end_info->tm_min = std::atoi(t_str.substr(14, 2).c_str());
184 4342168 : t_end_info->tm_sec = 0;
185 4342168 : t_end = mktime(t_end_info);
186 4342168 : return t_end;
187 : }
188 :
189 : void
190 6740835 : Factory::deprecatedMessage(const std::string obj_name) const
191 : {
192 6740835 : const auto time_it = _deprecated_time.find(obj_name);
193 :
194 : // If the object is not deprecated return
195 6740835 : if (time_it == _deprecated_time.end())
196 6739119 : return;
197 :
198 : // If the message has already been printed, return
199 9756 : if (_deprecated_types.count(obj_name))
200 8040 : return;
201 1716 : _deprecated_types.emplace(obj_name);
202 :
203 : // We dont need a backtrace on this, this is user-facing
204 1716 : const auto current_show_trace = Moose::show_trace;
205 1716 : Moose::show_trace = false;
206 :
207 : // Get the current time
208 : std::time_t now;
209 1716 : time(&now);
210 :
211 : // Get the stop time
212 1716 : std::time_t t_end = time_it->second;
213 :
214 : // Message storage
215 1716 : std::ostringstream msg;
216 :
217 1716 : const auto name_it = _deprecated_name.find(obj_name);
218 :
219 : // Expired object
220 1716 : if (now > t_end)
221 : {
222 1149 : msg << "***** Invalid Object: " << obj_name << " *****\n";
223 1149 : msg << "Expired on " << ctime(&t_end);
224 :
225 : // Append replacement object, if it exists
226 1149 : if (name_it != _deprecated_name.end())
227 453 : msg << "Update your application using the '" << name_it->second << "' object";
228 :
229 : // Produce the error message
230 1149 : mooseDeprecationExpired(msg.str());
231 : }
232 :
233 : // Expiring object
234 : else
235 : {
236 : // Build the basic message
237 567 : msg << "Deprecated Object: " << obj_name << "\n";
238 567 : msg << "This object will be removed on " << ctime(&t_end);
239 :
240 : // Append replacement object, if it exists
241 567 : if (name_it != _deprecated_name.end())
242 196 : msg << "Replace " << obj_name << " with " << name_it->second;
243 :
244 : // Produce the error message
245 567 : mooseDeprecated(msg.str());
246 : }
247 1712 : Moose::show_trace = current_show_trace;
248 1712 : }
249 :
250 : void
251 19 : Factory::reportUnregisteredError(const std::string & obj_name) const
252 : {
253 19 : std::ostringstream oss;
254 19 : std::set<std::string> paths = _app.getLoadedLibraryPaths();
255 :
256 19 : oss << "A '" + obj_name + "' is not a registered object.\n";
257 :
258 19 : if (!paths.empty())
259 : {
260 : oss << "\nWe loaded objects from the following libraries and still couldn't find your "
261 2 : "object:\n\t";
262 2 : std::copy(paths.begin(), paths.end(), infix_ostream_iterator<std::string>(oss, "\n\t"));
263 2 : 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 19 : "MOOSE_LIBRARY_PATH environment variable.";
269 :
270 19 : mooseError(oss.str());
271 0 : }
272 :
273 : std::vector<std::string>
274 0 : Factory::getConstructedObjects() const
275 : {
276 0 : std::vector<std::string> list;
277 0 : for (const auto & name : _constructed_types)
278 0 : list.push_back(name);
279 0 : return list;
280 0 : }
281 :
282 : const InputParameters *
283 2487906 : Factory::currentlyConstructing() const
284 : {
285 2487906 : return _currently_constructing.size() ? _currently_constructing.back() : nullptr;
286 : }
287 :
288 : FileLineInfo
289 491388 : Factory::getLineInfo(const std::string & name) const
290 : {
291 491388 : return _name_to_line.getInfo(name);
292 : }
293 :
294 : void
295 4879582 : Factory::associateNameToClass(const std::string & name, const std::string & class_name)
296 : {
297 4879582 : _name_to_class[name] = class_name;
298 4879582 : }
299 :
300 : std::string
301 491386 : Factory::associatedClassName(const std::string & name) const
302 : {
303 491386 : auto it = _name_to_class.find(name);
304 491386 : if (it == _name_to_class.end())
305 940936 : return "";
306 : else
307 20918 : return it->second;
308 : }
309 :
310 : InputParameters &
311 2195092 : 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 2195092 : const auto it = _name_to_object.find(type);
318 :
319 : // Check if the object is registered
320 2195092 : if (it == _name_to_object.end())
321 0 : reportUnregisteredError(type);
322 :
323 : // Print out deprecated message, if it exists
324 2195092 : deprecatedMessage(type);
325 :
326 : // Create the actual parameters object that the object will reference
327 : InputParameters & params =
328 2195092 : _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 2195080 : if (!params.getHitNode() || params.getHitNode()->isRoot())
335 968714 : if (const auto hit_node = _app.getCurrentActionHitNode())
336 967523 : params.setHitNode(*hit_node, {});
337 :
338 : // Set the type parameter
339 2195080 : params.set<std::string>(MooseBase::type_param) = type;
340 :
341 : // Check to make sure that all required parameters are supplied
342 2195080 : params.finalize(name);
343 :
344 : // register type name as constructed
345 2195052 : _constructed_types.insert(type);
346 :
347 : // add FEProblem pointers to object's params object
348 2195052 : if (_app.actionWarehouse().problemBase())
349 1790997 : _app.actionWarehouse().problemBase()->setInputParametersFEProblem(params);
350 :
351 2195052 : return params;
352 : }
353 :
354 : void
355 2357657 : 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 2357657 : InputParameters orig_params = getValidParams(type);
361 2357657 : const auto & object_params = object.parameters();
362 2357657 : if (orig_params.n_parameters() != object_params.n_parameters())
363 : {
364 1784 : std::set<std::string> orig, populated;
365 71360 : for (const auto & it : orig_params)
366 69576 : orig.emplace(it.first);
367 66008 : for (const auto & it : object_params)
368 64224 : populated.emplace(it.first);
369 :
370 1784 : std::set<std::string> diff;
371 1784 : std::set_difference(populated.begin(),
372 : populated.end(),
373 : orig.begin(),
374 : orig.end(),
375 : std::inserter(diff, diff.begin()));
376 :
377 1784 : if (!diff.empty())
378 : {
379 0 : std::stringstream ss;
380 0 : for (const auto & name : diff)
381 0 : ss << ", " << name;
382 0 : object.mooseError("Attempted to set unregistered parameter(s):\n ", ss.str().substr(2));
383 0 : }
384 1784 : }
385 2357657 : }
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> &);
|