https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ActionWarehouse.C
Go to the documentation of this file.
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 "PhysicsBase.h"
15#include "InputFileFormatter.h"
16#include "InputParameters.h"
17#include "MooseMesh.h"
18#include "AddVariableAction.h"
20#include "XTermConstants.h"
21#include "InfixIterator.h"
22#include "FEProblem.h"
23#include "MemoryUtils.h"
25
26#include "DependencyResolver.h"
27
28#include "libmesh/simple_range.h"
29
30std::vector<UserObjectName>
32{
33 std::vector<UserObjectName> dependencies;
34 for (const auto & [_, param] : params)
35 {
36 if (const auto dependency =
37 dynamic_cast<const libMesh::Parameters::Parameter<UserObjectName> *>(param.get()))
38 {
39 const auto & uo_name = dependency->get();
40 if (!uo_name.empty())
41 dependencies.push_back(uo_name);
42 }
43 else if (const auto vector_dependency =
45 param.get()))
46 for (const auto & uo_name : vector_dependency->get())
47 if (!uo_name.empty())
48 dependencies.push_back(uo_name);
49 }
50 return dependencies;
51}
52
53void
54ActionWarehouse::sortUserObjectActions(std::list<Action *> & actions) const
55{
56 // We key on act->name() because for a MooseObjectAction the action name is exactly the name the
57 // UserObject is constructed under (see AddUserObjectAction), so a UserObjectName parameter value
58 // matches the action that builds the referenced object.
59 std::map<std::string, Action *> action_for_uo_name;
60 for (const auto act : actions)
61 if (dynamic_cast<MooseObjectAction *>(act))
62 action_for_uo_name.emplace(act->name(), act);
63 // A Physics does not build its UserObjects under its own action name, so it declares the names
64 // it supplies through getSuppliedUserObjects(). Key those to the Physics action so an object
65 // referencing a Physics-supplied UserObject is constructed after the Physics adds it.
66 else if (const auto physics = dynamic_cast<const PhysicsBase *>(act))
67 for (const auto & uo_name : physics->getSuppliedUserObjects())
68 action_for_uo_name.emplace(uo_name, act);
69
70 // Seed the resolver in the current (input-file) order so that independent UserObjects keep their
71 // input order (DependencyResolver resolves in insertion order modulo dependencies).
73 for (const auto act : actions)
74 resolver.addItem(act);
75
76 for (const auto act : actions)
77 {
78 // A MooseObjectAction carries its dependencies in the parameters of the object it builds. Any
79 // other action that consumes a UserObject (e.g. a Physics that programmatically adds one) names
80 // it in the action's own parameters, so the dependency is ordered against just the same.
81 const auto moose_object_action = dynamic_cast<MooseObjectAction *>(act);
82 const auto & relevant_params =
83 moose_object_action ? moose_object_action->getObjectParams() : act->parameters();
84 for (const auto & dep_name : getUserObjectParamDependencies(relevant_params))
85 {
86 const auto it = action_for_uo_name.find(dep_name);
87 if (it != action_for_uo_name.end() && it->second != act)
88 // act references the UserObject built by it->second, which must be constructed first
89 resolver.addEdge(it->second, act);
90 }
91 }
92
93 // A UserObjectName parameter does not necessarily denote a construction-time dependency: many
94 // UserObjects only resolve a referenced UserObject during initialSetup() or execution. Mutually
95 // referencing UserObjects therefore form a cycle here even though they construct fine in input
96 // order. So a cycle is not an error - fall back to the original input order, which is the
97 // behavior prior to this sorting. A genuine construction-time cycle still surfaces as the usual
98 // "UserObject not found" error when the object is constructed.
99 try
100 {
101 const auto & sorted = resolver.getSortedValues();
102 actions.assign(sorted.begin(), sorted.end());
103 }
105 {
106 }
107}
108
111 _app(app),
112 _syntax(syntax),
113 _action_factory(factory),
114 _generator_valid(false),
115 _show_action_dependencies(false),
116 _show_actions(false),
117 _show_parser(false),
118 _current_action(nullptr),
119 _mesh(nullptr),
120 _displaced_mesh(nullptr)
121{
122}
123
125
126void
127ActionWarehouse::setFinalTask(const std::string & task)
128{
129 if (!_syntax.hasTask(task))
130 mooseError("cannot use unregistered task '", task, "' as final task");
131 _final_task = task;
132}
133
134void
136{
138 for (const auto & name : _ordered_names)
140}
141
142void
144{
145 for (auto & ptr : _all_ptrs)
146 ptr.reset();
147
148 _action_blocks.clear();
149 _generator_valid = false;
150
151 // Due to the way ActionWarehouse is cleaned up (see MooseApp's
152 // destructor) we must guarantee that ActionWarehouse::clear()
153 // releases all the resources which have to be released _before_ the
154 // _comm object owned by the MooseApp is destroyed.
155 _problem.reset();
156 _displaced_mesh.reset();
157 _mesh.reset();
158}
159
160void
161ActionWarehouse::addActionBlock(std::shared_ptr<Action> action)
162{
170 std::string registered_identifier =
171 action->parameters().get<std::string>("registered_identifier");
172 std::set<std::string> tasks;
173
174 if (_show_parser)
175 Moose::err << COLOR_DEFAULT << "Parsing Syntax: " << COLOR_GREEN << action->name()
176 << '\n'
177 << COLOR_DEFAULT << "Building Action: " << COLOR_DEFAULT << action->type()
178 << '\n'
179 << COLOR_DEFAULT << "Registered Identifier: " << COLOR_GREEN << registered_identifier
180 << '\n'
181 << COLOR_DEFAULT << "Specific Task: " << COLOR_CYAN
182 << action->specificTaskName() << std::endl;
183
204 if (action->specificTaskName() != "") // Case 1
205 tasks.insert(action->specificTaskName());
206 else if (registered_identifier == "" &&
207 _syntax.getNonDeprecatedSyntaxByAction(action->type()).size() > 1) // Case 2
208 {
209 std::set<std::string> local_tasks = action->getAllTasks();
210 mooseAssert(local_tasks.size() == 1, "More than one task inside of the " << action->name());
211 tasks.insert(*local_tasks.begin());
212 }
213 else // Case 3
214 tasks = _action_factory.getTasksByAction(action->type());
215
216 // TODO: Now we need to weed out the double registrations!
217 for (const auto & task : tasks)
218 {
219 // Some error checking
220 if (!_syntax.hasTask(task))
221 mooseError("A(n) ", task, " is not a registered task");
222
223 // Make sure that the ObjectAction task and Action task are consistent
224 // otherwise that means that is action was built by the wrong type
225 std::shared_ptr<MooseObjectAction> moa = std::dynamic_pointer_cast<MooseObjectAction>(action);
226 if (moa.get())
227 {
228 const InputParameters & mparams = moa->getObjectParams();
229
230 if (mparams.hasBase())
231 {
232 const std::string & base = mparams.getBase();
233 if (!_syntax.verifyMooseObjectTask(base, task))
234 mooseError("Task ", task, " is not registered to build ", base, " derived objects");
235 }
236 else
237 mooseError("Unable to locate registered base parameter for ", moa->getMooseObjectType());
238 }
239
240 // Add the current task to current action
241 action->appendTask(task);
242
243 if (_show_parser)
244 Moose::err << COLOR_YELLOW << "Adding Action: " << COLOR_DEFAULT << action->type()
245 << " (" << COLOR_YELLOW << task << COLOR_DEFAULT << ")" << std::endl;
246
247 // Add it to the warehouse
248 _action_blocks[task].push_back(action.get());
249 }
250 _all_ptrs.push_back(action);
251
252 if (_show_parser)
253 Moose::err << std::endl;
254}
255
258{
259 return _action_blocks[task].begin();
260}
261
264{
265 return _action_blocks[task].end();
266}
267
268const std::vector<std::shared_ptr<Action>> &
270{
271 return _all_ptrs;
272}
273
274const std::list<Action *> &
275ActionWarehouse::getActionListByName(const std::string & task) const
276{
277 const auto it = _action_blocks.find(task);
278 if (it == _action_blocks.end())
279 return _empty_action_list;
280 else
281 return it->second;
282}
283
284bool
285ActionWarehouse::hasActions(const std::string & task) const
286{
287 auto it = _action_blocks.find(task);
288 return it != _action_blocks.end() && !it->second.empty();
289}
290
291void
293{
294 if (_syntax.shouldAutoBuild(task) && _action_blocks[task].empty())
295 {
296 bool ret_value = false;
297 auto it_pair = _action_factory.getActionsByTask(task);
298 for (const auto & action_pair : as_range(it_pair))
299 {
300 const auto & type = action_pair.second;
302 params.set<ActionWarehouse *>("awh") = this;
303
304 std::string name = "auto_" + type;
305 std::transform(
306 name.begin(), name.end(), name.begin(), [](const auto v) { return std::tolower(v); });
307
308 if (params.areAllRequiredParamsValid())
309 {
310 params.set<std::string>("registered_identifier") = "(AutoBuilt)";
311 addActionBlock(_action_factory.create(type, name, params));
312 ret_value = true;
313 }
314 }
315
316 if (!ret_value)
317 _unsatisfied_dependencies.insert(task);
318 }
319}
320
321void
323{
324 std::stringstream oss;
325 bool empty = true;
326
327 for (const auto & udep : _unsatisfied_dependencies)
328 {
329 if (_action_blocks.find(udep) == _action_blocks.end())
330 {
331 if (empty)
332 empty = false;
333 else
334 oss << " ";
335 oss << udep;
336 }
337 }
338
339 if (!empty)
341 std::string(
342 "The following unsatisfied actions where found while setting up the MOOSE problem:\n") +
343 oss.str() + "\n");
344}
345
346void
348{
358 std::ostringstream oss;
359
360 const auto & ordered_names = _syntax.getSortedTaskSet();
361 for (const auto & task_vector : ordered_names)
362 {
363 oss << "[DBG][ACT] (" << COLOR_YELLOW;
364 std::copy(
365 task_vector.begin(), task_vector.end(), infix_ostream_iterator<std::string>(oss, ", "));
366 oss << COLOR_DEFAULT << ")\n";
367
368 std::set<std::string> task_set(task_vector.begin(), task_vector.end());
369 for (const auto & task : task_set)
370 {
371 if (_action_blocks.find(task) == _action_blocks.end())
372 continue;
373
374 for (const auto & act : _action_blocks.at(task))
375 {
376 // The Syntax of the Action if it exists
377 if (act->name() != "")
378 oss << "[DBG][ACT]\t" << COLOR_GREEN << act->name() << COLOR_DEFAULT << '\n';
379
380 // The task sets
381 oss << "[DBG][ACT]\t" << act->type();
382 const std::set<std::string> tasks = act->getAllTasks();
383 if (tasks.size() > 1)
384 {
385 oss << " (";
386 // Break the current Action's tasks into 2 sets, those intersecting with current set and
387 // then the difference.
388 std::set<std::string> intersection, difference;
389 std::set_intersection(tasks.begin(),
390 tasks.end(),
391 task_set.begin(),
392 task_set.end(),
393 std::inserter(intersection, intersection.end()));
394 std::set_difference(tasks.begin(),
395 tasks.end(),
396 intersection.begin(),
397 intersection.end(),
398 std::inserter(difference, difference.end()));
399
400 oss << COLOR_CYAN;
401 std::copy(intersection.begin(),
402 intersection.end(),
404 oss << COLOR_MAGENTA << (difference.empty() ? "" : ", ");
405 std::copy(
406 difference.begin(), difference.end(), infix_ostream_iterator<std::string>(oss, ", "));
407 oss << COLOR_DEFAULT << ")";
408 }
409 oss << '\n';
410 }
411 }
412 }
413
415 _console << oss.str() << std::endl;
416}
417
418void
420{
421 _completed_tasks.clear();
422
424 {
425 _console << "[DBG][ACT] Action Dependency Sets:\n";
427
428 _console << "\n[DBG][ACT] Executing actions:" << std::endl;
429 }
430
431 for (const auto & task : _ordered_names)
432 {
434 std::scoped_lock lock(_completed_tasks_mutex);
435 _completed_tasks.insert(task);
436 if (_final_task != "" && task == _final_task)
437 break;
438 }
439
440 if (_show_actions)
441 {
442 MemoryUtils::Stats stats;
444 auto usage =
446 _console << "[DBG][ACT] Finished executing all actions with memory usage " << usage << "MB\n"
447 << std::endl;
448 }
449}
450
451void
453{
454 // Set the current task name
455 _current_task = task;
456
457 // UserObjects may reference other UserObjects in their constructors (e.g. through a
458 // UserObjectName parameter). Construct them in dependency order so the input file does not have
459 // to declare a referenced UserObject before the UserObject that uses it.
460 if (task == "add_user_object")
462
463 for (auto it = actionBlocksWithActionBegin(task); it != actionBlocksWithActionEnd(task); ++it)
464 {
465 _current_action = *it;
466
467 if (_show_actions)
468 {
469 MemoryUtils::Stats stats;
471 auto usage =
473 _console << "[DBG][ACT] "
474 << "TASK (" << COLOR_YELLOW << std::setw(24) << task << COLOR_DEFAULT << ") "
475 << "TYPE (" << COLOR_YELLOW << std::setw(32) << _current_action->type()
476 << COLOR_DEFAULT << ") "
477 << "NAME (" << COLOR_YELLOW << std::setw(16) << _current_action->name()
478 << COLOR_DEFAULT << ") Memory usage " << usage << "MB" << std::endl;
479 }
480
482 }
483
484 _current_action = nullptr;
485}
486
487void
489{
490 InputFileFormatter tree(false);
491
492 std::map<std::string, std::vector<Action *>>::iterator iter;
493
494 std::vector<Action *> ordered_actions;
495 for (const auto & block : _action_blocks)
496 for (const auto & act : block.second)
497 ordered_actions.push_back(act);
498
499 for (const auto & act : ordered_actions)
500 {
501 std::string name;
502 if (act->parameters().blockFullpath() != "")
503 name = act->parameters().blockFullpath();
504 else
505 name = act->name();
506 const std::set<std::string> & tasks = act->getAllTasks();
507 mooseAssert(!tasks.empty(), "Task list is empty");
508
509 bool is_parent;
510 if (_syntax.isAssociated(name, &is_parent) != "")
511 {
512 const auto & all_params = _app.getInputParameterWarehouse().getInputParameters();
513 InputParameters & params = *(all_params.find(act->uniqueActionName())->second.get());
514
515 // temporarily allow input parameter copies required by the input file formatter
516 params.allowCopy(true);
517
518 // TODO: Do we need to insert more nodes for each task?
519 tree.insertNode(name, *tasks.begin(), true, &params);
520 params.allowCopy(false);
521
522 MooseObjectAction * moose_object_action = dynamic_cast<MooseObjectAction *>(act);
523 if (moose_object_action)
524 {
525 InputParameters obj_params = moose_object_action->getObjectParams();
526 tree.insertNode(name, *tasks.begin(), false, &obj_params);
527 }
528 }
529 }
530
531 out << tree.print("");
532}
533
534std::shared_ptr<FEProblem>
536{
538 "ActionWarehouse::problem() is deprecated, please use ActionWarehouse::problemBase() \n");
539 return std::dynamic_pointer_cast<FEProblem>(_problem);
540}
541
542std::string
544{
545 return getCurrentAction()->parameters().getHitNode()->fullpath();
546}
547
548const std::string &
553
554bool
555ActionWarehouse::hasTask(const std::string & task) const
556{
558}
559
560bool
561ActionWarehouse::isTaskComplete(const std::string & task) const
562{
563 if (!hasTask(task))
564 mooseError("\"", task, "\" is not a registered task.");
565 std::scoped_lock lock(_completed_tasks_mutex);
566 return _completed_tasks.count(task);
567}
std::list< Action * >::iterator ActionIterator
alias to hide implementation details
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
void mooseDeprecated(Args &&... args)
Emit a deprecated code/feature message with the given stringified, concatenated args.
Definition MooseError.h:363
Specialized factory for generic Action System objects.
std::set< std::string > getTasksByAction(const std::string &action) const
std::shared_ptr< Action > create(const std::string &action, const std::string &action_name, InputParameters &parameters)
std::pair< std::multimap< std::string, std::string >::const_iterator, std::multimap< std::string, std::string >::const_iterator > getActionsByTask(const std::string &task) const
Returns begin and end iterators in a multimap from tasks to actions names.
bool isRegisteredTask(const std::string &task) const
Whether or not a task with the name task is registered.
InputParameters getValidParams(const std::string &name)
Storage for action instances.
std::mutex _completed_tasks_mutex
Mutex for preventing read/write races for _completed_tasks.
const std::string & getMooseAppName()
void checkUnsatisfiedActions() const
This method checks the actions stored in the warehouse against the list of required registered action...
void setFinalTask(const std::string &task)
void printInputFile(std::ostream &out)
This method uses the Actions in the warehouse to reproduce the input file.
std::string _final_task
Last task to run before (optional) early termination - blank means no early termination.
std::map< std::string, std::list< Action * > > _action_blocks
Pointers to the actual parsed input file blocks.
std::string _current_task
const Action * getCurrentAction() const
bool _show_actions
Whether or not the action warehouse prints the action execution information.
void clear()
This method deletes all of the Actions in the warehouse.
void buildBuildableActions(const std::string &task)
This method auto-builds all Actions that needs to be built and adds them to ActionWarehouse.
std::set< std::string > _unsatisfied_dependencies
Use to store the current list of unsatisfied dependencies.
MooseApp & _app
The MooseApp this Warehouse is associated with.
const std::vector< std::shared_ptr< Action > > & allActionBlocks() const
Returns a reference to all of the actions.
std::string getCurrentActionName() const
bool _show_action_dependencies
Whether or not the action warehouse prints the action dependency information.
const std::list< Action * > _empty_action_list
std::vector< UserObjectName > getUserObjectParamDependencies(const InputParameters &params) const
bool empty() const
returns a Boolean indicating whether the warehouse is empty or not.
bool isTaskComplete(const std::string &task) const
std::shared_ptr< FEProblem > problem()
bool _generator_valid
Flag to indicate whether or not there is an active iterator on this class.
Syntax & _syntax
Reference to a "syntax" of actions.
ActionWarehouse(MooseApp &app, Syntax &syntax, ActionFactory &factory)
std::vector< std::string > _ordered_names
The container that holds the sorted action names from the DependencyResolver.
std::shared_ptr< FEProblemBase > _problem
Problem class.
void sortUserObjectActions(std::list< Action * > &actions) const
Reorder the UserObject-constructing actions actions so that a UserObject that references another (thr...
bool hasActions(const std::string &task) const
Check if Actions associated with passed in task exist.
ActionIterator actionBlocksWithActionEnd(const std::string &task)
ActionFactory & _action_factory
The Factory that builds Actions.
std::vector< std::shared_ptr< Action > > _all_ptrs
ActionIterator actionBlocksWithActionBegin(const std::string &task)
Iterators to the Actions in the warehouse.
bool _show_parser
Whether or not to print messages when actions are inserted in the warehouse by the parser.
std::set< std::string > _completed_tasks
The completed tasks.
void build()
Builds all auto-buildable tasks.
void executeActionsWithAction(const std::string &task_name)
This method executes only the actions in the warehouse that satisfy the task passed in.
const std::list< Action * > & getActionListByName(const std::string &task) const
Retrieve a constant list of Action pointers associated with the passed in task.
std::shared_ptr< MooseMesh > _displaced_mesh
Possible mesh for displaced problem.
void printActionDependencySets() const
This method is used only during debugging when show_actions is set to true.
void executeAllActions()
This method loops over all actions in the warehouse and executes them.
bool hasTask(const std::string &task) const
void addActionBlock(std::shared_ptr< Action > blk)
This method add an Action instance to the warehouse.
std::shared_ptr< MooseMesh > _mesh
Mesh class.
void timedAct()
The method called externally that causes the action to act()
Definition Action.C:76
An inteface for the _console for outputting to the Console object.
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
Class that represents the dependecy as a graph.
void addItem(const T &value)
Add an independent item to the set.
const std::vector< T > & getSortedValues()
This function also returns dependency resolved values but with a simpler single vector interface.
void addEdge(const T &a, const T &b)
Add an edge between nodes 'a' and 'b'.
This class produces produces a dump of the InputParameters that appears like the normal input file sy...
const std::multimap< MooseObjectName, std::shared_ptr< InputParameters > > & getInputParameters(THREAD_ID tid=0) const
Return const reference to the map containing the InputParameter objects.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void allowCopy(bool status)
Toggle the availability of the copy constructor.
bool areAllRequiredParamsValid() const
This method returns true if all of the parameters in this object are valid (i.e.
const hit::Node * getHitNode(const std::string &param) const
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
const std::string & getBase() const
bool hasBase() const
Base class for MOOSE-based applications.
Definition MooseApp.h:110
InputParameterWarehouse & getInputParameterWarehouse()
Get the InputParameterWarehouse for MooseObjects.
Definition MooseApp.C:2867
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const std::string & type() const
Get the type of this class.
Definition MooseBase.h:93
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
InputParameters & getObjectParams()
Retrieve the parameters of the object to be created by this action.
Base class to help creating an entire physics.
Definition PhysicsBase.h:31
void insertNode(std::string syntax, const std::string &action, bool is_action_params=true, InputParameters *params=NULL)
Definition SyntaxTree.C:27
std::string print(const std::string &search_string)
Definition SyntaxTree.C:39
Holding syntax for parsing input files.
Definition Syntax.h:22
const std::vector< std::vector< std::string > > & getSortedTaskSet()
Get a list of serialized tasks in a correct dependency order.
Definition Syntax.C:119
std::string isAssociated(const std::string &real_id, bool *is_parent, const std::map< std::string, std::set< std::string > > &alt_map={}) const
Method for determining whether a piece of syntax is associated with an Action an optional syntax map ...
Definition Syntax.C:252
std::vector< std::string > getNonDeprecatedSyntaxByAction(const std::string &action, const std::string &task="")
Retrieve the non-deprecated syntax associated with the passed in action type string.
Definition Syntax.C:238
bool verifyMooseObjectTask(const std::string &base, const std::string &task) const
Returns a Boolean indicating whether a task is associated with on of the MOOSE pluggable systems (BAS...
Definition Syntax.C:335
const std::vector< std::string > & getSortedTask()
Get a list of serialized tasks in a correct dependency order.
Definition Syntax.C:105
bool shouldAutoBuild(const std::string &task) const
Returns a Boolean indicating whether MOOSE should attempt to automatically create an Action to satisf...
Definition Syntax.C:138
bool hasTask(const std::string &task) const
Returns a Boolean indicating whether or not a task is registered with the syntax object.
Definition Syntax.C:125
GCC9 currently hits a "no type named 'value_type'" error during build if this is removed and iterator...
void usage(const std::string &progName)
std::size_t convertBytes(std::size_t bytes, MemUnits unit)
convert bytes to selected unit prefix
bool getMemoryStats(Stats &stats)
get all memory stats for the current process stats The Stats object to fill with the data
Definition MemoryUtils.C:79
std::size_t _physical_memory
Definition MemoryUtils.h:23