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 "ActionWarehouse.h"
11 : #include "ActionFactory.h"
12 : #include "Parser.h"
13 : #include "MooseObjectAction.h"
14 : #include "InputFileFormatter.h"
15 : #include "InputParameters.h"
16 : #include "MooseMesh.h"
17 : #include "AddVariableAction.h"
18 : #include "AddAuxVariableAction.h"
19 : #include "XTermConstants.h"
20 : #include "InfixIterator.h"
21 : #include "FEProblem.h"
22 : #include "MemoryUtils.h"
23 : #include "InputParameterWarehouse.h"
24 :
25 : #include "libmesh/simple_range.h"
26 :
27 68420 : ActionWarehouse::ActionWarehouse(MooseApp & app, Syntax & syntax, ActionFactory & factory)
28 : : ConsoleStreamInterface(app),
29 68420 : _app(app),
30 68420 : _syntax(syntax),
31 68420 : _action_factory(factory),
32 68420 : _generator_valid(false),
33 68420 : _show_action_dependencies(false),
34 68420 : _show_actions(false),
35 68420 : _show_parser(false),
36 68420 : _current_action(nullptr),
37 68420 : _mesh(nullptr),
38 136840 : _displaced_mesh(nullptr)
39 : {
40 68420 : }
41 :
42 62828 : ActionWarehouse::~ActionWarehouse() {}
43 :
44 : void
45 4102 : ActionWarehouse::setFinalTask(const std::string & task)
46 : {
47 4102 : if (!_syntax.hasTask(task))
48 0 : mooseError("cannot use unregistered task '", task, "' as final task");
49 4102 : _final_task = task;
50 4102 : }
51 :
52 : void
53 67606 : ActionWarehouse::build()
54 : {
55 67606 : _ordered_names = _syntax.getSortedTask();
56 9734733 : for (const auto & name : _ordered_names)
57 9667127 : buildBuildableActions(name);
58 67606 : }
59 :
60 : void
61 62827 : ActionWarehouse::clear()
62 : {
63 3130153 : for (auto & ptr : _all_ptrs)
64 3067326 : ptr.reset();
65 :
66 62827 : _action_blocks.clear();
67 62827 : _generator_valid = false;
68 :
69 : // Due to the way ActionWarehouse is cleaned up (see MooseApp's
70 : // destructor) we must guarantee that ActionWarehouse::clear()
71 : // releases all the resources which have to be released _before_ the
72 : // _comm object owned by the MooseApp is destroyed.
73 62827 : _problem.reset();
74 62827 : _displaced_mesh.reset();
75 62827 : _mesh.reset();
76 62827 : }
77 :
78 : void
79 3314010 : ActionWarehouse::addActionBlock(std::shared_ptr<Action> action)
80 : {
81 : /**
82 : * Note: This routine uses the XTerm colors directly which is not advised for general purpose
83 : * output coloring. Most users should prefer using Problem::colorText() which respects the
84 : * "color_output" option for terminals that do not support coloring. Since this routine is
85 : * intended for debugging only and runs before several objects exist in the system, we are just
86 : * using the constants directly.
87 : */
88 : std::string registered_identifier =
89 3314010 : action->parameters().get<std::string>("registered_identifier");
90 3314010 : std::set<std::string> tasks;
91 :
92 3314010 : if (_show_parser)
93 0 : Moose::err << COLOR_DEFAULT << "Parsing Syntax: " << COLOR_GREEN << action->name()
94 0 : << '\n'
95 0 : << COLOR_DEFAULT << "Building Action: " << COLOR_DEFAULT << action->type()
96 0 : << '\n'
97 0 : << COLOR_DEFAULT << "Registered Identifier: " << COLOR_GREEN << registered_identifier
98 0 : << '\n'
99 0 : << COLOR_DEFAULT << "Specific Task: " << COLOR_CYAN
100 0 : << action->specificTaskName() << std::endl;
101 :
102 : /**
103 : * We need to see if the current Action satisfies multiple tasks. There are a few cases to
104 : * consider:
105 : *
106 : * 1. The current Action is registered with multiple syntax blocks. In this case we can only use
107 : * the current instance to satisfy the specific task listed for this syntax block. We can
108 : * detect this case by inspecting whether it has a "specific task name" set in the Action
109 : * instance.
110 : *
111 : * 2. This action does not have a valid "registered identifier" set in the Action instance. This
112 : * means that this Action was not built by the Parser. It was most likely created through a
113 : * Meta-Action (See Case 3 for exception). In this case, the ActionFactory itself would have
114 : * already set the task it found from the build info used to construct the Action so we'd
115 : * arbitrarily satisfy a single task in this case.
116 : *
117 : * 3. The current Action is registered with only a single syntax block. In this case we can simply
118 : * re-use the current instance to act and satisfy _all_ registered tasks. This is the normal
119 : * case where we have a Parser-built Action that does not have a specific task name to satisfy.
120 : * We will use the Action "type" to retrieve the list of tasks that this Action may satisfy.
121 : */
122 3314010 : if (action->specificTaskName() != "") // Case 1
123 463906 : tasks.insert(action->specificTaskName());
124 3123424 : else if (registered_identifier == "" &&
125 3670064 : _syntax.getNonDeprecatedSyntaxByAction(action->type()).size() > 1) // Case 2
126 : {
127 79 : std::set<std::string> local_tasks = action->getAllTasks();
128 : mooseAssert(local_tasks.size() == 1, "More than one task inside of the " << action->name());
129 79 : tasks.insert(*local_tasks.begin());
130 79 : }
131 : else // Case 3
132 2850025 : tasks = _action_factory.getTasksByAction(action->type());
133 :
134 : // TODO: Now we need to weed out the double registrations!
135 8499679 : for (const auto & task : tasks)
136 : {
137 : // Some error checking
138 5185673 : if (!_syntax.hasTask(task))
139 0 : mooseError("A(n) ", task, " is not a registered task");
140 :
141 : // Make sure that the ObjectAction task and Action task are consistent
142 : // otherwise that means that is action was built by the wrong type
143 5185673 : std::shared_ptr<MooseObjectAction> moa = std::dynamic_pointer_cast<MooseObjectAction>(action);
144 5185673 : if (moa.get())
145 : {
146 1170512 : const InputParameters & mparams = moa->getObjectParams();
147 :
148 1170512 : if (mparams.hasBase())
149 : {
150 1170512 : const std::string & base = mparams.getBase();
151 1170512 : if (!_syntax.verifyMooseObjectTask(base, task))
152 4 : mooseError("Task ", task, " is not registered to build ", base, " derived objects");
153 : }
154 : else
155 0 : mooseError("Unable to locate registered base parameter for ", moa->getMooseObjectType());
156 : }
157 :
158 : // Add the current task to current action
159 5185669 : action->appendTask(task);
160 :
161 5185669 : if (_show_parser)
162 0 : Moose::err << COLOR_YELLOW << "Adding Action: " << COLOR_DEFAULT << action->type()
163 0 : << " (" << COLOR_YELLOW << task << COLOR_DEFAULT << ")" << std::endl;
164 :
165 : // Add it to the warehouse
166 5185669 : _action_blocks[task].push_back(action.get());
167 5185669 : }
168 3314006 : _all_ptrs.push_back(action);
169 :
170 3314006 : if (_show_parser)
171 0 : Moose::err << std::endl;
172 3314006 : }
173 :
174 : ActionIterator
175 11526534 : ActionWarehouse::actionBlocksWithActionBegin(const std::string & task)
176 : {
177 11526534 : return _action_blocks[task].begin();
178 : }
179 :
180 : ActionIterator
181 16543123 : ActionWarehouse::actionBlocksWithActionEnd(const std::string & task)
182 : {
183 16543123 : return _action_blocks[task].end();
184 : }
185 :
186 : const std::vector<std::shared_ptr<Action>> &
187 190140 : ActionWarehouse::allActionBlocks() const
188 : {
189 190140 : return _all_ptrs;
190 : }
191 :
192 : const std::list<Action *> &
193 318856 : ActionWarehouse::getActionListByName(const std::string & task) const
194 : {
195 318856 : const auto it = _action_blocks.find(task);
196 318856 : if (it == _action_blocks.end())
197 40579 : return _empty_action_list;
198 : else
199 278277 : return it->second;
200 : }
201 :
202 : bool
203 306691 : ActionWarehouse::hasActions(const std::string & task) const
204 : {
205 306691 : auto it = _action_blocks.find(task);
206 306691 : return it != _action_blocks.end() && !it->second.empty();
207 : }
208 :
209 : void
210 9667127 : ActionWarehouse::buildBuildableActions(const std::string & task)
211 : {
212 9667127 : if (_syntax.shouldAutoBuild(task) && _action_blocks[task].empty())
213 : {
214 1610185 : bool ret_value = false;
215 1610185 : auto it_pair = _action_factory.getActionsByTask(task);
216 3243650 : for (const auto & action_pair : as_range(it_pair))
217 : {
218 1633465 : const auto & type = action_pair.second;
219 1633465 : InputParameters params = _action_factory.getValidParams(type);
220 3266930 : params.set<ActionWarehouse *>("awh") = this;
221 :
222 1633465 : std::string name = "auto_" + type;
223 1633465 : std::transform(
224 45082573 : name.begin(), name.end(), name.begin(), [](const auto v) { return std::tolower(v); });
225 :
226 1633465 : if (params.areAllRequiredParamsValid())
227 : {
228 1521846 : params.set<std::string>("registered_identifier") = "(AutoBuilt)";
229 1521846 : addActionBlock(_action_factory.create(type, name, params));
230 1521846 : ret_value = true;
231 : }
232 1633465 : }
233 :
234 1610185 : if (!ret_value)
235 88339 : _unsatisfied_dependencies.insert(task);
236 : }
237 9667127 : }
238 :
239 : void
240 61244 : ActionWarehouse::checkUnsatisfiedActions() const
241 : {
242 61244 : std::stringstream oss;
243 61244 : bool empty = true;
244 :
245 142493 : for (const auto & udep : _unsatisfied_dependencies)
246 : {
247 81249 : if (_action_blocks.find(udep) == _action_blocks.end())
248 : {
249 0 : if (empty)
250 0 : empty = false;
251 : else
252 0 : oss << " ";
253 0 : oss << udep;
254 : }
255 : }
256 :
257 61244 : if (!empty)
258 0 : mooseError(
259 0 : std::string(
260 0 : "The following unsatisfied actions where found while setting up the MOOSE problem:\n") +
261 0 : oss.str() + "\n");
262 61244 : }
263 :
264 : void
265 20 : ActionWarehouse::printActionDependencySets() const
266 : {
267 : /**
268 : * Note: This routine uses the XTerm colors directly which is not advised for general purpose
269 : * output coloring.
270 : * Most users should prefer using Problem::colorText() which respects the "color_output" option
271 : * for terminals
272 : * that do not support coloring. Since this routine is intended for debugging only and runs
273 : * before several
274 : * objects exist in the system, we are just using the constants directly.
275 : */
276 20 : std::ostringstream oss;
277 :
278 20 : const auto & ordered_names = _syntax.getSortedTaskSet();
279 2024 : for (const auto & task_vector : ordered_names)
280 : {
281 2004 : oss << "[DBG][ACT] (" << COLOR_YELLOW;
282 2004 : std::copy(
283 : task_vector.begin(), task_vector.end(), infix_ostream_iterator<std::string>(oss, ", "));
284 2004 : oss << COLOR_DEFAULT << ")\n";
285 :
286 2004 : std::set<std::string> task_set(task_vector.begin(), task_vector.end());
287 4856 : for (const auto & task : task_set)
288 : {
289 2852 : if (_action_blocks.find(task) == _action_blocks.end())
290 1636 : continue;
291 :
292 2568 : for (const auto & act : _action_blocks.at(task))
293 : {
294 : // The Syntax of the Action if it exists
295 1352 : if (act->name() != "")
296 1352 : oss << "[DBG][ACT]\t" << COLOR_GREEN << act->name() << COLOR_DEFAULT << '\n';
297 :
298 : // The task sets
299 1352 : oss << "[DBG][ACT]\t" << act->type();
300 1352 : const std::set<std::string> tasks = act->getAllTasks();
301 1352 : if (tasks.size() > 1)
302 : {
303 820 : oss << " (";
304 : // Break the current Action's tasks into 2 sets, those intersecting with current set and
305 : // then the difference.
306 820 : std::set<std::string> intersection, difference;
307 820 : std::set_intersection(tasks.begin(),
308 : tasks.end(),
309 : task_set.begin(),
310 : task_set.end(),
311 : std::inserter(intersection, intersection.end()));
312 820 : std::set_difference(tasks.begin(),
313 : tasks.end(),
314 : intersection.begin(),
315 : intersection.end(),
316 : std::inserter(difference, difference.end()));
317 :
318 820 : oss << COLOR_CYAN;
319 820 : std::copy(intersection.begin(),
320 : intersection.end(),
321 : infix_ostream_iterator<std::string>(oss, ", "));
322 820 : oss << COLOR_MAGENTA << (difference.empty() ? "" : ", ");
323 820 : std::copy(
324 : difference.begin(), difference.end(), infix_ostream_iterator<std::string>(oss, ", "));
325 820 : oss << COLOR_DEFAULT << ")";
326 820 : }
327 1352 : oss << '\n';
328 1352 : }
329 : }
330 2004 : }
331 :
332 20 : if (_show_action_dependencies)
333 20 : _console << oss.str() << std::endl;
334 20 : }
335 :
336 : void
337 67598 : ActionWarehouse::executeAllActions()
338 : {
339 67598 : _completed_tasks.clear();
340 :
341 67598 : if (_show_action_dependencies)
342 : {
343 20 : _console << "[DBG][ACT] Action Dependency Sets:\n";
344 20 : printActionDependencySets();
345 :
346 20 : _console << "\n[DBG][ACT] Executing actions:" << std::endl;
347 : }
348 :
349 9091495 : for (const auto & task : _ordered_names)
350 : {
351 9030371 : executeActionsWithAction(task);
352 9027443 : std::scoped_lock lock(_completed_tasks_mutex);
353 9027443 : _completed_tasks.insert(task);
354 9027443 : if (_final_task != "" && task == _final_task)
355 3546 : break;
356 9027443 : }
357 :
358 64670 : if (_show_actions)
359 : {
360 : MemoryUtils::Stats stats;
361 73 : MemoryUtils::getMemoryStats(stats);
362 : auto usage =
363 73 : MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes);
364 73 : _console << "[DBG][ACT] Finished executing all actions with memory usage " << usage << "MB\n"
365 73 : << std::endl;
366 : }
367 64670 : }
368 :
369 : void
370 9030371 : ActionWarehouse::executeActionsWithAction(const std::string & task)
371 : {
372 : // Set the current task name
373 9030371 : _current_task = task;
374 :
375 13930799 : for (auto it = actionBlocksWithActionBegin(task); it != actionBlocksWithActionEnd(task); ++it)
376 : {
377 4903356 : _current_action = *it;
378 :
379 4903356 : if (_show_actions)
380 : {
381 : MemoryUtils::Stats stats;
382 5690 : MemoryUtils::getMemoryStats(stats);
383 : auto usage =
384 5690 : MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes);
385 5690 : _console << "[DBG][ACT] "
386 5690 : << "TASK (" << COLOR_YELLOW << std::setw(24) << task << COLOR_DEFAULT << ") "
387 5690 : << "TYPE (" << COLOR_YELLOW << std::setw(32) << _current_action->type()
388 5690 : << COLOR_DEFAULT << ") "
389 5690 : << "NAME (" << COLOR_YELLOW << std::setw(16) << _current_action->name()
390 5690 : << COLOR_DEFAULT << ") Memory usage " << usage << "MB" << std::endl;
391 : }
392 :
393 4903356 : _current_action->timedAct();
394 : }
395 :
396 9027443 : _current_action = nullptr;
397 9027443 : }
398 :
399 : void
400 34832 : ActionWarehouse::printInputFile(std::ostream & out)
401 : {
402 34832 : InputFileFormatter tree(false);
403 :
404 34832 : std::map<std::string, std::vector<Action *>>::iterator iter;
405 :
406 34832 : std::vector<Action *> ordered_actions;
407 5012932 : for (const auto & block : _action_blocks)
408 7720515 : for (const auto & act : block.second)
409 2742415 : ordered_actions.push_back(act);
410 :
411 2777247 : for (const auto & act : ordered_actions)
412 : {
413 2742415 : std::string name;
414 2742415 : if (act->parameters().blockFullpath() != "")
415 1468351 : name = act->parameters().blockFullpath();
416 : else
417 1274064 : name = act->name();
418 2742415 : const std::set<std::string> & tasks = act->getAllTasks();
419 : mooseAssert(!tasks.empty(), "Task list is empty");
420 :
421 : bool is_parent;
422 2742415 : if (_syntax.isAssociated(name, &is_parent) != "")
423 : {
424 1451134 : const auto & all_params = _app.getInputParameterWarehouse().getInputParameters();
425 1451134 : InputParameters & params = *(all_params.find(act->uniqueActionName())->second.get());
426 :
427 : // temporarily allow input parameter copies required by the input file formatter
428 1451134 : params.allowCopy(true);
429 :
430 : // TODO: Do we need to insert more nodes for each task?
431 1451134 : tree.insertNode(name, *tasks.begin(), true, ¶ms);
432 1451134 : params.allowCopy(false);
433 :
434 1451134 : MooseObjectAction * moose_object_action = dynamic_cast<MooseObjectAction *>(act);
435 1451134 : if (moose_object_action)
436 : {
437 634025 : InputParameters obj_params = moose_object_action->getObjectParams();
438 634025 : tree.insertNode(name, *tasks.begin(), false, &obj_params);
439 634025 : }
440 : }
441 2742415 : }
442 :
443 34832 : out << tree.print("");
444 34832 : }
445 :
446 : std::shared_ptr<FEProblem>
447 0 : ActionWarehouse::problem()
448 : {
449 0 : mooseDeprecated(
450 : "ActionWarehouse::problem() is deprecated, please use ActionWarehouse::problemBase() \n");
451 0 : return std::dynamic_pointer_cast<FEProblem>(_problem);
452 : }
453 :
454 : std::string
455 100 : ActionWarehouse::getCurrentActionName() const
456 : {
457 100 : return getCurrentAction()->parameters().getHitNode()->fullpath();
458 : }
459 :
460 : const std::string &
461 0 : ActionWarehouse::getMooseAppName()
462 : {
463 0 : return _app.name();
464 : }
465 :
466 : bool
467 217556 : ActionWarehouse::hasTask(const std::string & task) const
468 : {
469 217556 : return _action_factory.isRegisteredTask(task);
470 : }
471 :
472 : bool
473 183921 : ActionWarehouse::isTaskComplete(const std::string & task) const
474 : {
475 183921 : if (!hasTask(task))
476 0 : mooseError("\"", task, "\" is not a registered task.");
477 183921 : std::scoped_lock lock(_completed_tasks_mutex);
478 367842 : return _completed_tasks.count(task);
479 183921 : }
|