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 67610 : ActionWarehouse::ActionWarehouse(MooseApp & app, Syntax & syntax, ActionFactory & factory)
28 : : ConsoleStreamInterface(app),
29 67610 : _app(app),
30 67610 : _syntax(syntax),
31 67610 : _action_factory(factory),
32 67610 : _generator_valid(false),
33 67610 : _show_action_dependencies(false),
34 67610 : _show_actions(false),
35 67610 : _show_parser(false),
36 67610 : _current_action(nullptr),
37 67610 : _mesh(nullptr),
38 135220 : _displaced_mesh(nullptr)
39 : {
40 67610 : }
41 :
42 62074 : ActionWarehouse::~ActionWarehouse() {}
43 :
44 : void
45 3968 : ActionWarehouse::setFinalTask(const std::string & task)
46 : {
47 3968 : if (!_syntax.hasTask(task))
48 0 : mooseError("cannot use unregistered task '", task, "' as final task");
49 3968 : _final_task = task;
50 3968 : }
51 :
52 : void
53 66787 : ActionWarehouse::build()
54 : {
55 66787 : _ordered_names = _syntax.getSortedTask();
56 9549816 : for (const auto & name : _ordered_names)
57 9483029 : buildBuildableActions(name);
58 66787 : }
59 :
60 : void
61 62073 : ActionWarehouse::clear()
62 : {
63 3070201 : for (auto & ptr : _all_ptrs)
64 3008128 : ptr.reset();
65 :
66 62073 : _action_blocks.clear();
67 62073 : _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 62073 : _problem.reset();
74 62073 : _displaced_mesh.reset();
75 62073 : _mesh.reset();
76 62073 : }
77 :
78 : void
79 3248954 : 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 3248954 : action->parameters().get<std::string>("registered_identifier");
90 3248954 : std::set<std::string> tasks;
91 :
92 3248954 : 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 3248954 : if (action->specificTaskName() != "") // Case 1
123 458359 : tasks.insert(action->specificTaskName());
124 3060744 : else if (registered_identifier == "" &&
125 3060744 : _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 2790516 : tasks = _action_factory.getTasksByAction(action->type());
133 :
134 : // TODO: Now we need to weed out the double registrations!
135 8346969 : for (const auto & task : tasks)
136 : {
137 : // Some error checking
138 5098019 : 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 5098019 : std::shared_ptr<MooseObjectAction> moa = std::dynamic_pointer_cast<MooseObjectAction>(action);
144 5098019 : if (moa.get())
145 : {
146 1154499 : const InputParameters & mparams = moa->getObjectParams();
147 :
148 1154499 : if (mparams.have_parameter<std::string>("_moose_base"))
149 : {
150 1154499 : const std::string & base = mparams.get<std::string>("_moose_base");
151 1154499 : 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 5098015 : action->appendTask(task);
160 :
161 5098015 : 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 5098015 : _action_blocks[task].push_back(action.get());
167 5098015 : }
168 3248950 : _all_ptrs.push_back(action);
169 :
170 3248950 : if (_show_parser)
171 0 : Moose::err << std::endl;
172 3248950 : }
173 :
174 : ActionIterator
175 11268995 : ActionWarehouse::actionBlocksWithActionBegin(const std::string & task)
176 : {
177 11268995 : return _action_blocks[task].begin();
178 : }
179 :
180 : ActionIterator
181 16205624 : ActionWarehouse::actionBlocksWithActionEnd(const std::string & task)
182 : {
183 16205624 : return _action_blocks[task].end();
184 : }
185 :
186 : const std::vector<std::shared_ptr<Action>> &
187 187943 : ActionWarehouse::allActionBlocks() const
188 : {
189 187943 : return _all_ptrs;
190 : }
191 :
192 : const std::list<Action *> &
193 315210 : ActionWarehouse::getActionListByName(const std::string & task) const
194 : {
195 315210 : const auto it = _action_blocks.find(task);
196 315210 : if (it == _action_blocks.end())
197 40391 : return _empty_action_list;
198 : else
199 274819 : return it->second;
200 : }
201 :
202 : bool
203 303438 : ActionWarehouse::hasActions(const std::string & task) const
204 : {
205 303438 : auto it = _action_blocks.find(task);
206 303438 : return it != _action_blocks.end() && !it->second.empty();
207 : }
208 :
209 : void
210 9483029 : ActionWarehouse::buildBuildableActions(const std::string & task)
211 : {
212 9483029 : if (_syntax.shouldAutoBuild(task) && _action_blocks[task].empty())
213 : {
214 1523935 : bool ret_value = false;
215 1523935 : auto it_pair = _action_factory.getActionsByTask(task);
216 3114632 : for (const auto & action_pair : as_range(it_pair))
217 : {
218 1590697 : InputParameters params = _action_factory.getValidParams(action_pair.second);
219 1590697 : params.set<ActionWarehouse *>("awh") = this;
220 :
221 1590697 : if (params.areAllRequiredParamsValid())
222 : {
223 1480378 : params.set<std::string>("registered_identifier") = "(AutoBuilt)";
224 1480378 : addActionBlock(_action_factory.create(action_pair.second, "", params));
225 1480378 : ret_value = true;
226 : }
227 1590697 : }
228 :
229 1523935 : if (!ret_value)
230 43557 : _unsatisfied_dependencies.insert(task);
231 : }
232 9483029 : }
233 :
234 : void
235 60555 : ActionWarehouse::checkUnsatisfiedActions() const
236 : {
237 60555 : std::stringstream oss;
238 60555 : bool empty = true;
239 :
240 100637 : for (const auto & udep : _unsatisfied_dependencies)
241 : {
242 40082 : if (_action_blocks.find(udep) == _action_blocks.end())
243 : {
244 0 : if (empty)
245 0 : empty = false;
246 : else
247 0 : oss << " ";
248 0 : oss << udep;
249 : }
250 : }
251 :
252 60555 : if (!empty)
253 0 : mooseError(
254 0 : std::string(
255 0 : "The following unsatisfied actions where found while setting up the MOOSE problem:\n") +
256 0 : oss.str() + "\n");
257 60555 : }
258 :
259 : void
260 20 : ActionWarehouse::printActionDependencySets() const
261 : {
262 : /**
263 : * Note: This routine uses the XTerm colors directly which is not advised for general purpose
264 : * output coloring.
265 : * Most users should prefer using Problem::colorText() which respects the "color_output" option
266 : * for terminals
267 : * that do not support coloring. Since this routine is intended for debugging only and runs
268 : * before several
269 : * objects exist in the system, we are just using the constants directly.
270 : */
271 20 : std::ostringstream oss;
272 :
273 20 : const auto & ordered_names = _syntax.getSortedTaskSet();
274 1984 : for (const auto & task_vector : ordered_names)
275 : {
276 1964 : oss << "[DBG][ACT] (" << COLOR_YELLOW;
277 1964 : std::copy(
278 : task_vector.begin(), task_vector.end(), infix_ostream_iterator<std::string>(oss, ", "));
279 1964 : oss << COLOR_DEFAULT << ")\n";
280 :
281 1964 : std::set<std::string> task_set(task_vector.begin(), task_vector.end());
282 4796 : for (const auto & task : task_set)
283 : {
284 2832 : if (_action_blocks.find(task) == _action_blocks.end())
285 1636 : continue;
286 :
287 2540 : for (const auto & act : _action_blocks.at(task))
288 : {
289 : // The Syntax of the Action if it exists
290 1344 : if (act->name() != "")
291 600 : oss << "[DBG][ACT]\t" << COLOR_GREEN << act->name() << COLOR_DEFAULT << '\n';
292 :
293 : // The task sets
294 1344 : oss << "[DBG][ACT]\t" << act->type();
295 1344 : const std::set<std::string> tasks = act->getAllTasks();
296 1344 : if (tasks.size() > 1)
297 : {
298 820 : oss << " (";
299 : // Break the current Action's tasks into 2 sets, those intersecting with current set and
300 : // then the difference.
301 820 : std::set<std::string> intersection, difference;
302 820 : std::set_intersection(tasks.begin(),
303 : tasks.end(),
304 : task_set.begin(),
305 : task_set.end(),
306 : std::inserter(intersection, intersection.end()));
307 820 : std::set_difference(tasks.begin(),
308 : tasks.end(),
309 : intersection.begin(),
310 : intersection.end(),
311 : std::inserter(difference, difference.end()));
312 :
313 820 : oss << COLOR_CYAN;
314 820 : std::copy(intersection.begin(),
315 : intersection.end(),
316 : infix_ostream_iterator<std::string>(oss, ", "));
317 820 : oss << COLOR_MAGENTA << (difference.empty() ? "" : ", ");
318 820 : std::copy(
319 : difference.begin(), difference.end(), infix_ostream_iterator<std::string>(oss, ", "));
320 820 : oss << COLOR_DEFAULT << ")";
321 820 : }
322 1344 : oss << '\n';
323 1344 : }
324 : }
325 1964 : }
326 :
327 20 : if (_show_action_dependencies)
328 20 : _console << oss.str() << std::endl;
329 20 : }
330 :
331 : void
332 66779 : ActionWarehouse::executeAllActions()
333 : {
334 66779 : _completed_tasks.clear();
335 :
336 66779 : if (_show_action_dependencies)
337 : {
338 20 : _console << "[DBG][ACT] Action Dependency Sets:\n";
339 20 : printActionDependencySets();
340 :
341 20 : _console << "\n[DBG][ACT] Executing actions:" << std::endl;
342 : }
343 :
344 8926625 : for (const auto & task : _ordered_names)
345 : {
346 8866190 : executeActionsWithAction(task);
347 8863302 : std::scoped_lock lock(_completed_tasks_mutex);
348 8863302 : _completed_tasks.insert(task);
349 8863302 : if (_final_task != "" && task == _final_task)
350 3456 : break;
351 8863302 : }
352 :
353 63891 : if (_show_actions)
354 : {
355 : MemoryUtils::Stats stats;
356 73 : MemoryUtils::getMemoryStats(stats);
357 : auto usage =
358 73 : MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes);
359 73 : _console << "[DBG][ACT] Finished executing all actions with memory usage " << usage << "MB\n"
360 73 : << std::endl;
361 : }
362 63891 : }
363 :
364 : void
365 8866190 : ActionWarehouse::executeActionsWithAction(const std::string & task)
366 : {
367 : // Set the current task name
368 8866190 : _current_task = task;
369 :
370 13688010 : for (auto it = actionBlocksWithActionBegin(task); it != actionBlocksWithActionEnd(task); ++it)
371 : {
372 4824708 : _current_action = *it;
373 :
374 4824708 : if (_show_actions)
375 : {
376 : MemoryUtils::Stats stats;
377 5660 : MemoryUtils::getMemoryStats(stats);
378 : auto usage =
379 5660 : MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes);
380 5660 : _console << "[DBG][ACT] "
381 5660 : << "TASK (" << COLOR_YELLOW << std::setw(24) << task << COLOR_DEFAULT << ") "
382 5660 : << "TYPE (" << COLOR_YELLOW << std::setw(32) << _current_action->type()
383 5660 : << COLOR_DEFAULT << ") "
384 5660 : << "NAME (" << COLOR_YELLOW << std::setw(16) << _current_action->name()
385 5660 : << COLOR_DEFAULT << ") Memory usage " << usage << "MB" << std::endl;
386 : }
387 :
388 4824708 : _current_action->timedAct();
389 : }
390 :
391 8863302 : _current_action = nullptr;
392 8863302 : }
393 :
394 : void
395 34519 : ActionWarehouse::printInputFile(std::ostream & out)
396 : {
397 34519 : InputFileFormatter tree(false);
398 :
399 34519 : std::map<std::string, std::vector<Action *>>::iterator iter;
400 :
401 34519 : std::vector<Action *> ordered_actions;
402 4933339 : for (const auto & block : _action_blocks)
403 7602810 : for (const auto & act : block.second)
404 2703990 : ordered_actions.push_back(act);
405 :
406 2738509 : for (const auto & act : ordered_actions)
407 : {
408 2703990 : std::string name;
409 2703990 : if (act->parameters().blockFullpath() != "")
410 1453162 : name = act->parameters().blockFullpath();
411 : else
412 1250828 : name = act->name();
413 2703990 : const std::set<std::string> & tasks = act->getAllTasks();
414 : mooseAssert(!tasks.empty(), "Task list is empty");
415 :
416 : bool is_parent;
417 2703990 : if (_syntax.isAssociated(name, &is_parent) != "")
418 : {
419 2686941 : const auto & all_params = _app.getInputParameterWarehouse().getInputParameters();
420 2686941 : InputParameters & params = *(all_params.find(act->uniqueActionName())->second.get());
421 :
422 : // temporarily allow input parameter copies required by the input file formatter
423 2686941 : params.allowCopy(true);
424 :
425 : // TODO: Do we need to insert more nodes for each task?
426 2686941 : tree.insertNode(name, *tasks.begin(), true, ¶ms);
427 2686941 : params.allowCopy(false);
428 :
429 2686941 : MooseObjectAction * moose_object_action = dynamic_cast<MooseObjectAction *>(act);
430 2686941 : if (moose_object_action)
431 : {
432 626656 : InputParameters obj_params = moose_object_action->getObjectParams();
433 626656 : tree.insertNode(name, *tasks.begin(), false, &obj_params);
434 626656 : }
435 : }
436 2703990 : }
437 :
438 34519 : out << tree.print("");
439 34519 : }
440 :
441 : std::shared_ptr<FEProblem>
442 0 : ActionWarehouse::problem()
443 : {
444 0 : mooseDeprecated(
445 : "ActionWarehouse::problem() is deprecated, please use ActionWarehouse::problemBase() \n");
446 0 : return std::dynamic_pointer_cast<FEProblem>(_problem);
447 : }
448 :
449 : std::string
450 100 : ActionWarehouse::getCurrentActionName() const
451 : {
452 100 : return getCurrentAction()->parameters().getHitNode()->fullpath();
453 : }
454 :
455 : const std::string &
456 0 : ActionWarehouse::getMooseAppName()
457 : {
458 0 : return _app.name();
459 : }
460 :
461 : bool
462 182725 : ActionWarehouse::hasTask(const std::string & task) const
463 : {
464 182725 : return _action_factory.isRegisteredTask(task);
465 : }
466 :
467 : bool
468 182333 : ActionWarehouse::isTaskComplete(const std::string & task) const
469 : {
470 182333 : if (!hasTask(task))
471 0 : mooseError("\"", task, "\" is not a registered task.");
472 182333 : std::scoped_lock lock(_completed_tasks_mutex);
473 364666 : return _completed_tasks.count(task);
474 182333 : }
|