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 "Nemesis.h" 11 : 12 : // MOOSE includes 13 : #include "FEProblem.h" 14 : #include "MooseApp.h" 15 : #include "MooseMesh.h" 16 : #include "MooseVariableScalar.h" 17 : #include "SystemBase.h" 18 : 19 : #include "libmesh/dof_map.h" 20 : #include "libmesh/nemesis_io.h" 21 : 22 : using namespace libMesh; 23 : 24 : registerMooseObject("MooseApp", Nemesis); 25 : 26 : InputParameters 27 14761 : Nemesis::validParams() 28 : { 29 14761 : InputParameters params = AdvancedOutput::validParams(); 30 14761 : params += AdvancedOutput::enableOutputTypes("scalar postprocessor input"); 31 14761 : params.addParam<bool>("write_hdf5", false, "Enables HDF5 output format for Nemesis files."); 32 14761 : params.addClassDescription("Object for output data in the Nemesis (parallel ExodusII) format."); 33 14761 : return params; 34 0 : } 35 : 36 248 : Nemesis::Nemesis(const InputParameters & parameters) 37 : : AdvancedOutput(parameters), 38 248 : _nemesis_io_ptr(nullptr), 39 248 : _file_num(declareRestartableData<unsigned int>("nemesis_file_num", 0)), 40 248 : _nemesis_num(declareRestartableData<unsigned int>("nemesis_num", 0)), 41 248 : _nemesis_initialized(false), 42 248 : _recovering(_app.isRecovering()), 43 248 : _nemesis_mesh_changed(declareRestartableData<bool>("nemesis_mesh_changed", true)), 44 496 : _write_hdf5(getParam<bool>("write_hdf5")) 45 : { 46 248 : } 47 : 48 : void 49 248 : Nemesis::initialSetup() 50 : { 51 248 : AdvancedOutput::initialSetup(); 52 248 : } 53 : 54 : void 55 217 : Nemesis::meshChanged() 56 : { 57 : // Do not delete the Nemesis_IO object if it has not been used; also there is no need to setup 58 : // the object in this case, so just return 59 217 : if (_nemesis_io_ptr != nullptr && !_nemesis_initialized) 60 0 : return; 61 : 62 : // Indicate to the Nemesis object that the mesh has changed 63 217 : _nemesis_mesh_changed = true; 64 : } 65 : 66 : void 67 863 : Nemesis::outputSetup() 68 : { 69 863 : if (_nemesis_io_ptr) 70 : { 71 : // Do nothing if the Nemesis_IO objects exists, but has not been initialized 72 626 : if (!_nemesis_initialized) 73 0 : return; 74 : 75 : // Do nothing if the mesh has not changed 76 626 : if (!_nemesis_mesh_changed) 77 514 : return; 78 : } 79 : 80 : // Create the new NemesisIO object 81 349 : _nemesis_io_ptr = std::make_unique<Nemesis_IO>(_problem_ptr->mesh().getMesh()); 82 349 : _nemesis_initialized = false; 83 : 84 349 : if (_write_hdf5) 85 : { 86 : #ifndef LIBMESH_HAVE_HDF5 87 : mooseError("Moose input requested HDF Nemesis output, but libMesh was built without HDF5."); 88 : #endif 89 : 90 : // This is redundant unless the libMesh default changes 91 0 : _nemesis_io_ptr->set_hdf5_writing(true); 92 : } 93 : else 94 : { 95 349 : _nemesis_io_ptr->set_hdf5_writing(false); 96 : } 97 : 98 349 : if (_recovering && !_nemesis_mesh_changed && _nemesis_num > 0) 99 : { 100 : // Set the recovering flag to false so that this special case is not triggered again 101 17 : _recovering = false; 102 : 103 : // Set the append flag to true b/c on recover the file is being appended 104 17 : _nemesis_io_ptr->append(true); 105 : } 106 : else 107 : { 108 : // Increment file counter 109 332 : if (_nemesis_mesh_changed) 110 332 : _file_num++; 111 : 112 : // Disable file appending and reset nemesis file number count 113 332 : _nemesis_io_ptr->append(false); 114 332 : _nemesis_num = 1; 115 : } 116 : } 117 : 118 : void 119 72 : Nemesis::outputPostprocessors() 120 : { 121 : // List of desired postprocessor outputs 122 72 : const std::set<std::string> & pps = getPostprocessorOutput(); 123 : 124 : // Append the postprocessor data to the global name value parameters; scalar outputs 125 : // also append these member variables 126 144 : for (const auto & name : pps) 127 : { 128 72 : _global_names.push_back(name); 129 72 : _global_values.push_back(_problem_ptr->getPostprocessorValueByName(name)); 130 : } 131 72 : } 132 : 133 : void 134 112 : Nemesis::outputScalarVariables() 135 : { 136 : // List of desired scalar outputs 137 112 : const std::set<std::string> & out = getScalarOutput(); 138 : 139 : // Append the scalar to the global output lists 140 448 : for (const auto & out_name : out) 141 : { 142 : // Make sure scalar values are in sync with the solution vector 143 : // and are visible on this processor. See TableOutput.C for 144 : // TableOutput::outputScalarVariables() explanatory comments 145 : 146 336 : MooseVariableScalar & scalar_var = _problem_ptr->getScalarVariable(0, out_name); 147 336 : scalar_var.reinit(); 148 336 : VariableValue value(scalar_var.sln()); 149 : 150 336 : const std::vector<dof_id_type> & dof_indices = scalar_var.dofIndices(); 151 336 : const unsigned int n = dof_indices.size(); 152 336 : value.resize(n); 153 : 154 336 : const DofMap & dof_map = scalar_var.sys().dofMap(); 155 672 : for (unsigned int i = 0; i != n; ++i) 156 : { 157 336 : const processor_id_type pid = dof_map.dof_owner(dof_indices[i]); 158 336 : this->comm().broadcast(value[i], pid); 159 : } 160 : 161 : // If the scalar has a single component, output the name directly 162 336 : if (n == 1) 163 : { 164 336 : _global_names.push_back(out_name); 165 336 : _global_values.push_back(value[0]); 166 : } 167 : 168 : // If the scalar as many components add indices to the end of the name 169 : else 170 : { 171 0 : for (unsigned int i = 0; i < n; ++i) 172 : { 173 0 : std::ostringstream os; 174 0 : os << out_name << "_" << i; 175 0 : _global_names.push_back(os.str()); 176 0 : _global_values.push_back(value[i]); 177 0 : } 178 : } 179 336 : } 180 112 : } 181 : 182 : void 183 863 : Nemesis::output() 184 : { 185 863 : outputSetup(); 186 : 187 : // Clear the global variables (postprocessors and scalars) 188 863 : _global_names.clear(); 189 863 : _global_values.clear(); 190 : 191 : // Call the output methods 192 863 : AdvancedOutput::output(); 193 : 194 : // Set up the whitelist of nodal variable names to write. 195 1726 : _nemesis_io_ptr->set_output_variables( 196 1726 : std::vector<std::string>(getNodalVariableOutput().begin(), getNodalVariableOutput().end())); 197 : 198 : // Write nodal data 199 1726 : _nemesis_io_ptr->write_timestep( 200 1726 : filename(), *_es_ptr, _nemesis_num, getOutputTime() + _app.getGlobalTimeOffset()); 201 863 : _nemesis_initialized = true; 202 : 203 : // Write elemental data 204 863 : std::vector<std::string> elemental(getElementalVariableOutput().begin(), 205 1726 : getElementalVariableOutput().end()); 206 863 : _nemesis_io_ptr->set_output_variables(elemental); 207 863 : _nemesis_io_ptr->write_element_data(*_es_ptr); 208 : 209 : // Increment output call counter for the current file 210 863 : _nemesis_num++; 211 : 212 : // Write the global variables (populated by the output methods) 213 863 : if (!_global_values.empty()) 214 184 : _nemesis_io_ptr->write_global_data(_global_values, _global_names); 215 : 216 : // Reset the mesh changed flag 217 863 : _nemesis_mesh_changed = false; 218 863 : } 219 : 220 : std::string 221 1111 : Nemesis::filename() 222 : { 223 : // Append the .e extension on the base file name 224 1111 : std::ostringstream output; 225 1111 : output << _file_base << ".e"; 226 : 227 : // Add the _000x extension to the file 228 1111 : if (_file_num > 1) 229 112 : output << "-s" << std::setw(_padding) << std::setprecision(0) << std::setfill('0') << std::right 230 112 : << _file_num; 231 : 232 : // Return the filename 233 2222 : return output.str(); 234 1111 : }