Line data Source code
1 : // MOOSE includes 2 : #include "PostprocessorInterface.h" 3 : #include "ResponseHistoryBuilder.h" 4 : 5 : // libMesh includes 6 : #include "libmesh/parallel_algebra.h" 7 : 8 : // C++ includes 9 : #include <unistd.h> 10 : 11 : registerMooseObject("MastodonApp", ResponseHistoryBuilder); 12 : 13 : InputParameters 14 364 : ResponseHistoryBuilder::validParams() 15 : { 16 364 : InputParameters params = NodalVectorPostprocessor::validParams(); 17 728 : params.addParam<std::vector<dof_id_type>>( 18 : "nodes", "Node number(s) at which the response history is needed."); 19 : 20 : // Force the object to only execute once per node even if it has multiple boundary ids 21 364 : params.set<bool>("unique_node_execute") = true; 22 364 : params.suppressParameter<bool>("unique_node_execute"); 23 : 24 1456 : params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END}; 25 364 : params.suppressParameter<ExecFlagEnum>("execute_on"); 26 : 27 364 : params.set<bool>("contains_complete_history") = true; 28 364 : params.suppressParameter<bool>("contains_complete_history"); 29 : 30 728 : params.addRequiredCoupledVar("variables", 31 : "Variable name for which the response history is requested."); 32 364 : params.addClassDescription("Calculates response histories for a given node and variable(s)."); 33 364 : return params; 34 364 : } 35 : 36 230 : ResponseHistoryBuilder::ResponseHistoryBuilder(const InputParameters & parameters) 37 : : NodalVectorPostprocessor(parameters), 38 230 : _var_names(getParam<std::vector<VariableName>>("variables")), 39 460 : _history_time(declareVector("time")) 40 : { 41 : // Set that will store the union of node ids from all the boundaries or requested nodes 42 : std::set<dof_id_type> history_nodes; 43 : 44 282 : if (parameters.isParamValid("boundary") && parameters.isParamValid("nodes")) 45 0 : mooseError("Error in VectorPostprocessor, '", 46 : name(), 47 : "'. Please specify either of boundary or node, but not both."); 48 : 49 586 : if (!parameters.isParamValid("boundary") && !parameters.isParamValid("nodes")) 50 0 : mooseError("Error in VectorPostprocessor, '", 51 : name(), 52 : "'. Please provide either boundary or node for response history output."); 53 : 54 460 : if (parameters.isParamValid("boundary")) 55 : { 56 : // Retrieving boundaries and making a set of all the nodes in these boundaries 57 : std::set<BoundaryID> bnd_ids = 58 52 : boundaryIDs(); // Set containing the boundary IDs input by the user 59 104 : for (auto id : boundaryIDs()) 60 104 : history_nodes.insert(_mesh.getNodeList(id).begin(), _mesh.getNodeList(id).end()); 61 : } 62 : 63 460 : if (parameters.isParamValid("nodes")) 64 : { 65 : // Retrieving vector of nodes from input and storing them in a set, in case 66 : // there are repetetions 67 534 : std::vector<dof_id_type> vec = getParam<std::vector<dof_id_type>>("nodes"); 68 178 : history_nodes.insert(vec.begin(), vec.end()); 69 178 : } 70 : 71 : // Resizing _history to the number of nodes * number of variables 72 230 : _history.resize(_var_names.size() * history_nodes.size()); 73 230 : _history_names.resize(_history.size()); 74 : 75 : // Declaring _history vectors and creating map from node_id to the location of 76 : // the corresponding VPP in _history 77 : std::size_t count = 0; 78 900 : for (dof_id_type node_id : history_nodes) 79 : { 80 1686 : for (std::size_t i = 0; i < _var_names.size(); ++i) 81 : { 82 1016 : _history_names[count * _var_names.size() + i] = 83 2032 : "node_" + Moose::stringify(node_id) + "_" + _var_names[i]; 84 1016 : _history[count * _var_names.size() + i] = 85 1016 : &declareVector(_history_names[count * _var_names.size() + i]); 86 : } 87 670 : _node_map[node_id] = count; 88 670 : count++; 89 : } 90 : 91 : // Coupling variables 92 624 : for (std::size_t i = 0; i < _var_names.size(); ++i) 93 788 : _variables.push_back(&coupledValue("variables", i)); 94 230 : } 95 : 96 : void 97 12783 : ResponseHistoryBuilder::initialize() 98 : { 99 12783 : _current_data.clear(); 100 12783 : _current_data.resize(_history.size()); 101 12783 : } 102 : 103 : void 104 6747 : ResponseHistoryBuilder::finalize() 105 : { 106 : // Data to be added to the current vectors 107 6747 : std::vector<Real> data(_history.size()); 108 : 109 6747 : if (n_processors() > 1) 110 : { 111 : // On each processor _current_data is sized for the number of history vectors (N). The allgather 112 : // method puts these vectors together on the root processor in a single vector. Therefore, if 113 : // there are two processors (A and B) then the _current_data for each processors are: 114 : // A = [A_0, A_1, ..., A_N] 115 : // B = [B_0, B_1, ..., B_N] 116 : // After allgather is executed the _current_data on the root processor becomes: 117 : // _current_data = [A_0, A_1, ..., A_N, B_0, B_1, ..., B_N] 118 5898 : _communicator.allgather(_current_data, true); 119 : 120 : // The values for _current_data are zero everywhere except on the processor on which it was 121 : // computed and there should never be repeated values because "unique_node_execute" is true and 122 : // the execute method sets the data by index so any repeated calls would overwrite a previous 123 : // calculation. Therefore, the data that needs to be added is simply the sum of all the vector 124 : // across processors. 125 : const std::size_t N = _history.size(); 126 20214 : for (dof_id_type rank = 0; rank < n_processors(); ++rank) 127 71268 : for (std::size_t i = 0; i < _history.size(); ++i) 128 56952 : data[i] += _current_data[rank * N + i]; 129 : } 130 : 131 : else 132 849 : data = _current_data; 133 : 134 : // Update the history vectors with the new data 135 33558 : for (std::size_t i = 0; i < _history.size(); ++i) 136 26811 : _history[i]->push_back(data[i]); 137 : 138 : // Update the time vector 139 6747 : _history_time.push_back(_t); 140 6747 : } 141 : 142 : void 143 6036 : ResponseHistoryBuilder::threadJoin(const UserObject & uo) 144 : { 145 : // As detailed in the finalize() method the _current_data are zero everywhere except on the 146 : // process and thread where it was computed. Thus, adding the values from the other threads 147 : // updates the root thread correctly. 148 : const ResponseHistoryBuilder & builder = static_cast<const ResponseHistoryBuilder &>(uo); 149 30096 : for (std::size_t i = 0; i < _history.size(); ++i) 150 24060 : _current_data[i] += builder._current_data[i]; 151 6036 : } 152 : 153 : void 154 67464 : ResponseHistoryBuilder::execute() 155 : { 156 : // finding the index of the VPP corresponding to _current_node in _history 157 67464 : if (_node_map.find(_current_node->id()) != _node_map.end()) 158 : { 159 : // The index of the data within the _history vector for the current node 160 6786 : std::size_t loc = _node_map[_current_node->id()]; 161 20196 : for (std::size_t i = 0; i < _variables.size(); ++i) 162 13410 : _current_data[loc * _variables.size() + i] = (*_variables[i])[0]; 163 : } 164 67464 : } 165 : 166 : const std::vector<VectorPostprocessorValue *> & 167 153 : ResponseHistoryBuilder::getHistories() const 168 : { 169 153 : return _history; 170 : } 171 : 172 : const std::vector<std::string> & 173 41 : ResponseHistoryBuilder::getHistoryNames() const 174 : { 175 41 : return _history_names; 176 : }