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 66995 : ActionWarehouse::ActionWarehouse(MooseApp & app, Syntax & syntax, ActionFactory & factory)
28 : : ConsoleStreamInterface(app),
29 66995 : _app(app),
30 66995 : _syntax(syntax),
31 66995 : _action_factory(factory),
32 66995 : _generator_valid(false),
33 66995 : _show_action_dependencies(false),
34 66995 : _show_actions(false),
35 66995 : _show_parser(false),
36 66995 : _current_action(nullptr),
37 66995 : _mesh(nullptr),
38 133990 : _displaced_mesh(nullptr)
39 : {
40 66995 : }
41 :
42 62876 : ActionWarehouse::~ActionWarehouse() {}
43 :
44 : void
45 4352 : ActionWarehouse::setFinalTask(const std::string & task)
46 : {
47 4352 : if (!_syntax.hasTask(task))
48 0 : mooseError("cannot use unregistered task '", task, "' as final task");
49 4352 : _final_task = task;
50 4352 : }
51 :
52 : void
53 65942 : ActionWarehouse::build()
54 : {
55 65942 : _ordered_names = _syntax.getSortedTask();
56 9960745 : for (const auto & name : _ordered_names)
57 9894803 : buildBuildableActions(name);
58 65942 : }
59 :
60 : void
61 62874 : ActionWarehouse::clear()
62 : {
63 3181493 : for (auto & ptr : _all_ptrs)
64 3118619 : ptr.reset();
65 :
66 62874 : _action_blocks.clear();
67 62874 : _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 62874 : _problem.reset();
74 62874 : _displaced_mesh.reset();
75 62874 : _mesh.reset();
76 62874 : }
77 :
78 : void
79 3303817 : 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 3303817 : action->parameters().get<std::string>("registered_identifier");
90 3303817 : std::set<std::string> tasks;
91 :
92 3303817 : 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 3303817 : if (action->specificTaskName() != "") // Case 1
123 455835 : tasks.insert(action->specificTaskName());
124 3116041 : else if (registered_identifier == "" &&
125 3652159 : _syntax.getNonDeprecatedSyntaxByAction(action->type()).size() > 1) // Case 2
126 : {
127 75 : std::set<std::string> local_tasks = action->getAllTasks();
128 : mooseAssert(local_tasks.size() == 1, "More than one task inside of the " << action->name());
129 75 : tasks.insert(*local_tasks.begin());
130 75 : }
131 : else // Case 3
132 2847907 : tasks = _action_factory.getTasksByAction(action->type());
133 :
134 : // TODO: Now we need to weed out the double registrations!
135 8432968 : for (const auto & task : tasks)
136 : {
137 : // Some error checking
138 5129154 : 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 5129154 : std::shared_ptr<MooseObjectAction> moa = std::dynamic_pointer_cast<MooseObjectAction>(action);
144 5129154 : if (moa.get())
145 : {
146 1138477 : const InputParameters & mparams = moa->getObjectParams();
147 :
148 1138477 : if (mparams.hasBase())
149 : {
150 1138477 : const std::string & base = mparams.getBase();
151 1138477 : if (!_syntax.verifyMooseObjectTask(base, task))
152 3 : 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 5129151 : action->appendTask(task);
160 :
161 5129151 : 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 5129151 : _action_blocks[task].push_back(action.get());
167 5129151 : }
168 3303814 : _all_ptrs.push_back(action);
169 :
170 3303814 : if (_show_parser)
171 0 : Moose::err << std::endl;
172 3303814 : }
173 :
174 : ActionIterator
175 9351766 : ActionWarehouse::actionBlocksWithActionBegin(const std::string & task)
176 : {
177 9351766 : return _action_blocks[task].begin();
178 : }
179 :
180 : ActionIterator
181 14310141 : ActionWarehouse::actionBlocksWithActionEnd(const std::string & task)
182 : {
183 14310141 : return _action_blocks[task].end();
184 : }
185 :
186 : const std::vector<std::shared_ptr<Action>> &
187 185642 : ActionWarehouse::allActionBlocks() const
188 : {
189 185642 : return _all_ptrs;
190 : }
191 :
192 : const std::list<Action *> &
193 310499 : ActionWarehouse::getActionListByName(const std::string & task) const
194 : {
195 310499 : const auto it = _action_blocks.find(task);
196 310499 : if (it == _action_blocks.end())
197 39659 : return _empty_action_list;
198 : else
199 270840 : return it->second;
200 : }
201 :
202 : bool
203 297705 : ActionWarehouse::hasActions(const std::string & task) const
204 : {
205 297705 : auto it = _action_blocks.find(task);
206 297705 : return it != _action_blocks.end() && !it->second.empty();
207 : }
208 :
209 : void
210 9894803 : ActionWarehouse::buildBuildableActions(const std::string & task)
211 : {
212 9894803 : if (_syntax.shouldAutoBuild(task) && _action_blocks[task].empty())
213 : {
214 1654736 : bool ret_value = false;
215 1654736 : auto it_pair = _action_factory.getActionsByTask(task);
216 3326015 : for (const auto & action_pair : as_range(it_pair))
217 : {
218 1671279 : const auto & type = action_pair.second;
219 1671279 : InputParameters params = _action_factory.getValidParams(type);
220 3342558 : params.set<ActionWarehouse *>("awh") = this;
221 :
222 1671279 : std::string name = "auto_" + type;
223 1671279 : std::transform(
224 46402143 : name.begin(), name.end(), name.begin(), [](const auto v) { return std::tolower(v); });
225 :
226 1671279 : if (params.areAllRequiredParamsValid())
227 : {
228 1556968 : params.set<std::string>("registered_identifier") = "(AutoBuilt)";
229 1556968 : addActionBlock(_action_factory.create(type, name, params));
230 1556968 : ret_value = true;
231 : }
232 1671279 : }
233 :
234 1654736 : if (!ret_value)
235 97768 : _unsatisfied_dependencies.insert(task);
236 : }
237 9894803 : }
238 :
239 : void
240 59829 : ActionWarehouse::checkUnsatisfiedActions() const
241 : {
242 59829 : std::stringstream oss;
243 59829 : bool empty = true;
244 :
245 149379 : for (const auto & udep : _unsatisfied_dependencies)
246 : {
247 89550 : 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 59829 : 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 59829 : }
263 :
264 : void
265 18 : 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 18 : std::ostringstream oss;
277 :
278 18 : const auto & ordered_names = _syntax.getSortedTaskSet();
279 1914 : for (const auto & task_vector : ordered_names)
280 : {
281 1896 : oss << "[DBG][ACT] (" << COLOR_YELLOW;
282 1896 : std::copy(
283 : task_vector.begin(), task_vector.end(), infix_ostream_iterator<std::string>(oss, ", "));
284 1896 : oss << COLOR_DEFAULT << ")\n";
285 :
286 1896 : std::set<std::string> task_set(task_vector.begin(), task_vector.end());
287 4584 : for (const auto & task : task_set)
288 : {
289 2688 : if (_action_blocks.find(task) == _action_blocks.end())
290 1590 : continue;
291 :
292 2334 : for (const auto & act : _action_blocks.at(task))
293 : {
294 : // The Syntax of the Action if it exists
295 1236 : if (act->name() != "")
296 1236 : oss << "[DBG][ACT]\t" << COLOR_GREEN << act->name() << COLOR_DEFAULT << '\n';
297 :
298 : // The task sets
299 1236 : oss << "[DBG][ACT]\t" << act->type();
300 1236 : const std::set<std::string> tasks = act->getAllTasks();
301 1236 : if (tasks.size() > 1)
302 : {
303 738 : oss << " (";
304 : // Break the current Action's tasks into 2 sets, those intersecting with current set and
305 : // then the difference.
306 738 : std::set<std::string> intersection, difference;
307 738 : std::set_intersection(tasks.begin(),
308 : tasks.end(),
309 : task_set.begin(),
310 : task_set.end(),
311 : std::inserter(intersection, intersection.end()));
312 738 : std::set_difference(tasks.begin(),
313 : tasks.end(),
314 : intersection.begin(),
315 : intersection.end(),
316 : std::inserter(difference, difference.end()));
317 :
318 738 : oss << COLOR_CYAN;
319 738 : std::copy(intersection.begin(),
320 : intersection.end(),
321 : infix_ostream_iterator<std::string>(oss, ", "));
322 738 : oss << COLOR_MAGENTA << (difference.empty() ? "" : ", ");
323 738 : std::copy(
324 : difference.begin(), difference.end(), infix_ostream_iterator<std::string>(oss, ", "));
325 738 : oss << COLOR_DEFAULT << ")";
326 738 : }
327 1236 : oss << '\n';
328 1236 : }
329 : }
330 1896 : }
331 :
332 18 : if (_show_action_dependencies)
333 18 : _console << oss.str() << std::endl;
334 18 : }
335 :
336 : void
337 65936 : ActionWarehouse::executeAllActions()
338 : {
339 65936 : _completed_tasks.clear();
340 :
341 65936 : if (_show_action_dependencies)
342 : {
343 18 : _console << "[DBG][ACT] Action Dependency Sets:\n";
344 18 : printActionDependencySets();
345 :
346 18 : _console << "\n[DBG][ACT] Executing actions:" << std::endl;
347 : }
348 :
349 9284923 : for (const auto & task : _ordered_names)
350 : {
351 9225190 : executeActionsWithAction(task);
352 9222886 : std::scoped_lock lock(_completed_tasks_mutex);
353 9222886 : _completed_tasks.insert(task);
354 9222886 : if (_final_task != "" && task == _final_task)
355 3899 : break;
356 9222886 : }
357 :
358 63632 : if (_show_actions)
359 : {
360 : MemoryUtils::Stats stats;
361 66 : MemoryUtils::getMemoryStats(stats);
362 : auto usage =
363 66 : MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes);
364 66 : _console << "[DBG][ACT] Finished executing all actions with memory usage " << usage << "MB\n"
365 66 : << std::endl;
366 : }
367 63632 : }
368 :
369 : void
370 9225190 : ActionWarehouse::executeActionsWithAction(const std::string & task)
371 : {
372 : // Set the current task name
373 9225190 : _current_task = task;
374 :
375 14070848 : for (auto it = actionBlocksWithActionBegin(task); it != actionBlocksWithActionEnd(task); ++it)
376 : {
377 4847962 : _current_action = *it;
378 :
379 4847962 : if (_show_actions)
380 : {
381 : MemoryUtils::Stats stats;
382 5153 : MemoryUtils::getMemoryStats(stats);
383 : auto usage =
384 5153 : MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes);
385 5153 : _console << "[DBG][ACT] "
386 5153 : << "TASK (" << COLOR_YELLOW << std::setw(24) << task << COLOR_DEFAULT << ") "
387 5153 : << "TYPE (" << COLOR_YELLOW << std::setw(32) << _current_action->type()
388 5153 : << COLOR_DEFAULT << ") "
389 5153 : << "NAME (" << COLOR_YELLOW << std::setw(16) << _current_action->name()
390 5153 : << COLOR_DEFAULT << ") Memory usage " << usage << "MB" << std::endl;
391 : }
392 :
393 4847962 : _current_action->timedAct();
394 : }
395 :
396 9222886 : _current_action = nullptr;
397 9222886 : }
398 :
399 : void
400 33635 : ActionWarehouse::printInputFile(std::ostream & out)
401 : {
402 33635 : InputFileFormatter tree(false);
403 :
404 33635 : std::map<std::string, std::vector<Action *>>::iterator iter;
405 :
406 33635 : std::vector<Action *> ordered_actions;
407 5074843 : for (const auto & block : _action_blocks)
408 7725592 : for (const auto & act : block.second)
409 2684384 : ordered_actions.push_back(act);
410 :
411 2718019 : for (const auto & act : ordered_actions)
412 : {
413 2684384 : std::string name;
414 2684384 : if (act->parameters().blockFullpath() != "")
415 1417420 : name = act->parameters().blockFullpath();
416 : else
417 1266964 : name = act->name();
418 2684384 : const std::set<std::string> & tasks = act->getAllTasks();
419 : mooseAssert(!tasks.empty(), "Task list is empty");
420 :
421 : bool is_parent;
422 2684384 : if (_syntax.isAssociated(name, &is_parent) != "")
423 : {
424 1399987 : const auto & all_params = _app.getInputParameterWarehouse().getInputParameters();
425 1399987 : InputParameters & params = *(all_params.find(act->uniqueActionName())->second.get());
426 :
427 : // temporarily allow input parameter copies required by the input file formatter
428 1399987 : params.allowCopy(true);
429 :
430 : // TODO: Do we need to insert more nodes for each task?
431 1399987 : tree.insertNode(name, *tasks.begin(), true, ¶ms);
432 1399987 : params.allowCopy(false);
433 :
434 1399987 : MooseObjectAction * moose_object_action = dynamic_cast<MooseObjectAction *>(act);
435 1399987 : if (moose_object_action)
436 : {
437 610531 : InputParameters obj_params = moose_object_action->getObjectParams();
438 610531 : tree.insertNode(name, *tasks.begin(), false, &obj_params);
439 610531 : }
440 : }
441 2684384 : }
442 :
443 33635 : out << tree.print("");
444 33635 : }
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 90 : ActionWarehouse::getCurrentActionName() const
456 : {
457 90 : 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 221556 : ActionWarehouse::hasTask(const std::string & task) const
468 : {
469 221556 : return _action_factory.isRegisteredTask(task);
470 : }
471 :
472 : bool
473 187285 : ActionWarehouse::isTaskComplete(const std::string & task) const
474 : {
475 187285 : if (!hasTask(task))
476 0 : mooseError("\"", task, "\" is not a registered task.");
477 187285 : std::scoped_lock lock(_completed_tasks_mutex);
478 374570 : return _completed_tasks.count(task);
479 187285 : }
|