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 14819 : Nemesis::validParams() 28 : { 29 14819 : InputParameters params = AdvancedOutput::validParams(); 30 14819 : params += AdvancedOutput::enableOutputTypes("scalar postprocessor input"); 31 14819 : params.addParam<bool>("write_hdf5", false, "Enables HDF5 output format for Nemesis files."); 32 14819 : params.addClassDescription("Object for output data in the Nemesis (parallel ExodusII) format."); 33 14819 : return params; 34 0 : } 35 : 36 277 : Nemesis::Nemesis(const InputParameters & parameters) 37 : : AdvancedOutput(parameters), 38 277 : _nemesis_io_ptr(nullptr), 39 277 : _file_num(declareRestartableData<unsigned int>("nemesis_file_num", 0)), 40 277 : _nemesis_num(declareRestartableData<unsigned int>("nemesis_num", 0)), 41 277 : _nemesis_initialized(false), 42 277 : _recovering(_app.isRecovering()), 43 277 : _nemesis_mesh_changed(declareRestartableData<bool>("nemesis_mesh_changed", true)), 44 554 : _write_hdf5(getParam<bool>("write_hdf5")) 45 : { 46 277 : } 47 : 48 : void 49 277 : Nemesis::initialSetup() 50 : { 51 277 : AdvancedOutput::initialSetup(); 52 277 : } 53 : 54 : void 55 248 : 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 248 : if (_nemesis_io_ptr != nullptr && !_nemesis_initialized) 60 0 : return; 61 : 62 : // Indicate to the Nemesis object that the mesh has changed 63 248 : _nemesis_mesh_changed = true; 64 : } 65 : 66 : void 67 959 : Nemesis::outputSetup() 68 : { 69 959 : if (_nemesis_io_ptr) 70 : { 71 : // Do nothing if the Nemesis_IO objects exists, but has not been initialized 72 693 : if (!_nemesis_initialized) 73 0 : return; 74 : 75 : // Do nothing if the mesh has not changed 76 693 : if (!_nemesis_mesh_changed) 77 565 : return; 78 : } 79 : 80 : // Create the new NemesisIO object 81 394 : _nemesis_io_ptr = std::make_unique<Nemesis_IO>(_problem_ptr->mesh().getMesh()); 82 394 : _nemesis_initialized = false; 83 : 84 394 : 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 394 : _nemesis_io_ptr->set_hdf5_writing(false); 96 : } 97 : 98 394 : 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 377 : if (_nemesis_mesh_changed) 110 377 : _file_num++; 111 : 112 : // Disable file appending and reset nemesis file number count 113 377 : _nemesis_io_ptr->append(false); 114 377 : _nemesis_num = 1; 115 : } 116 : } 117 : 118 : void 119 82 : Nemesis::outputPostprocessors() 120 : { 121 : // List of desired postprocessor outputs 122 82 : 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 164 : for (const auto & name : pps) 127 : { 128 82 : _global_names.push_back(name); 129 82 : _global_values.push_back(_problem_ptr->getPostprocessorValueByName(name)); 130 : } 131 82 : } 132 : 133 : void 134 128 : Nemesis::outputScalarVariables() 135 : { 136 : // List of desired scalar outputs 137 128 : const std::set<std::string> & out = getScalarOutput(); 138 : 139 : // Append the scalar to the global output lists 140 512 : 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 384 : MooseVariableScalar & scalar_var = _problem_ptr->getScalarVariable(0, out_name); 147 384 : scalar_var.reinit(); 148 384 : VariableValue value(scalar_var.sln()); 149 : 150 384 : const std::vector<dof_id_type> & dof_indices = scalar_var.dofIndices(); 151 384 : const unsigned int n = dof_indices.size(); 152 384 : value.resize(n); 153 : 154 384 : const DofMap & dof_map = scalar_var.sys().dofMap(); 155 768 : for (unsigned int i = 0; i != n; ++i) 156 : { 157 384 : const processor_id_type pid = dof_map.dof_owner(dof_indices[i]); 158 384 : this->comm().broadcast(value[i], pid); 159 : } 160 : 161 : // If the scalar has a single component, output the name directly 162 384 : if (n == 1) 163 : { 164 384 : _global_names.push_back(out_name); 165 384 : _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 384 : } 180 128 : } 181 : 182 : void 183 959 : Nemesis::output() 184 : { 185 959 : outputSetup(); 186 : 187 : // Clear the global variables (postprocessors and scalars) 188 959 : _global_names.clear(); 189 959 : _global_values.clear(); 190 : 191 : // Call the output methods 192 959 : AdvancedOutput::output(); 193 : 194 : // Set up the whitelist of nodal variable names to write. 195 1918 : _nemesis_io_ptr->set_output_variables( 196 1918 : std::vector<std::string>(getNodalVariableOutput().begin(), getNodalVariableOutput().end())); 197 : 198 : // Write nodal data 199 1918 : _nemesis_io_ptr->write_timestep( 200 1918 : filename(), *_es_ptr, _nemesis_num, getOutputTime() + _app.getGlobalTimeOffset()); 201 959 : _nemesis_initialized = true; 202 : 203 : // Write elemental data 204 959 : std::vector<std::string> elemental(getElementalVariableOutput().begin(), 205 1918 : getElementalVariableOutput().end()); 206 959 : _nemesis_io_ptr->set_output_variables(elemental); 207 959 : _nemesis_io_ptr->write_element_data(*_es_ptr); 208 : 209 : // Increment output call counter for the current file 210 959 : _nemesis_num++; 211 : 212 : // Write the global variables (populated by the output methods) 213 959 : if (!_global_values.empty()) 214 210 : _nemesis_io_ptr->write_global_data(_global_values, _global_names); 215 : 216 : // Reset the mesh changed flag 217 959 : _nemesis_mesh_changed = false; 218 959 : } 219 : 220 : std::string 221 1236 : Nemesis::filename() 222 : { 223 : // Append the .e extension on the base file name 224 1236 : std::ostringstream output; 225 1236 : output << _file_base << ".e"; 226 : 227 : // Add the _000x extension to the file 228 1236 : if (_file_num > 1) 229 128 : output << "-s" << std::setw(_padding) << std::setprecision(0) << std::setfill('0') << std::right 230 128 : << _file_num; 231 : 232 : // Return the filename 233 2472 : return output.str(); 234 1236 : }