LCOV - code coverage report
Current view: top level - src/outputs - Exodus.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 219 238 92.0 %
Date: 2025-07-17 01:28:37 Functions: 19 21 90.5 %
Legend: Lines: hit not hit

          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 "Exodus.h"
      11             : 
      12             : // Moose includes
      13             : #include "DisplacedProblem.h"
      14             : #include "ExodusFormatter.h"
      15             : #include "FEProblem.h"
      16             : #include "FileMesh.h"
      17             : #include "MooseApp.h"
      18             : #include "MooseVariableScalar.h"
      19             : #include "LockFile.h"
      20             : 
      21             : #include "libmesh/exodusII_io.h"
      22             : #include "libmesh/libmesh_config.h" // LIBMESH_HAVE_HDF5
      23             : 
      24             : using namespace libMesh;
      25             : 
      26             : registerMooseObject("MooseApp", Exodus);
      27             : 
      28             : InputParameters
      29       86020 : Exodus::validParams()
      30             : {
      31             :   // Get the base class parameters
      32       86020 :   InputParameters params = SampledOutput::validParams();
      33             :   params +=
      34       86020 :       AdvancedOutput::enableOutputTypes("nodal elemental scalar postprocessor reporter input");
      35             : 
      36             :   // Enable sequential file output (do not set default, the use_displace criteria relies on
      37             :   // isParamValid, see Constructor)
      38       86020 :   params.addParam<bool>("sequence",
      39             :                         "Enable/disable sequential file output (enabled by default "
      40             :                         "when 'use_displace = true', otherwise defaults to false");
      41             : 
      42             :   // Select problem dimension for mesh output
      43       86020 :   params.addDeprecatedParam<bool>("use_problem_dimension",
      44             :                                   "Use the problem dimension to the mesh output. "
      45             :                                   "Set to false when outputting lower dimensional "
      46             :                                   "meshes embedded in a higher dimensional space.",
      47             :                                   "Use 'output_dimension = problem_dimension' instead.");
      48             : 
      49       86020 :   MooseEnum output_dimension("default 1 2 3 problem_dimension", "default");
      50             : 
      51       86020 :   params.addParam<MooseEnum>(
      52             :       "output_dimension", output_dimension, "The dimension of the output file");
      53             : 
      54       86020 :   params.addParamNamesToGroup("output_dimension", "Advanced");
      55             : 
      56             :   // Set the default padding to 3
      57       86020 :   params.set<unsigned int>("padding") = 3;
      58             : 
      59             :   // Add description for the Exodus class
      60       86020 :   params.addClassDescription("Object for output data in the Exodus format");
      61             : 
      62             :   // Flag for overwriting at each timestep
      63      258060 :   params.addParam<bool>("overwrite",
      64      172040 :                         false,
      65             :                         "When true the latest timestep will overwrite the "
      66             :                         "existing file, so only a single timestep exists.");
      67             : 
      68             :   // Set outputting of the input to be on by default
      69       86020 :   params.set<ExecFlagEnum>("execute_input_on") = EXEC_INITIAL;
      70             : 
      71             :   // Flag for outputting discontinuous data to Exodus
      72      258060 :   params.addParam<bool>(
      73      172040 :       "discontinuous", false, "Enables discontinuous output format for Exodus files.");
      74             : 
      75             :   // Flag for outputting added side elements (for side-discontinuous data) to Exodus
      76      258060 :   params.addParam<bool>(
      77      172040 :       "side_discontinuous", false, "Enables adding side-discontinuous output in Exodus files.");
      78             : 
      79             :   // Flag for outputting Exodus data in HDF5 format (when libMesh is
      80             :   // configured with HDF5 support).  libMesh wants to do so by default
      81             :   // (for backwards compatibility with libMesh HDF5 users), but we
      82             :   // want to avoid this by default (for backwards compatibility with
      83             :   // most Moose users and to avoid generating regression test gold
      84             :   // files that non-HDF5 Moose builds can't read)
      85       86020 :   params.addParam<bool>("write_hdf5", false, "Enables HDF5 output format for Exodus files.");
      86             : 
      87             :   // Need a layer of geometric ghosting for mesh serialization
      88       86020 :   params.addRelationshipManager("ElementPointNeighborLayers",
      89             :                                 Moose::RelationshipManagerType::GEOMETRIC);
      90             : 
      91             :   // Return the InputParameters
      92      172040 :   return params;
      93       86020 : }
      94             : 
      95       34725 : Exodus::Exodus(const InputParameters & parameters)
      96             :   : SampledOutput(parameters),
      97       34713 :     _exodus_initialized(false),
      98       34713 :     _exodus_mesh_changed(declareRestartableData<bool>("exodus_mesh_changed", true)),
      99       69396 :     _sequence(isParamValid("sequence") ? getParam<bool>("sequence")
     100       34683 :               : _use_displaced         ? true
     101             :                                        : false),
     102       34713 :     _exodus_num(declareRestartableData<unsigned int>("exodus_num", 0)),
     103       34713 :     _recovering(_app.isRecovering()),
     104       34713 :     _overwrite(getParam<bool>("overwrite")),
     105       34713 :     _output_dimension(getParam<MooseEnum>("output_dimension").getEnum<OutputDimension>()),
     106       34713 :     _discontinuous(getParam<bool>("discontinuous")),
     107       34713 :     _side_discontinuous(getParam<bool>("side_discontinuous")),
     108      104151 :     _write_hdf5(getParam<bool>("write_hdf5"))
     109             : {
     110       34713 :   if (isParamValid("use_problem_dimension"))
     111             :   {
     112           0 :     auto use_problem_dimension = getParam<bool>("use_problem_dimension");
     113             : 
     114           0 :     if (use_problem_dimension)
     115           0 :       _output_dimension = OutputDimension::PROBLEM_DIMENSION;
     116             :     else
     117           0 :       _output_dimension = OutputDimension::DEFAULT;
     118             :   }
     119             :   // If user sets 'discontinuous = true' and 'elemental_as_nodal = false', issue an error that these
     120             :   // are incompatible states
     121       34713 :   if (_discontinuous && parameters.isParamSetByUser("elemental_as_nodal") && !_elemental_as_nodal)
     122           0 :     mooseError(name(),
     123             :                ": Invalid parameters. 'elemental_as_nodal' set to false while 'discontinuous' set "
     124             :                "to true.");
     125             :   // At this point, if we have discontinuous ouput, we know the user hasn't explicitly set
     126             :   // 'elemental_as_nodal = false', so we can safely default it to true
     127       34713 :   if (_discontinuous)
     128          36 :     _elemental_as_nodal = true;
     129       34713 : }
     130             : 
     131             : void
     132           0 : Exodus::setOutputDimension(unsigned int /*dim*/)
     133             : {
     134           0 :   mooseDeprecated(
     135             :       "This method is no longer needed. We can determine output dimension programmatically");
     136           0 : }
     137             : 
     138             : void
     139       34250 : Exodus::initialSetup()
     140             : {
     141             :   // Call base class setup method
     142       34250 :   SampledOutput::initialSetup();
     143             : 
     144             :   // The libMesh::ExodusII_IO will fail when it is closed if the object is created but
     145             :   // nothing is written to the file. This checks that at least something will be written.
     146       34246 :   if (!hasOutput())
     147           0 :     mooseError("The current settings result in nothing being output to the Exodus file.");
     148             : 
     149             :   // Test that some sort of variable output exists (case when all variables are disabled but input
     150             :   // output is still enabled
     151       34294 :   if (!hasNodalVariableOutput() && !hasElementalVariableOutput() && !hasPostprocessorOutput() &&
     152          48 :       !hasScalarOutput())
     153           4 :     mooseError("The current settings results in only the input file and no variables being output "
     154             :                "to the Exodus file, this is not supported.");
     155       34242 : }
     156             : 
     157             : void
     158        4742 : Exodus::meshChanged()
     159             : {
     160             :   // Maintain Sampled::meshChanged() functionality
     161        4742 :   SampledOutput::meshChanged();
     162             : 
     163             :   // Indicate to the Exodus object that the mesh has changed
     164        4742 :   _exodus_mesh_changed = true;
     165        4742 : }
     166             : 
     167             : void
     168           0 : Exodus::sequence(bool state)
     169             : {
     170           0 :   _sequence = state;
     171           0 : }
     172             : 
     173             : void
     174      157257 : Exodus::outputSetup()
     175             : {
     176      157257 :   if (_exodus_io_ptr)
     177             :   {
     178             :     // Do nothing if the ExodusII_IO objects exists, but has not been initialized
     179      124614 :     if (!_exodus_initialized)
     180      121243 :       return;
     181             : 
     182             :     // Do nothing if the output is using oversampling. In this case the mesh that is being output
     183             :     // has not been changed, so there is no need to create a new ExodusII_IO object
     184      119272 :     if (_use_sampled_output)
     185         282 :       return;
     186             : 
     187             :     // Do nothing if the mesh has not changed and sequential output is not desired
     188      118990 :     if (!_exodus_mesh_changed && !_sequence)
     189      115619 :       return;
     190             :   }
     191             : 
     192       76394 :   auto serialize = [this](auto & moose_mesh)
     193             :   {
     194       38197 :     auto & lm_mesh = moose_mesh.getMesh();
     195             :     // Exodus is serial output so that we have to gather everything to "zero".
     196       38197 :     lm_mesh.gather_to_zero();
     197             :     // This makes the face information out-of-date on process 0 for distributed meshes, e.g.
     198             :     // elements will have neighbors that they didn't previously have
     199       38197 :     if ((this->processor_id() == 0) && !lm_mesh.is_replicated())
     200        3791 :       moose_mesh.markFiniteVolumeInfoDirty();
     201       74211 :   };
     202       36014 :   serialize(_problem_ptr->mesh());
     203             : 
     204             :   // We need to do the same thing for displaced mesh to make them consistent.
     205             :   // In general, it is a good idea to make the reference mesh and the displaced mesh
     206             :   // consistent since some operations or calculations are already based on this assumption.
     207             :   // For example,
     208             :   // FlagElementsThread::onElement(const Elem * elem)
     209             :   //   if (_displaced_problem)
     210             :   //    _displaced_problem->mesh().elemPtr(elem->id())->set_refinement_flag((Elem::RefinementState)marker_value);
     211             :   // Here we assume that the displaced mesh and the reference mesh are identical except
     212             :   // coordinations.
     213       36014 :   if (_problem_ptr->getDisplacedProblem())
     214        2183 :     serialize(_problem_ptr->getDisplacedProblem()->mesh());
     215             : 
     216             :   // Create the ExodusII_IO object
     217       36014 :   _exodus_io_ptr = std::make_unique<ExodusII_IO>(_es_ptr->get_mesh());
     218       36014 :   _exodus_initialized = false;
     219             : 
     220       36014 :   if (_write_hdf5)
     221             :   {
     222             : #ifndef LIBMESH_HAVE_HDF5
     223             :     mooseError("Moose input requested HDF Exodus output, but libMesh was built without HDF5.");
     224             : #endif
     225             : 
     226             :     // This is redundant unless the libMesh default changes
     227           0 :     _exodus_io_ptr->set_hdf5_writing(true);
     228             :   }
     229             :   else
     230             :   {
     231       36014 :     _exodus_io_ptr->set_hdf5_writing(false);
     232             :   }
     233             : 
     234       36014 :   if (_side_discontinuous)
     235          22 :     _exodus_io_ptr->write_added_sides(true);
     236             : 
     237             :   // Increment file number and set appending status, append if all the following conditions are met:
     238             :   //   (1) If the application is recovering (not restarting)
     239             :   //   (2) The mesh has NOT changed
     240             :   //   (3) An existing Exodus file exists for appending (_exodus_num > 0)
     241             :   //   (4) Sequential output is NOT desired
     242             :   //   (5) Exodus is NOT being output only on FINAL
     243       36789 :   if (_recovering && !_exodus_mesh_changed && _exodus_num > 0 && !_sequence &&
     244         775 :       (getExecuteOnEnum().size() != 1 || !getExecuteOnEnum().contains(EXEC_FINAL)))
     245             :   {
     246             :     // Set the recovering flag to false so that this special case is not triggered again
     247         775 :     _recovering = false;
     248             : 
     249             :     // Set the append flag to true b/c on recover the file is being appended
     250         775 :     _exodus_io_ptr->append(true);
     251             :   }
     252             :   else
     253             :   {
     254             :     // Disable file appending and reset exodus file number count
     255       35239 :     _exodus_io_ptr->append(false);
     256             : 
     257             :     // Customize file output
     258       35239 :     customizeFileOutput();
     259             :   }
     260             : 
     261       36014 :   setOutputDimensionInExodusWriter(*_exodus_io_ptr, *_mesh_ptr, _output_dimension);
     262             : }
     263             : 
     264             : void
     265       35239 : Exodus::customizeFileOutput()
     266             : {
     267       35239 :   if (_exodus_mesh_changed || _sequence)
     268       34428 :     _file_num++;
     269             : 
     270       35239 :   _exodus_num = 1;
     271       35239 : }
     272             : 
     273             : void
     274       39020 : Exodus::setOutputDimensionInExodusWriter(ExodusII_IO & exodus_io,
     275             :                                          const MooseMesh & mesh,
     276             :                                          OutputDimension output_dimension)
     277             : {
     278       39020 :   switch (output_dimension)
     279             :   {
     280       39009 :     case OutputDimension::DEFAULT:
     281             :       // If the mesh_dimension is 1, we need to write out as 3D.
     282             :       //
     283             :       // This works around an issue in Paraview where 1D meshes cannot
     284             :       // not be visualized correctly. Otherwise, write out based on the effectiveSpatialDimension.
     285       39009 :       if (mesh.getMesh().mesh_dimension() == 1)
     286        4391 :         exodus_io.write_as_dimension(3);
     287             :       else
     288       34618 :         exodus_io.write_as_dimension(static_cast<int>(mesh.effectiveSpatialDimension()));
     289       39009 :       break;
     290             : 
     291          11 :     case OutputDimension::ONE:
     292             :     case OutputDimension::TWO:
     293             :     case OutputDimension::THREE:
     294          11 :       exodus_io.write_as_dimension(static_cast<int>(output_dimension));
     295          11 :       break;
     296             : 
     297           0 :     case OutputDimension::PROBLEM_DIMENSION:
     298           0 :       exodus_io.use_mesh_dimension_instead_of_spatial_dimension(true);
     299           0 :       break;
     300             : 
     301           0 :     default:
     302           0 :       ::mooseError("Unknown output_dimension in Exodus writer");
     303             :   }
     304       39020 : }
     305             : 
     306             : void
     307      143082 : Exodus::outputNodalVariables()
     308             : {
     309             :   // Set the output variable to the nodal variables
     310      143082 :   std::vector<std::string> nodal(getNodalVariableOutput().begin(), getNodalVariableOutput().end());
     311      143082 :   _exodus_io_ptr->set_output_variables(nodal);
     312             : 
     313             :   // Check if the mesh is contiguously numbered, because exodus output will renumber to force that
     314      143082 :   const auto & mesh = _problem_ptr->mesh().getMesh();
     315             :   const bool mesh_contiguous_numbering =
     316      143082 :       (mesh.n_nodes() == mesh.max_node_id()) && (mesh.n_elem() == mesh.max_elem_id());
     317             : 
     318             :   // Write the data via libMesh::ExodusII_IO
     319      143082 :   if (_discontinuous)
     320         110 :     _exodus_io_ptr->write_timestep_discontinuous(
     321         110 :         filename(), *_es_ptr, _exodus_num, getOutputTime() + _app.getGlobalTimeOffset());
     322             :   else
     323      286054 :     _exodus_io_ptr->write_timestep(
     324      286054 :         filename(), *_es_ptr, _exodus_num, getOutputTime() + _app.getGlobalTimeOffset());
     325             : 
     326      143082 :   if (!_overwrite)
     327      139728 :     _exodus_num++;
     328             : 
     329      143082 :   if (!mesh_contiguous_numbering)
     330          35 :     handleExodusIOMeshRenumbering();
     331             : 
     332             :   // This satisfies the initialization of the ExodusII_IO object
     333      143082 :   _exodus_initialized = true;
     334      143082 : }
     335             : 
     336             : void
     337       33721 : Exodus::outputElementalVariables()
     338             : {
     339             :   // Make sure the the file is ready for writing of elemental data
     340       33721 :   if (!_exodus_initialized || !hasNodalVariableOutput())
     341        8010 :     outputEmptyTimestep();
     342             : 
     343             :   // Write the elemental data
     344       33721 :   std::vector<std::string> elemental(getElementalVariableOutput().begin(),
     345       67442 :                                      getElementalVariableOutput().end());
     346       33721 :   _exodus_io_ptr->set_output_variables(elemental);
     347       33721 :   _exodus_io_ptr->write_element_data(*_es_ptr);
     348       33721 : }
     349             : 
     350             : void
     351       33499 : Exodus::outputPostprocessors()
     352             : {
     353             :   // List of desired postprocessor outputs
     354       33499 :   const std::set<std::string> & pps = getPostprocessorOutput();
     355             : 
     356             :   // Append the postprocessor data to the global name value parameters; scalar outputs
     357             :   // also append these member variables
     358       94229 :   for (const auto & name : pps)
     359             :   {
     360       60730 :     _global_names.push_back(name);
     361       60730 :     _global_values.push_back(_problem_ptr->getPostprocessorValueByName(name));
     362             :   }
     363       33499 : }
     364             : 
     365             : void
     366         457 : Exodus::outputReporters()
     367             : {
     368        2012 :   for (const auto & combined_name : getReporterOutput())
     369             :   {
     370        1555 :     ReporterName r_name(combined_name);
     371        1772 :     if (_reporter_data.hasReporterValue<Real>(r_name) &&
     372        1772 :         !hasPostprocessorByName(r_name.getObjectName()))
     373             :     {
     374         217 :       const Real & value = _reporter_data.getReporterValue<Real>(r_name);
     375         217 :       _global_names.push_back(r_name.getValueName());
     376         217 :       _global_values.push_back(value);
     377             :     }
     378        1555 :   }
     379         457 : }
     380             : 
     381             : void
     382        3888 : Exodus::outputScalarVariables()
     383             : {
     384             :   // List of desired scalar outputs
     385        3888 :   const std::set<std::string> & out = getScalarOutput();
     386             : 
     387             :   // Append the scalar to the global output lists
     388       10745 :   for (const auto & out_name : out)
     389             :   {
     390             :     // Make sure scalar values are in sync with the solution vector
     391             :     // and are visible on this processor.  See TableOutput.C for
     392             :     // TableOutput::outputScalarVariables() explanatory comments
     393             : 
     394        6857 :     MooseVariableScalar & scalar_var = _problem_ptr->getScalarVariable(0, out_name);
     395        6857 :     scalar_var.reinit();
     396        6857 :     VariableValue value(scalar_var.sln());
     397             : 
     398        6857 :     const std::vector<dof_id_type> & dof_indices = scalar_var.dofIndices();
     399        6857 :     const unsigned int n = dof_indices.size();
     400        6857 :     value.resize(n);
     401             : 
     402        6857 :     const DofMap & dof_map = scalar_var.sys().dofMap();
     403       14774 :     for (unsigned int i = 0; i != n; ++i)
     404             :     {
     405        7917 :       const processor_id_type pid = dof_map.dof_owner(dof_indices[i]);
     406        7917 :       this->comm().broadcast(value[i], pid);
     407             :     }
     408             : 
     409             :     // If the scalar has a single component, output the name directly
     410        6857 :     if (n == 1)
     411             :     {
     412        6296 :       _global_names.push_back(out_name);
     413        6296 :       _global_values.push_back(value[0]);
     414             :     }
     415             : 
     416             :     // If the scalar as many components add indices to the end of the name
     417             :     else
     418             :     {
     419        2182 :       for (unsigned int i = 0; i < n; ++i)
     420             :       {
     421        1621 :         std::ostringstream os;
     422        1621 :         os << out_name << "_" << i;
     423        1621 :         _global_names.push_back(os.str());
     424        1621 :         _global_values.push_back(value[i]);
     425        1621 :       }
     426             :     }
     427        6857 :   }
     428        3888 : }
     429             : 
     430             : void
     431       31628 : Exodus::outputInput()
     432             : {
     433             :   // Format the input file
     434       31628 :   ExodusFormatter syntax_formatter;
     435       31628 :   syntax_formatter.printInputFile(_app.actionWarehouse());
     436       31628 :   syntax_formatter.format();
     437             : 
     438             :   // Store the information
     439       31628 :   _input_record = syntax_formatter.getInputFileRecord();
     440       31628 : }
     441             : 
     442             : void
     443      157257 : Exodus::output()
     444             : {
     445             :   // Prepare the ExodusII_IO object
     446      157257 :   outputSetup();
     447      157257 :   LockFile lf(filename(), processor_id() == 0);
     448             : 
     449             :   // Adjust the position of the output
     450      157257 :   if (_app.hasOutputPosition())
     451        5833 :     _exodus_io_ptr->set_coordinate_offset(_app.getOutputPosition());
     452             : 
     453             :   // Clear the global variables (postprocessors and scalars)
     454      157257 :   _global_names.clear();
     455      157257 :   _global_values.clear();
     456             : 
     457             :   // Call the individual output methods
     458      157257 :   AdvancedOutput::output();
     459             : 
     460             :   // Write the global variables (populated by the output methods)
     461      157257 :   if (!_global_values.empty())
     462             :   {
     463       34549 :     if (!_exodus_initialized)
     464          42 :       outputEmptyTimestep();
     465       34549 :     _exodus_io_ptr->write_global_data(_global_values, _global_names);
     466             :   }
     467             : 
     468             :   // Write the input file record if it exists and the output file is initialized
     469      157257 :   if (!_input_record.empty() && _exodus_initialized)
     470             :   {
     471       31543 :     _exodus_io_ptr->write_information_records(_input_record);
     472       31543 :     _input_record.clear();
     473             :   }
     474             : 
     475             :   // Reset the mesh changed flag
     476      157257 :   _exodus_mesh_changed = false;
     477             : 
     478             :   // It is possible to have an empty file created with the following scenario. By default the
     479             :   // 'execute_on_input' flag is setup to run on INITIAL. If the 'execute_on' is set to FINAL
     480             :   // but the simulation stops early (e.g., --test-checkpoint-half-transient) the Exodus file is
     481             :   // created but there is no data in it, because of the initial call to write the input data seems
     482             :   // to create the file but doesn't actually write the data into the solution/mesh is also supplied
     483             :   // to the IO object. Then if --recover is used this empty file fails to open for appending.
     484             :   //
     485             :   // The code below will delete any empty files that exist. Another solution is to set the
     486             :   // 'execute_on_input' flag to NONE.
     487      157257 :   std::string current = filename();
     488      273643 :   if (processor_id() == 0 && MooseUtils::checkFileReadable(current, false, false) &&
     489      116386 :       (MooseUtils::fileSize(current) == 0))
     490             :   {
     491        3310 :     int err = std::remove(current.c_str());
     492        3310 :     if (err != 0)
     493           0 :       mooseError("MOOSE failed to remove the empty file ", current);
     494             :   }
     495      157257 : }
     496             : 
     497             : std::string
     498      499950 : Exodus::filename()
     499             : {
     500             :   // Append the .e extension on the base file name
     501      499950 :   std::ostringstream output;
     502      499950 :   output << _file_base + ".e";
     503             : 
     504             :   // Add the -s00x extension to the file
     505      499950 :   if (_file_num > 1)
     506       15250 :     output << "-s" << std::setw(_padding) << std::setprecision(0) << std::setfill('0') << std::right
     507       15250 :            << _file_num;
     508             : 
     509      999900 :   return output.str();
     510      499950 : }
     511             : 
     512             : void
     513        8052 : Exodus::outputEmptyTimestep()
     514             : {
     515             :   // Check if the mesh is contiguously numbered, because exodus output will renumber to force that
     516        8052 :   const auto & mesh = _problem_ptr->mesh().getMesh();
     517             :   const bool mesh_contiguous_numbering =
     518        8052 :       (mesh.n_nodes() == mesh.max_node_id()) && (mesh.n_elem() == mesh.max_elem_id());
     519             : 
     520             :   // Write a timestep with no variables
     521        8052 :   _exodus_io_ptr->set_output_variables(std::vector<std::string>());
     522       16104 :   _exodus_io_ptr->write_timestep(
     523       16104 :       filename(), *_es_ptr, _exodus_num, getOutputTime() + _app.getGlobalTimeOffset());
     524             : 
     525        8052 :   if (!_overwrite)
     526        8008 :     _exodus_num++;
     527             : 
     528        8052 :   if (!mesh_contiguous_numbering)
     529          22 :     handleExodusIOMeshRenumbering();
     530        8052 :   _exodus_initialized = true;
     531        8052 : }
     532             : 
     533             : void
     534        2463 : Exodus::clear()
     535             : {
     536        2463 :   _exodus_io_ptr.reset();
     537        2463 : }
     538             : 
     539             : void
     540          57 : Exodus::handleExodusIOMeshRenumbering()
     541             : {
     542             :   // We renumbered our mesh, so we need the other mesh to do the same
     543          57 :   if (auto * const disp_problem = _problem_ptr->getDisplacedProblem().get(); disp_problem)
     544             :   {
     545          11 :     auto & disp_eq = disp_problem->es();
     546          11 :     auto & other_mesh = &disp_eq == _es_ptr ? _problem_ptr->mesh().getMesh() : disp_eq.get_mesh();
     547             :     mooseAssert(
     548             :         !other_mesh.allow_renumbering(),
     549             :         "The only way we shouldn't have contiguous numbering is if we've disabled renumbering");
     550          11 :     other_mesh.allow_renumbering(true);
     551          11 :     other_mesh.renumber_nodes_and_elements();
     552             :     // Copying over the comment in MeshOutput::write_equation_systems
     553             :     // Not sure what good going back to false will do here, the
     554             :     // renumbering horses have already left the barn...
     555          11 :     other_mesh.allow_renumbering(false);
     556             :   }
     557             : 
     558             :   // Objects that depend on element/node ids are no longer valid
     559          57 :   _problem_ptr->meshChanged(
     560             :       /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
     561          57 : }

Generated by: LCOV version 1.14