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 70119 : ActionWarehouse::ActionWarehouse(MooseApp & app, Syntax & syntax, ActionFactory & factory)
28 : : ConsoleStreamInterface(app),
29 70119 : _app(app),
30 70119 : _syntax(syntax),
31 70119 : _action_factory(factory),
32 70119 : _generator_valid(false),
33 70119 : _show_action_dependencies(false),
34 70119 : _show_actions(false),
35 70119 : _show_parser(false),
36 70119 : _current_action(nullptr),
37 70119 : _mesh(nullptr),
38 140238 : _displaced_mesh(nullptr)
39 : {
40 70119 : }
41 :
42 64353 : ActionWarehouse::~ActionWarehouse() {}
43 :
44 : void
45 4144 : ActionWarehouse::setFinalTask(const std::string & task)
46 : {
47 4144 : if (!_syntax.hasTask(task))
48 0 : mooseError("cannot use unregistered task '", task, "' as final task");
49 4144 : _final_task = task;
50 4144 : }
51 :
52 : void
53 69082 : ActionWarehouse::build()
54 : {
55 69082 : _ordered_names = _syntax.getSortedTask();
56 10018100 : for (const auto & name : _ordered_names)
57 9949018 : buildBuildableActions(name);
58 69082 : }
59 :
60 : void
61 64351 : ActionWarehouse::clear()
62 : {
63 3260904 : for (auto & ptr : _all_ptrs)
64 3196553 : ptr.reset();
65 :
66 64351 : _action_blocks.clear();
67 64351 : _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 64351 : _problem.reset();
74 64351 : _displaced_mesh.reset();
75 64351 : _mesh.reset();
76 64351 : }
77 :
78 : void
79 3456315 : 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 3456315 : action->parameters().get<std::string>("registered_identifier");
90 3456315 : std::set<std::string> tasks;
91 :
92 3456315 : 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 3456315 : if (action->specificTaskName() != "") // Case 1
123 475641 : tasks.insert(action->specificTaskName());
124 3260164 : else if (registered_identifier == "" &&
125 3819144 : _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 2980595 : tasks = _action_factory.getTasksByAction(action->type());
133 :
134 : // TODO: Now we need to weed out the double registrations!
135 8825166 : for (const auto & task : tasks)
136 : {
137 : // Some error checking
138 5368855 : 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 5368855 : std::shared_ptr<MooseObjectAction> moa = std::dynamic_pointer_cast<MooseObjectAction>(action);
144 5368855 : if (moa.get())
145 : {
146 1196693 : const InputParameters & mparams = moa->getObjectParams();
147 :
148 1196693 : if (mparams.hasBase())
149 : {
150 1196693 : const std::string & base = mparams.getBase();
151 1196693 : 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 5368851 : action->appendTask(task);
160 :
161 5368851 : 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 5368851 : _action_blocks[task].push_back(action.get());
167 5368851 : }
168 3456311 : _all_ptrs.push_back(action);
169 :
170 3456311 : if (_show_parser)
171 0 : Moose::err << std::endl;
172 3456311 : }
173 :
174 : ActionIterator
175 9434026 : ActionWarehouse::actionBlocksWithActionBegin(const std::string & task)
176 : {
177 9434026 : return _action_blocks[task].begin();
178 : }
179 :
180 : ActionIterator
181 14627370 : ActionWarehouse::actionBlocksWithActionEnd(const std::string & task)
182 : {
183 14627370 : return _action_blocks[task].end();
184 : }
185 :
186 : const std::vector<std::shared_ptr<Action>> &
187 240241 : ActionWarehouse::allActionBlocks() const
188 : {
189 240241 : return _all_ptrs;
190 : }
191 :
192 : const std::list<Action *> &
193 326260 : ActionWarehouse::getActionListByName(const std::string & task) const
194 : {
195 326260 : const auto it = _action_blocks.find(task);
196 326260 : if (it == _action_blocks.end())
197 41532 : return _empty_action_list;
198 : else
199 284728 : return it->second;
200 : }
201 :
202 : bool
203 313798 : ActionWarehouse::hasActions(const std::string & task) const
204 : {
205 313798 : auto it = _action_blocks.find(task);
206 313798 : return it != _action_blocks.end() && !it->second.empty();
207 : }
208 :
209 : void
210 9949018 : ActionWarehouse::buildBuildableActions(const std::string & task)
211 : {
212 9949018 : if (_syntax.shouldAutoBuild(task) && _action_blocks[task].empty())
213 : {
214 1715018 : bool ret_value = false;
215 1715018 : auto it_pair = _action_factory.getActionsByTask(task);
216 3453516 : for (const auto & action_pair : as_range(it_pair))
217 : {
218 1738498 : const auto & type = action_pair.second;
219 1738498 : InputParameters params = _action_factory.getValidParams(type);
220 3476996 : params.set<ActionWarehouse *>("awh") = this;
221 :
222 1738498 : std::string name = "auto_" + type;
223 1738498 : std::transform(
224 48285965 : name.begin(), name.end(), name.begin(), [](const auto v) { return std::tolower(v); });
225 :
226 1738498 : if (params.areAllRequiredParamsValid())
227 : {
228 1624197 : params.set<std::string>("registered_identifier") = "(AutoBuilt)";
229 1624197 : addActionBlock(_action_factory.create(type, name, params));
230 1624197 : ret_value = true;
231 : }
232 1738498 : }
233 :
234 1715018 : if (!ret_value)
235 90821 : _unsatisfied_dependencies.insert(task);
236 : }
237 9949018 : }
238 :
239 : void
240 62681 : ActionWarehouse::checkUnsatisfiedActions() const
241 : {
242 62681 : std::stringstream oss;
243 62681 : bool empty = true;
244 :
245 146354 : for (const auto & udep : _unsatisfied_dependencies)
246 : {
247 83673 : 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 62681 : 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 62681 : }
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 2044 : for (const auto & task_vector : ordered_names)
280 : {
281 2024 : oss << "[DBG][ACT] (" << COLOR_YELLOW;
282 2024 : std::copy(
283 : task_vector.begin(), task_vector.end(), infix_ostream_iterator<std::string>(oss, ", "));
284 2024 : oss << COLOR_DEFAULT << ")\n";
285 :
286 2024 : std::set<std::string> task_set(task_vector.begin(), task_vector.end());
287 4896 : for (const auto & task : task_set)
288 : {
289 2872 : if (_action_blocks.find(task) == _action_blocks.end())
290 1656 : continue;
291 :
292 2588 : for (const auto & act : _action_blocks.at(task))
293 : {
294 : // The Syntax of the Action if it exists
295 1372 : if (act->name() != "")
296 1372 : oss << "[DBG][ACT]\t" << COLOR_GREEN << act->name() << COLOR_DEFAULT << '\n';
297 :
298 : // The task sets
299 1372 : oss << "[DBG][ACT]\t" << act->type();
300 1372 : const std::set<std::string> tasks = act->getAllTasks();
301 1372 : 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 1372 : oss << '\n';
328 1372 : }
329 : }
330 2024 : }
331 :
332 20 : if (_show_action_dependencies)
333 20 : _console << oss.str() << std::endl;
334 20 : }
335 :
336 : void
337 69074 : ActionWarehouse::executeAllActions()
338 : {
339 69074 : _completed_tasks.clear();
340 :
341 69074 : 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 9363754 : for (const auto & task : _ordered_names)
350 : {
351 9301199 : executeActionsWithAction(task);
352 9298264 : std::scoped_lock lock(_completed_tasks_mutex);
353 9298264 : _completed_tasks.insert(task);
354 9298264 : if (_final_task != "" && task == _final_task)
355 3584 : break;
356 9298264 : }
357 :
358 66139 : 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 66139 : }
368 :
369 : void
370 9301199 : ActionWarehouse::executeActionsWithAction(const std::string & task)
371 : {
372 : // Set the current task name
373 9301199 : _current_task = task;
374 :
375 14375563 : for (auto it = actionBlocksWithActionBegin(task); it != actionBlocksWithActionEnd(task); ++it)
376 : {
377 5077299 : _current_action = *it;
378 :
379 5077299 : if (_show_actions)
380 : {
381 : MemoryUtils::Stats stats;
382 5763 : MemoryUtils::getMemoryStats(stats);
383 : auto usage =
384 5763 : MemoryUtils::convertBytes(stats._physical_memory, MemoryUtils::MemUnits::Megabytes);
385 5763 : _console << "[DBG][ACT] "
386 5763 : << "TASK (" << COLOR_YELLOW << std::setw(24) << task << COLOR_DEFAULT << ") "
387 5763 : << "TYPE (" << COLOR_YELLOW << std::setw(32) << _current_action->type()
388 5763 : << COLOR_DEFAULT << ") "
389 5763 : << "NAME (" << COLOR_YELLOW << std::setw(16) << _current_action->name()
390 5763 : << COLOR_DEFAULT << ") Memory usage " << usage << "MB" << std::endl;
391 : }
392 :
393 5077299 : _current_action->timedAct();
394 : }
395 :
396 9298264 : _current_action = nullptr;
397 9298264 : }
398 :
399 : void
400 35637 : ActionWarehouse::printInputFile(std::ostream & out)
401 : {
402 35637 : InputFileFormatter tree(false);
403 :
404 35637 : std::map<std::string, std::vector<Action *>>::iterator iter;
405 :
406 35637 : std::vector<Action *> ordered_actions;
407 5165571 : for (const auto & block : _action_blocks)
408 7968943 : for (const auto & act : block.second)
409 2839009 : ordered_actions.push_back(act);
410 :
411 2874646 : for (const auto & act : ordered_actions)
412 : {
413 2839009 : std::string name;
414 2839009 : if (act->parameters().blockFullpath() != "")
415 1499757 : name = act->parameters().blockFullpath();
416 : else
417 1339252 : name = act->name();
418 2839009 : const std::set<std::string> & tasks = act->getAllTasks();
419 : mooseAssert(!tasks.empty(), "Task list is empty");
420 :
421 : bool is_parent;
422 2839009 : if (_syntax.isAssociated(name, &is_parent) != "")
423 : {
424 1482228 : const auto & all_params = _app.getInputParameterWarehouse().getInputParameters();
425 1482228 : InputParameters & params = *(all_params.find(act->uniqueActionName())->second.get());
426 :
427 : // temporarily allow input parameter copies required by the input file formatter
428 1482228 : params.allowCopy(true);
429 :
430 : // TODO: Do we need to insert more nodes for each task?
431 1482228 : tree.insertNode(name, *tasks.begin(), true, ¶ms);
432 1482228 : params.allowCopy(false);
433 :
434 1482228 : MooseObjectAction * moose_object_action = dynamic_cast<MooseObjectAction *>(act);
435 1482228 : if (moose_object_action)
436 : {
437 647571 : InputParameters obj_params = moose_object_action->getObjectParams();
438 647571 : tree.insertNode(name, *tasks.begin(), false, &obj_params);
439 647571 : }
440 : }
441 2839009 : }
442 :
443 35637 : out << tree.print("");
444 35637 : }
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 220867 : ActionWarehouse::hasTask(const std::string & task) const
468 : {
469 220867 : return _action_factory.isRegisteredTask(task);
470 : }
471 :
472 : bool
473 186619 : ActionWarehouse::isTaskComplete(const std::string & task) const
474 : {
475 186619 : if (!hasTask(task))
476 0 : mooseError("\"", task, "\" is not a registered task.");
477 186619 : std::scoped_lock lock(_completed_tasks_mutex);
478 373238 : return _completed_tasks.count(task);
479 186619 : }
|