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 66995 : Factory::Factory(MooseApp & app) : _app(app) {}
19 :
20 62876 : Factory::~Factory() {}
21 :
22 : void
23 112247459 : Factory::reg(std::shared_ptr<RegistryEntryBase> obj)
24 : {
25 112247459 : const std::string obj_name = obj->name();
26 112247459 : const std::string & label = obj->_label;
27 112247459 : const std::string & deprecated_time = obj->_deprecated_time;
28 112247459 : const std::string & replacement_name = obj->_replaced_by;
29 112247459 : const std::string & file = obj->_file;
30 112247459 : const int line = obj->_line;
31 :
32 : // do nothing if we have already added this exact object before
33 112247459 : auto key = std::make_pair(label, obj_name);
34 112247459 : 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 112247998 : if (_registerable_objects.empty() ||
47 112247998 : _registerable_objects.find(obj_name) != _registerable_objects.end())
48 : {
49 112246917 : 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 112246917 : _name_to_object[obj_name] = obj;
55 112246917 : _objects_by_label.insert(key);
56 : }
57 112247456 : _name_to_line.addInfo(obj_name, file, line);
58 :
59 112247456 : if (!replacement_name.empty())
60 3751118 : _deprecated_name[obj_name] = replacement_name;
61 112247456 : if (!deprecated_time.empty())
62 4352959 : _deprecated_time[obj_name] = parseTime(deprecated_time);
63 :
64 : // TODO: Possibly store and print information about objects that are skipped here?
65 112247462 : }
66 :
67 : InputParameters
68 4315684 : Factory::getValidParams(const std::string & obj_name) const
69 : {
70 4315684 : const auto it = _name_to_object.find(obj_name);
71 :
72 : // Check if the object is registered
73 4315684 : if (it == _name_to_object.end())
74 15 : reportUnregisteredError(obj_name);
75 :
76 : // Print out deprecated message, if it exists
77 4315669 : deprecatedMessage(obj_name);
78 :
79 : // Return the parameters
80 4315666 : auto params = it->second->buildParameters();
81 4315666 : params.addPrivateParam(MooseBase::app_param, &_app);
82 :
83 8631332 : return params;
84 0 : }
85 :
86 : template <class ptr_type>
87 : ptr_type
88 2089382 : 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 2089382 : 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 2089382 : auto & warehouse_params = initialize(obj_name, name, parameters, tid);
107 :
108 : // Mark that we're constructing this object
109 2089347 : _currently_constructing.push_back(&warehouse_params);
110 :
111 : // Construct the object
112 2089347 : auto & registry_entry = *_name_to_object.at(obj_name);
113 2089347 : ptr_type obj;
114 : if constexpr (std::is_same_v<ptr_type, std::unique_ptr<MooseObject>>)
115 1939 : obj = registry_entry.build(warehouse_params);
116 : else
117 2087408 : obj = registry_entry.buildShared(warehouse_params);
118 :
119 : // Done constructing the object
120 2087978 : _currently_constructing.pop_back();
121 :
122 2087978 : finalize(obj_name, *obj);
123 :
124 2087978 : return obj;
125 18 : }
126 :
127 : std::unique_ptr<MooseObject>
128 1939 : 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 1939 : std::optional<std::string> deprecated_method_name;
135 1939 : if (print_deprecated)
136 0 : deprecated_method_name = "createUnique";
137 : return createTempl<std::unique_ptr<MooseObject>>(
138 3869 : obj_name, name, parameters, tid, deprecated_method_name);
139 1930 : }
140 :
141 : std::shared_ptr<MooseObject>
142 2087443 : 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 2087443 : std::optional<std::string> deprecated_method_name;
149 2087443 : if (print_deprecated)
150 0 : deprecated_method_name = "create";
151 : return createTempl<std::shared_ptr<MooseObject>>(
152 4173491 : obj_name, name, parameters, tid, deprecated_method_name);
153 2086080 : }
154 :
155 : void
156 474734 : Factory::releaseSharedObjects(const MooseObject & moose_object, THREAD_ID tid)
157 : {
158 474734 : _app.getInputParameterWarehouse().removeInputParameters(moose_object, tid, {});
159 474734 : }
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 4352959 : Factory::parseTime(const std::string t_str)
169 : {
170 : // The string must be a certain length to be valid
171 4352959 : 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 4352959 : time(&t_end);
178 4352959 : t_end_info = localtime(&t_end);
179 4352959 : t_end_info->tm_mon = std::atoi(t_str.substr(0, 2).c_str()) - 1;
180 4352959 : t_end_info->tm_mday = std::atoi(t_str.substr(3, 2).c_str());
181 4352959 : t_end_info->tm_year = std::atoi(t_str.substr(6, 4).c_str()) - 1900;
182 4352959 : t_end_info->tm_hour = std::atoi(t_str.substr(11, 2).c_str()) + 1;
183 4352959 : t_end_info->tm_min = std::atoi(t_str.substr(14, 2).c_str());
184 4352959 : t_end_info->tm_sec = 0;
185 4352959 : t_end = mktime(t_end_info);
186 4352959 : return t_end;
187 : }
188 :
189 : void
190 6408161 : Factory::deprecatedMessage(const std::string obj_name) const
191 : {
192 6408161 : const auto time_it = _deprecated_time.find(obj_name);
193 :
194 : // If the object is not deprecated return
195 6408161 : if (time_it == _deprecated_time.end())
196 6406135 : return;
197 :
198 : // If the message has already been printed, return
199 10768 : if (_deprecated_types.count(obj_name))
200 8742 : return;
201 2026 : _deprecated_types.emplace(obj_name);
202 :
203 : // Get the current time
204 : std::time_t now;
205 2026 : time(&now);
206 :
207 : // Get the stop time
208 2026 : std::time_t t_end = time_it->second;
209 :
210 : // Message storage
211 2026 : std::ostringstream msg;
212 :
213 2026 : const auto name_it = _deprecated_name.find(obj_name);
214 :
215 : // Expired object
216 2026 : if (now > t_end)
217 : {
218 1350 : msg << "***** Invalid Object: " << obj_name << " *****\n";
219 1350 : msg << "Expired on " << ctime(&t_end);
220 :
221 : // Append replacement object, if it exists
222 1350 : if (name_it != _deprecated_name.end())
223 413 : msg << "Update your application using the '" << name_it->second << "' object";
224 :
225 : // Produce the error message
226 1350 : mooseDeprecationExpiredNoTrace(msg.str());
227 : }
228 :
229 : // Expiring object
230 : else
231 : {
232 : // Build the basic message
233 676 : msg << "Deprecated Object: " << obj_name << "\n";
234 676 : msg << "This object will be removed on " << ctime(&t_end);
235 :
236 : // Append replacement object, if it exists
237 676 : if (name_it != _deprecated_name.end())
238 655 : msg << "Replace " << obj_name << " with " << name_it->second;
239 :
240 : // Produce the error message
241 676 : mooseDeprecatedNoTrace(msg.str());
242 : }
243 2023 : }
244 :
245 : void
246 15 : Factory::reportUnregisteredError(const std::string & obj_name) const
247 : {
248 15 : std::ostringstream oss;
249 15 : std::set<std::string> paths = _app.getLoadedLibraryPaths();
250 :
251 15 : oss << "A '" + obj_name + "' is not a registered object.\n";
252 :
253 15 : if (!paths.empty())
254 : {
255 : oss << "\nWe loaded objects from the following libraries and still couldn't find your "
256 2 : "object:\n\t";
257 2 : std::copy(paths.begin(), paths.end(), infix_ostream_iterator<std::string>(oss, "\n\t"));
258 2 : 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 15 : "MOOSE_LIBRARY_PATH environment variable.";
264 :
265 15 : mooseError(oss.str());
266 0 : }
267 :
268 : std::vector<std::string>
269 0 : Factory::getConstructedObjects() const
270 : {
271 0 : std::vector<std::string> list;
272 0 : for (const auto & name : _constructed_types)
273 0 : list.push_back(name);
274 0 : return list;
275 0 : }
276 :
277 : const InputParameters *
278 2371429 : Factory::currentlyConstructing() const
279 : {
280 2371429 : return _currently_constructing.size() ? _currently_constructing.back() : nullptr;
281 : }
282 :
283 : FileLineInfo
284 63403 : Factory::getLineInfo(const std::string & name) const
285 : {
286 63403 : return _name_to_line.getInfo(name);
287 : }
288 :
289 : void
290 4689035 : Factory::associateNameToClass(const std::string & name, const std::string & class_name)
291 : {
292 4689035 : _name_to_class[name] = class_name;
293 4689035 : }
294 :
295 : std::string
296 63401 : Factory::associatedClassName(const std::string & name) const
297 : {
298 63401 : auto it = _name_to_class.find(name);
299 63401 : if (it == _name_to_class.end())
300 121698 : return "";
301 : else
302 2552 : return it->second;
303 : }
304 :
305 : InputParameters &
306 2092492 : 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 2092492 : const auto it = _name_to_object.find(type);
313 :
314 : // Check if the object is registered
315 2092492 : if (it == _name_to_object.end())
316 0 : reportUnregisteredError(type);
317 :
318 : // Print out deprecated message, if it exists
319 2092492 : deprecatedMessage(type);
320 :
321 : // Create the actual parameters object that the object will reference
322 : InputParameters & params =
323 2092492 : _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 2092480 : if (!params.getHitNode() || params.getHitNode()->isRoot())
330 932802 : if (const auto hit_node = _app.getCurrentActionHitNode())
331 931229 : params.setHitNode(*hit_node, {});
332 :
333 : // Set the type parameter
334 2092480 : params.set<std::string>(MooseBase::type_param) = type;
335 :
336 : // Check to make sure that all required parameters are supplied
337 2092480 : params.finalize(name);
338 :
339 : // register type name as constructed
340 2092457 : _constructed_types.insert(type);
341 :
342 : // add FEProblem pointers to object's params object
343 2092457 : if (_app.actionWarehouse().problemBase())
344 1707199 : _app.actionWarehouse().problemBase()->setInputParametersFEProblem(params);
345 :
346 2092457 : return params;
347 : }
348 :
349 : void
350 2247854 : 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 2247854 : InputParameters orig_params = getValidParams(type);
356 2247854 : const auto & object_params = object.parameters();
357 2247854 : if (orig_params.n_parameters() != object_params.n_parameters())
358 : {
359 1602 : std::set<std::string> orig, populated;
360 64080 : for (const auto & it : orig_params)
361 62478 : orig.emplace(it.first);
362 59274 : for (const auto & it : object_params)
363 57672 : populated.emplace(it.first);
364 :
365 1602 : std::set<std::string> diff;
366 1602 : std::set_difference(populated.begin(),
367 : populated.end(),
368 : orig.begin(),
369 : orig.end(),
370 : std::inserter(diff, diff.begin()));
371 :
372 1602 : if (!diff.empty())
373 : {
374 0 : std::stringstream ss;
375 0 : for (const auto & name : diff)
376 0 : ss << ", " << name;
377 0 : object.mooseError("Attempted to set unregistered parameter(s):\n ", ss.str().substr(2));
378 0 : }
379 1602 : }
380 2247854 : }
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> &);
|