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 62755 : Factory::Factory(MooseApp & app) : _app(app) {}
19 :
20 57254 : Factory::~Factory() {}
21 :
22 : void
23 93588376 : Factory::reg(std::shared_ptr<RegistryEntryBase> obj)
24 : {
25 93588376 : const std::string obj_name = obj->name();
26 93588376 : const std::string & label = obj->_label;
27 93588376 : const std::string & deprecated_time = obj->_deprecated_time;
28 93588376 : const std::string & replacement_name = obj->_replaced_by;
29 93588376 : const std::string & file = obj->_file;
30 93588376 : const int line = obj->_line;
31 :
32 : // do nothing if we have already added this exact object before
33 93588376 : auto key = std::make_pair(label, obj_name);
34 93588376 : 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 93588885 : if (_registerable_objects.empty() ||
47 93588885 : _registerable_objects.find(obj_name) != _registerable_objects.end())
48 : {
49 93587864 : 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 93587864 : _name_to_object[obj_name] = obj;
55 93587864 : _objects_by_label.insert(key);
56 : }
57 93588373 : _name_to_line.addInfo(obj_name, file, line);
58 :
59 93588373 : if (!replacement_name.empty())
60 3263072 : _deprecated_name[obj_name] = replacement_name;
61 93588373 : if (!deprecated_time.empty())
62 3701965 : _deprecated_time[obj_name] = parseTime(deprecated_time);
63 :
64 : // TODO: Possibly store and print information about objects that are skipped here?
65 93588379 : }
66 :
67 : InputParameters
68 4022060 : Factory::getValidParams(const std::string & obj_name) const
69 : {
70 4022060 : const auto it = _name_to_object.find(obj_name);
71 :
72 : // Check if the object is registered
73 4022060 : if (it == _name_to_object.end())
74 19 : reportUnregisteredError(obj_name);
75 :
76 : // Print out deprecated message, if it exists
77 4022041 : deprecatedMessage(obj_name);
78 :
79 : // Return the parameters
80 4022037 : auto params = it->second->buildParameters();
81 4022037 : params.addPrivateParam("_moose_app", &_app);
82 :
83 8044074 : return params;
84 0 : }
85 :
86 : std::unique_ptr<MooseObject>
87 1938910 : Factory::createUnique(const std::string & obj_name,
88 : const std::string & name,
89 : const InputParameters & parameters,
90 : THREAD_ID tid /* =0 */,
91 : bool print_deprecated /* =true */)
92 : {
93 1938910 : if (print_deprecated)
94 0 : mooseDeprecated("Factory::create() is deprecated, please use Factory::create<T>() instead");
95 :
96 : // Build the parameters that are stored in the InputParameterWarehouse for this
97 : // object, set a few other things and do a little error checking
98 1938910 : auto & warehouse_params = initialize(obj_name, name, parameters, tid);
99 :
100 : // call the function pointer to build the object
101 1938840 : _currently_constructing.push_back(&warehouse_params);
102 1938840 : auto obj = _name_to_object.at(obj_name)->build(warehouse_params);
103 1937116 : _currently_constructing.pop_back();
104 :
105 1937116 : finalize(obj_name, *obj);
106 :
107 1937116 : return obj;
108 0 : }
109 :
110 : std::shared_ptr<MooseObject>
111 0 : Factory::create(const std::string & obj_name,
112 : const std::string & name,
113 : const InputParameters & parameters,
114 : THREAD_ID tid /* =0 */,
115 : bool print_deprecated /* =true */)
116 : {
117 : std::shared_ptr<MooseObject> object =
118 0 : createUnique(obj_name, name, parameters, tid, print_deprecated);
119 :
120 0 : if (auto fep = std::dynamic_pointer_cast<FEProblemBase>(object))
121 0 : _app.actionWarehouse().problemBase() = fep;
122 :
123 0 : return object;
124 : }
125 :
126 : void
127 451897 : Factory::releaseSharedObjects(const MooseObject & moose_object, THREAD_ID tid)
128 : {
129 451897 : _app.getInputParameterWarehouse().removeInputParameters(moose_object, tid, {});
130 451897 : }
131 :
132 : void
133 2 : Factory::restrictRegisterableObjects(const std::vector<std::string> & names)
134 : {
135 2 : _registerable_objects.insert(names.begin(), names.end());
136 2 : }
137 :
138 : std::time_t
139 3701965 : Factory::parseTime(const std::string t_str)
140 : {
141 : // The string must be a certain length to be valid
142 3701965 : if (t_str.size() != 16)
143 0 : mooseError("The deprecated time not formatted correctly; it must be given as mm/dd/yyyy HH:MM");
144 :
145 : // Store the time, the time must be specified as: mm/dd/yyyy HH:MM
146 : std::time_t t_end;
147 : struct tm * t_end_info;
148 3701965 : time(&t_end);
149 3701965 : t_end_info = localtime(&t_end);
150 3701965 : t_end_info->tm_mon = std::atoi(t_str.substr(0, 2).c_str()) - 1;
151 3701965 : t_end_info->tm_mday = std::atoi(t_str.substr(3, 2).c_str());
152 3701965 : t_end_info->tm_year = std::atoi(t_str.substr(6, 4).c_str()) - 1900;
153 3701965 : t_end_info->tm_hour = std::atoi(t_str.substr(11, 2).c_str()) + 1;
154 3701965 : t_end_info->tm_min = std::atoi(t_str.substr(14, 2).c_str());
155 3701965 : t_end_info->tm_sec = 0;
156 3701965 : t_end = mktime(t_end_info);
157 3701965 : return t_end;
158 : }
159 :
160 : void
161 5964131 : Factory::deprecatedMessage(const std::string obj_name) const
162 : {
163 5964131 : const auto time_it = _deprecated_time.find(obj_name);
164 :
165 : // If the object is not deprecated return
166 5964131 : if (time_it == _deprecated_time.end())
167 5962780 : return;
168 :
169 : // If the message has already been printed, return
170 8168 : if (_deprecated_types.count(obj_name))
171 6817 : return;
172 1351 : _deprecated_types.emplace(obj_name);
173 :
174 : // We dont need a backtrace on this, this is user-facing
175 1351 : const auto current_show_trace = Moose::show_trace;
176 1351 : Moose::show_trace = false;
177 :
178 : // Get the current time
179 : std::time_t now;
180 1351 : time(&now);
181 :
182 : // Get the stop time
183 1351 : std::time_t t_end = time_it->second;
184 :
185 : // Message storage
186 1351 : std::ostringstream msg;
187 :
188 1351 : const auto name_it = _deprecated_name.find(obj_name);
189 :
190 : // Expired object
191 1351 : if (now > t_end)
192 : {
193 1018 : msg << "***** Invalid Object: " << obj_name << " *****\n";
194 1018 : msg << "Expired on " << ctime(&t_end);
195 :
196 : // Append replacement object, if it exists
197 1018 : if (name_it != _deprecated_name.end())
198 374 : msg << "Update your application using the '" << name_it->second << "' object";
199 :
200 : // Produce the error message
201 1018 : mooseDeprecationExpired(msg.str());
202 : }
203 :
204 : // Expiring object
205 : else
206 : {
207 : // Build the basic message
208 333 : msg << "Deprecated Object: " << obj_name << "\n";
209 333 : msg << "This object will be removed on " << ctime(&t_end);
210 :
211 : // Append replacement object, if it exists
212 333 : if (name_it != _deprecated_name.end())
213 22 : msg << "Replace " << obj_name << " with " << name_it->second;
214 :
215 : // Produce the error message
216 333 : mooseDeprecated(msg.str());
217 : }
218 1347 : Moose::show_trace = current_show_trace;
219 1347 : }
220 :
221 : void
222 19 : Factory::reportUnregisteredError(const std::string & obj_name) const
223 : {
224 19 : std::ostringstream oss;
225 19 : std::set<std::string> paths = _app.getLoadedLibraryPaths();
226 :
227 19 : oss << "A '" + obj_name + "' is not a registered object.\n";
228 :
229 19 : if (!paths.empty())
230 : {
231 : oss << "\nWe loaded objects from the following libraries and still couldn't find your "
232 2 : "object:\n\t";
233 2 : std::copy(paths.begin(), paths.end(), infix_ostream_iterator<std::string>(oss, "\n\t"));
234 2 : oss << '\n';
235 : }
236 :
237 : oss << "\nIf you are trying to find this object in a dynamically loaded library, make sure that\n"
238 : "the library can be found either in your \"Problem/library_path\" parameter or in the\n"
239 19 : "MOOSE_LIBRARY_PATH environment variable.";
240 :
241 19 : mooseError(oss.str());
242 0 : }
243 :
244 : std::vector<std::string>
245 0 : Factory::getConstructedObjects() const
246 : {
247 0 : std::vector<std::string> list;
248 0 : for (const auto & name : _constructed_types)
249 0 : list.push_back(name);
250 0 : return list;
251 0 : }
252 :
253 : const InputParameters *
254 2204805 : Factory::currentlyConstructing() const
255 : {
256 2204805 : return _currently_constructing.size() ? _currently_constructing.back() : nullptr;
257 : }
258 :
259 : FileLineInfo
260 404511 : Factory::getLineInfo(const std::string & name) const
261 : {
262 404511 : return _name_to_line.getInfo(name);
263 : }
264 :
265 : void
266 4204397 : Factory::associateNameToClass(const std::string & name, const std::string & class_name)
267 : {
268 4204397 : _name_to_class[name] = class_name;
269 4204397 : }
270 :
271 : std::string
272 404510 : Factory::associatedClassName(const std::string & name) const
273 : {
274 404510 : auto it = _name_to_class.find(name);
275 404510 : if (it == _name_to_class.end())
276 386618 : return "";
277 : else
278 17892 : return it->second;
279 : }
280 :
281 : InputParameters &
282 1942090 : Factory::initialize(const std::string & type,
283 : const std::string & name,
284 : const InputParameters & from_params,
285 : const THREAD_ID tid)
286 : {
287 : // Pointer to the object constructor
288 1942090 : const auto it = _name_to_object.find(type);
289 :
290 : // Check if the object is registered
291 1942090 : if (it == _name_to_object.end())
292 0 : reportUnregisteredError(type);
293 :
294 : // Print out deprecated message, if it exists
295 1942090 : deprecatedMessage(type);
296 :
297 : // Create the actual parameters object that the object will reference
298 : InputParameters & params =
299 1942090 : _app.getInputParameterWarehouse().addInputParameters(name, from_params, tid, {});
300 :
301 : // Add the hit node from the action if it isn't set already (it might be set
302 : // already because someone had a better option than just the action)
303 : // If it isn't set, it typically means that this object was created by a
304 : // non-MooseObjectAction Action
305 1942084 : if (!params.getHitNode() || params.getHitNode()->isRoot())
306 873883 : if (const auto hit_node = _app.getCurrentActionHitNode())
307 873241 : params.setHitNode(*hit_node, {});
308 :
309 : // Set the _type parameter
310 1942084 : params.set<std::string>("_type") = type;
311 :
312 : // Check to make sure that all required parameters are supplied
313 1942084 : params.finalize(name);
314 :
315 : // register type name as constructed
316 1942020 : _constructed_types.insert(type);
317 :
318 : // add FEProblem pointers to object's params object
319 1942020 : if (_app.actionWarehouse().problemBase())
320 1579400 : _app.actionWarehouse().problemBase()->setInputParametersFEProblem(params);
321 :
322 1942020 : return params;
323 : }
324 :
325 : void
326 2087895 : Factory::finalize(const std::string & type, const MooseObject & object)
327 : {
328 : // Make sure no unexpected parameters were added by the object's constructor or by the action
329 : // initiating this create call. All parameters modified by the constructor must have already
330 : // been specified in the object's validParams function.
331 2087895 : InputParameters orig_params = getValidParams(type);
332 2087895 : const auto & object_params = object.parameters();
333 2087895 : if (orig_params.n_parameters() != object_params.n_parameters())
334 : {
335 1674 : std::set<std::string> orig, populated;
336 66960 : for (const auto & it : orig_params)
337 65286 : orig.emplace(it.first);
338 61938 : for (const auto & it : object_params)
339 60264 : populated.emplace(it.first);
340 :
341 1674 : std::set<std::string> diff;
342 1674 : std::set_difference(populated.begin(),
343 : populated.end(),
344 : orig.begin(),
345 : orig.end(),
346 : std::inserter(diff, diff.begin()));
347 :
348 1674 : if (!diff.empty())
349 : {
350 0 : std::stringstream ss;
351 0 : for (const auto & name : diff)
352 0 : ss << ", " << name;
353 0 : object.mooseError("Attempted to set unregistered parameter(s):\n ", ss.str().substr(2));
354 0 : }
355 1674 : }
356 2087895 : }
|