LCOV - code coverage report
Current view: top level - src/actions - MeshOnlyAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 91 96 94.8 %
Date: 2026-05-29 20:35:17 Functions: 3 3 100.0 %
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 "MeshOnlyAction.h"
      11             : 
      12             : #include "MooseApp.h"
      13             : #include "MooseMesh.h"
      14             : #include "Exodus.h"
      15             : #include "AddOutputAction.h"
      16             : #include "RestartableDataWriter.h"
      17             : 
      18             : #include <filesystem>
      19             : 
      20             : #include "libmesh/exodusII_io.h"
      21             : #include "libmesh/exodusII_io_helper.h"
      22             : #include "libmesh/checkpoint_io.h"
      23             : 
      24             : using namespace libMesh;
      25             : 
      26             : registerMooseAction("MooseApp", MeshOnlyAction, "mesh_only");
      27             : 
      28             : InputParameters
      29        4185 : MeshOnlyAction::validParams()
      30             : {
      31        4185 :   return Action::validParams();
      32             : }
      33             : 
      34        4185 : MeshOnlyAction::MeshOnlyAction(const InputParameters & params) : Action(params) {}
      35             : 
      36             : void
      37        3744 : MeshOnlyAction::act()
      38             : {
      39             :   // Run error checking on input file first before trying to generate a mesh
      40        3744 :   bool warn = _app.unusedFlagIsWarning();
      41        3744 :   bool err = _app.unusedFlagIsError();
      42        3744 :   _app.builder().errorCheck(comm(), warn, err);
      43             : 
      44        3741 :   std::string mesh_file = _app.parameters().get<std::string>("mesh_only");
      45        3741 :   auto & mesh_ptr = _app.actionWarehouse().mesh();
      46             : 
      47             :   // Print information about the mesh
      48        3741 :   _console << mesh_ptr->getMesh().get_info(/* verbosity = */ 2) << std::endl;
      49             : 
      50        3741 :   if (mesh_file.empty())
      51             :   {
      52        2434 :     mesh_file = _app.builder().getPrimaryFileName();
      53        2434 :     size_t pos = mesh_file.find_last_of('.');
      54             : 
      55             :     // Default to writing out an ExodusII mesh base on the input filename.
      56        2434 :     mesh_file = mesh_file.substr(0, pos) + "_in.e";
      57             :   }
      58             : 
      59             :   /**
      60             :    * If we're writing an Exodus file, write the Mesh using it's effective spatial dimension unless
      61             :    * it's a 1D mesh. This is to work around a Paraview bug where 1D meshes are not visualized
      62             :    * properly.
      63             :    */
      64        3741 :   if (mesh_file.find(".e") + 2 == mesh_file.size())
      65             :   {
      66       18600 :     TIME_SECTION("act", 1, "Writing Exodus");
      67             : 
      68        3720 :     auto & output_mesh = mesh_ptr->getMesh();
      69        3720 :     ExodusII_IO exio(output_mesh);
      70             : 
      71             :     // Default to the maximum name length allowed by libMesh ExodusII
      72        3720 :     exio.set_max_name_length(80);
      73             : 
      74             :     // Extract the Output action to look for a non-default name
      75             :     // length, e.g. truncation to 32 to match gold files
      76        7440 :     const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
      77       20032 :     for (const auto & act : output_actions)
      78             :     {
      79       16312 :       AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
      80       16312 :       if (!action)
      81        3720 :         continue;
      82             : 
      83       12592 :       InputParameters & params = action->getObjectParams();
      84       25184 :       if (params.isParamSetByUser("max_output_name_length"))
      85             :       {
      86             :         const int max_output_name_length =
      87           0 :             action->getObjectParams().get<unsigned int>("max_output_name_length");
      88             : 
      89           0 :         exio.set_max_name_length(max_output_name_length);
      90             : 
      91           0 :         break;
      92             :       }
      93             :     }
      94             : 
      95        3720 :     Exodus::setOutputDimensionInExodusWriter(exio, *mesh_ptr);
      96             : 
      97             :     // Default to non-HDF5 output for wider compatibility
      98        3720 :     exio.set_hdf5_writing(false);
      99             : 
     100        3720 :     exio.write(mesh_file);
     101             : 
     102             :     // Check if extra element integers should be outputted to Exodus file
     103        3717 :     unsigned int n_eeid = output_mesh.n_elem_integers();
     104             : 
     105             :     // Iterate through all actions and see if `Outputs/output_extra_element_ids = true` in input
     106             :     // file
     107             : 
     108             :     // Truth of whether to output extra element ids is initially determined by whether
     109             :     // there are extra element ids defined on the mesh
     110        3717 :     bool output_extra_ids = (n_eeid > 0);
     111        3717 :     bool restrict_element_id_names = false;
     112        3717 :     std::vector<std::string> element_id_names;
     113       19806 :     for (const auto & act : output_actions)
     114             :     {
     115             :       // Extract the Output action
     116       16141 :       AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
     117       16141 :       if (!action)
     118        3717 :         continue;
     119             : 
     120       12424 :       InputParameters & params = action->getObjectParams();
     121       24848 :       if (params.isParamSetByUser("output_extra_element_ids"))
     122             :       {
     123             :         // User has set output_extra_element_ids, truth of output_extra_ids determined by value of
     124             :         // parameter
     125          52 :         output_extra_ids = params.get<bool>("output_extra_element_ids");
     126          52 :         if (output_extra_ids)
     127             :         {
     128             :           // `Outputs/extra_element_ids_to_output` sets a subset of extra element ids that should
     129             :           // be outputted to Exodus
     130          13 :           restrict_element_id_names = params.isParamValid("extra_element_ids_to_output");
     131          13 :           if (restrict_element_id_names)
     132             :           {
     133          13 :             element_id_names = params.get<std::vector<std::string>>("extra_element_ids_to_output");
     134             :             // Check which element id names actually are defined on the mesh, remove from
     135             :             // element_id_names if they don't belong
     136          23 :             for (auto it = element_id_names.begin(); it != element_id_names.end();)
     137             :             {
     138             :               // Erase contents of iterator and return iterator if element integer does not exist
     139          13 :               if (!output_mesh.has_elem_integer(*it))
     140             :               {
     141           3 :                 it = element_id_names.erase(it);
     142           3 :                 mooseWarning("Extra element id ",
     143           3 :                              *it,
     144             :                              " defined in Outputs/extra_element_ids_to_output "
     145             :                              "is not defined on the mesh and will be ignored.");
     146             :               }
     147             :               // Increment iterator if element integer exists
     148             :               else
     149          10 :                 ++it;
     150             :             }
     151             :           }
     152             :         }
     153          49 :         break;
     154             :       }
     155             :     }
     156             : 
     157        3714 :     if (output_extra_ids)
     158             :     {
     159             :       // Retrieve extra element id names and associated data
     160          60 :       const auto n_elem = output_mesh.n_elem();
     161          60 :       std::vector<std::string> eeid_vars;
     162          60 :       const auto n_eeid_to_output = restrict_element_id_names ? element_id_names.size() : n_eeid;
     163          60 :       std::vector<Number> eeid_soln(n_elem * n_eeid_to_output);
     164          60 :       unsigned int soln_index = 0;
     165         120 :       for (unsigned int i = 0; i < n_eeid; i++)
     166             :       {
     167          60 :         const auto eeid_name = output_mesh.get_elem_integer_name(i);
     168             :         // If `Outputs/extra_element_ids_to_output` is not set, output all ids to Exodus
     169             :         // Otherwise only output if the extra id name is contained within
     170             :         // `Outputs/extra_element_ids_to_output`
     171          70 :         if (!restrict_element_id_names ||
     172          10 :             (std::find(element_id_names.begin(), element_id_names.end(), eeid_name) !=
     173          70 :              element_id_names.end()))
     174             :         {
     175          60 :           eeid_vars.push_back(output_mesh.get_elem_integer_name(i));
     176        2246 :           for (const auto & elem : output_mesh.element_ptr_range())
     177             :           {
     178        2186 :             eeid_soln[soln_index] = (int)elem->get_extra_integer(i);
     179        2186 :             ++soln_index;
     180          60 :           }
     181             :         }
     182          60 :       }
     183             : 
     184             :       // Check size of output variables just in case none of the variables in
     185             :       // `Outpus/extra_element_ids_to_output` are specified on the actual mesh
     186          60 :       if (eeid_vars.size() > 0)
     187             :       {
     188             :         // Invoke ExodusII_IO_Helper to output extra element ids to Exodus file
     189          60 :         auto & exio_helper = exio.get_exio_helper();
     190             : 
     191             :         // Output empty timestep to Exodus file
     192          60 :         int empty_timestep = 1;
     193          60 :         Real default_time = 1.0;
     194          60 :         exio_helper.write_timestep(empty_timestep, default_time);
     195             : 
     196             :         // Write extra element id data to Exodus file
     197          60 :         std::vector<std::set<subdomain_id_type>> vars_active_subdomains;
     198          60 :         vars_active_subdomains.resize(n_eeid_to_output);
     199          60 :         exio_helper.initialize_element_variables(eeid_vars, vars_active_subdomains);
     200          60 :         exio_helper.write_element_values(
     201             :             output_mesh, eeid_soln, empty_timestep, vars_active_subdomains);
     202          60 :       }
     203             :       else
     204           0 :         mooseWarning(
     205             :             "Outputs/output_extra_element_ids is set to true but no extra element ids are being "
     206             :             "outputted. Please check extra element ids are properly defined on the mesh and any "
     207             :             "variables specified in Outputs/extra_element_ids_to_output are spelled correctly.");
     208          60 :     }
     209        3720 :   }
     210             : 
     211          21 :   else if (mesh_file.find(".cpa.gz") + 7 == mesh_file.size())
     212             :   {
     213         105 :     TIME_SECTION("act", 1, "Writing Checkpoint");
     214             : 
     215          21 :     CheckpointIO io(mesh_ptr->getMesh(), false);
     216          21 :     io.write(mesh_file);
     217             : 
     218             :     // Write mesh metadata
     219          21 :     if (processor_id() == 0)
     220             :     {
     221           7 :       const auto filenames = _app.writeRestartableMetaData(MooseApp::MESH_META_DATA, mesh_file);
     222           7 :       Moose::out << "Mesh meta data written into "
     223           7 :                  << std::filesystem::absolute(filenames[0].parent_path()) << "." << std::endl;
     224           7 :     }
     225          21 :   }
     226             :   else
     227             :   {
     228             :     // Just write the file using the name requested by the user.
     229           0 :     mesh_ptr->getMesh().write(mesh_file);
     230             :   }
     231        3738 : }

Generated by: LCOV version 1.14