LCOV - code coverage report
Current view: top level - src/restart - RestartableEquationSystems.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 99787a Lines: 208 229 90.8 %
Date: 2025-10-14 20:01:24 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 "RestartableEquationSystems.h"
      11             : 
      12             : #include "DataIO.h"
      13             : 
      14             : #include "libmesh/dof_map.h"
      15             : #include "libmesh/dof_object.h"
      16             : #include "libmesh/elem.h"
      17             : #include "libmesh/node.h"
      18             : 
      19             : const std::string RestartableEquationSystems::SystemHeader::system_solution_name =
      20             :     "SYSTEM_SOLUTION";
      21             : 
      22       64512 : RestartableEquationSystems::RestartableEquationSystems(libMesh::MeshBase & mesh)
      23       64512 :   : _es(mesh), _load_all_vectors(true)
      24             : {
      25       64512 : }
      26             : 
      27             : RestartableEquationSystems::EquationSystemsHeader
      28       45777 : RestartableEquationSystems::buildHeader(
      29             :     const std::vector<const libMesh::DofObject *> & ordered_objects) const
      30             : {
      31       45777 :   EquationSystemsHeader es_header;
      32             : 
      33             :   // Systems
      34      138374 :   for (const auto sys_num : make_range(_es.n_systems()))
      35             :   {
      36       92597 :     const auto & sys = _es.get_system(sys_num);
      37             : 
      38       92597 :     SystemHeader sys_header;
      39       92597 :     sys_header.name = sys.name();
      40       92597 :     sys_header.type = sys.system_type();
      41             : 
      42             :     // Variables in the system
      43      184855 :     for (const auto var_num : make_range(sys.n_vars()))
      44             :     {
      45       92258 :       const auto & var = sys.variable(var_num);
      46             : 
      47       92258 :       VariableHeader var_header;
      48       92258 :       var_header.name = var.name();
      49       92258 :       var_header.type = var.type();
      50       92258 :       var_header.size = 0;
      51       92258 :       var_header.variable = &var;
      52             : 
      53             :       mooseAssert(_es.comm().verify("sys_" + sys.name() + "_var_" + var.name()),
      54             :                   "Out of order in parallel");
      55             :       mooseAssert(!sys_header.variables.count(var.name()), "Already inserted");
      56             : 
      57             :       // Non-SCALAR variable
      58       92258 :       if (var.type().family != SCALAR)
      59             :       {
      60    18673938 :         for (const auto & obj : ordered_objects)
      61    18583372 :           var_header.size += sizeof(Real) * obj->n_comp(sys.number(), var.number());
      62             :       }
      63             :       // SCALAR variable on the last rank
      64        1692 :       else if (_es.processor_id() == _es.n_processors() - 1)
      65             :       {
      66        1655 :         std::vector<dof_id_type> scalar_dofs;
      67        1655 :         sys.get_dof_map().SCALAR_dof_indices(scalar_dofs, var.number());
      68        1655 :         var_header.size += sizeof(Real) * scalar_dofs.size();
      69        1655 :       }
      70             : 
      71       92258 :       sys_header.variables.emplace(var.name(), var_header);
      72       92258 :     }
      73             : 
      74             :     // System vector
      75       92597 :     auto & sys_vec_header = sys_header.vectors[SystemHeader::system_solution_name];
      76       92597 :     sys_vec_header.name = SystemHeader::system_solution_name;
      77       92597 :     sys_vec_header.vector = sys.solution.get();
      78       92597 :     sys_vec_header.type = sys_vec_header.vector->type();
      79      435235 :     for (const auto vec_num : make_range(sys.n_vectors()))
      80             :     {
      81             :       mooseAssert(_es.comm().verify("sys_" + sys.name() + "_vec_" + sys.vector_name(vec_num)),
      82             :                   "Out of order in parallel");
      83      342638 :       const auto & name = sys.vector_name(vec_num);
      84             :       mooseAssert(!sys_header.vectors.count(name), "Already inserted");
      85      342638 :       auto & vec_header = sys_header.vectors[name];
      86      342638 :       vec_header.name = sys.vector_name(vec_num);
      87      342638 :       vec_header.projections = sys.vector_preservation(vec_header.name);
      88      342638 :       vec_header.vector = &sys.get_vector(vec_header.name);
      89      342638 :       vec_header.type = vec_header.vector->type();
      90             :     }
      91             : 
      92             :     // System in this EquationSystems
      93             :     mooseAssert(!es_header.systems.count(sys.name()), "Already inserted");
      94       92597 :     es_header.systems.emplace(sys.name(), sys_header);
      95       92597 :   }
      96             : 
      97             :   // Setup the positions in each vector for easy access later
      98       45777 :   std::size_t offset = 0;
      99      138374 :   for (auto & sys_name_header_pair : es_header.systems)
     100             :   {
     101       92597 :     auto & sys_header = sys_name_header_pair.second;
     102      527832 :     for (auto & vec_name_header_pair : sys_header.vectors)
     103             :     {
     104      435235 :       auto & vec_header = vec_name_header_pair.second;
     105      869500 :       for (const auto & var_name_header_pair : sys_header.variables)
     106             :       {
     107      434265 :         const auto & var_header = var_name_header_pair.second;
     108             :         mooseAssert(!vec_header.variable_offset.count(var_header.name), "Already inserted");
     109      434265 :         vec_header.variable_offset[var_header.name] = offset;
     110      434265 :         offset += var_header.size;
     111             :       }
     112             :     }
     113             :   }
     114             : 
     115       45777 :   es_header.data_size = offset;
     116             : 
     117       45777 :   return es_header;
     118           0 : }
     119             : 
     120             : std::vector<const libMesh::DofObject *>
     121       60315 : RestartableEquationSystems::orderDofObjects() const
     122             : {
     123       60315 :   std::vector<const libMesh::DofObject *> objects;
     124      120630 :   auto add = [&objects](const auto begin, const auto end)
     125             :   {
     126      120630 :     std::set<const libMesh::DofObject *, libMesh::CompareDofObjectsByID> ordered(begin, end);
     127      120630 :     objects.insert(objects.end(), ordered.begin(), ordered.end());
     128      180945 :   };
     129             : 
     130       60315 :   const auto & mesh = _es.get_mesh();
     131       60315 :   add(mesh.local_elements_begin(), mesh.local_elements_end());
     132       60315 :   add(mesh.local_nodes_begin(), mesh.local_nodes_end());
     133             : 
     134      120630 :   return objects;
     135           0 : }
     136             : 
     137             : void
     138       45777 : RestartableEquationSystems::store(std::ostream & stream) const
     139             : {
     140             :   // Order objects (elements and then nodes) by ID for storing
     141       45777 :   const auto ordered_objects = orderDofObjects();
     142             : 
     143             :   // Store the header (systems, variables, vectors)
     144       45777 :   EquationSystemsHeader es_header = buildHeader(ordered_objects);
     145       45777 :   dataStore(stream, es_header, nullptr);
     146             : 
     147             :   // Store the ordered objects so we can do a sanity check on if we're
     148             :   // loading the same thing
     149             :   {
     150       45777 :     std::vector<dof_id_type> ordered_objects_ids(ordered_objects.size());
     151     9889680 :     for (const auto i : index_range(ordered_objects))
     152     9843903 :       ordered_objects_ids[i] = ordered_objects[i]->id();
     153       45777 :     dataStore(stream, ordered_objects_ids, nullptr);
     154       45777 :   }
     155             : 
     156             : #ifndef NDEBUG
     157             :   const std::size_t data_initial_position = static_cast<std::size_t>(stream.tellp());
     158             : #endif
     159             : 
     160             :   // Store each system
     161      138374 :   for (const auto & sys_name_header_pair : es_header.systems)
     162             :   {
     163       92597 :     const auto & sys_header = sys_name_header_pair.second;
     164       92597 :     const auto & sys = _es.get_system(sys_header.name);
     165             : 
     166             :     // Store each vector and variable
     167      527832 :     for (const auto & vec_name_header_pair : sys_header.vectors)
     168             :     {
     169      435235 :       const auto & vec_header = vec_name_header_pair.second;
     170      435235 :       const auto & vec = *vec_header.vector;
     171      869500 :       for (const auto & var_name_header_pair : sys_header.variables)
     172             :       {
     173      434265 :         const auto & var_header = var_name_header_pair.second;
     174      434265 :         const auto & var = *var_header.variable;
     175             : 
     176             : #ifndef NDEBUG
     177             :         const std::size_t var_initial_position = stream.tellp();
     178             : #endif
     179             : 
     180             :         // Non-SCALAR variable
     181      434265 :         if (var.type().family != SCALAR)
     182             :         {
     183             :           // Store for each component of each element and node
     184    82534626 :           for (const auto & obj : ordered_objects)
     185   124067433 :             for (const auto comp : make_range(obj->n_comp(sys.number(), var.number())))
     186             :             {
     187    41958934 :               auto val = vec(obj->dof_number(sys.number(), var.number(), comp));
     188    41958934 :               dataStore(stream, val, nullptr);
     189             :             }
     190             :         }
     191             :         // SCALAR variable on the last rank
     192        8138 :         else if (_es.processor_id() == _es.n_processors() - 1)
     193             :         {
     194        8027 :           const auto & dof_map = sys.get_dof_map();
     195        8027 :           std::vector<dof_id_type> scalar_dofs;
     196        8027 :           dof_map.SCALAR_dof_indices(scalar_dofs, var.number());
     197       17420 :           for (const auto dof : scalar_dofs)
     198             :           {
     199        9393 :             auto val = vec(dof);
     200        9393 :             dataStore(stream, val, nullptr);
     201             :           }
     202        8027 :         }
     203             : 
     204             : #ifndef NDEBUG
     205             :         const std::size_t data_offset = var_initial_position - data_initial_position;
     206             :         mooseAssert(vec_header.variable_offset.at(var_header.name) == data_offset,
     207             :                     "Invalid offset");
     208             : 
     209             :         const std::size_t current_position = static_cast<std::size_t>(stream.tellp());
     210             :         const std::size_t var_size = current_position - var_initial_position;
     211             :         mooseAssert(var_size == sys_header.variables.at(var.name()).size, "Incorrect assumed size");
     212             : #endif
     213             :       }
     214             :     }
     215             :   }
     216             : 
     217             :   mooseAssert((data_initial_position + es_header.data_size) ==
     218             :                   static_cast<std::size_t>(stream.tellp()),
     219             :               "Incorrect assumed size");
     220       45777 : }
     221             : 
     222             : void
     223       14538 : RestartableEquationSystems::load(std::istream & stream)
     224             : {
     225             :   // Load the header (systems, variables, vectors)
     226             :   // We do this first so that the loader can make informed decisions
     227             :   // on what to put where based on everything that is available
     228       14538 :   _loaded_header.systems.clear();
     229       14538 :   dataLoad(stream, _loaded_header, nullptr);
     230             : 
     231             :   // Order objects (elements and then node) by ID for storing
     232       14538 :   _loaded_ordered_objects = orderDofObjects();
     233             : 
     234             :   // Clear previously loaded variables to ensure a clean state
     235       14538 :   _loaded_variables.clear();
     236             : 
     237             :   // Sanity check on if we're loading the same thing
     238             :   {
     239       14538 :     std::vector<dof_id_type> from_ordered_objects_ids;
     240       14538 :     dataLoad(stream, from_ordered_objects_ids, nullptr);
     241       14538 :     if (_loaded_ordered_objects.size() != from_ordered_objects_ids.size())
     242           0 :       mooseError("RestartableEquationSystems::load(): Number of previously stored elements/nodes (",
     243           0 :                  _loaded_ordered_objects.size(),
     244             :                  ") does not "
     245             :                  "match the current number of elements/nodes (",
     246           0 :                  from_ordered_objects_ids.size(),
     247             :                  ")");
     248     3713327 :     for (const auto i : index_range(_loaded_ordered_objects))
     249     3698789 :       if (_loaded_ordered_objects[i]->id() != from_ordered_objects_ids[i])
     250           0 :         mooseError("RestartableEquationSystems::load(): Id of previously stored element/node (",
     251           0 :                    _loaded_ordered_objects[i]->id(),
     252             :                    ") does not "
     253             :                    "match the current element/node id (",
     254           0 :                    from_ordered_objects_ids[i],
     255             :                    ")");
     256       14538 :   }
     257             : 
     258       14538 :   _loaded_stream_data_begin = static_cast<std::size_t>(stream.tellg());
     259             : 
     260             :   // Load everything that we have available at the moment
     261       43750 :   for (const auto & sys_name_header_pair : _loaded_header.systems)
     262             :   {
     263       29212 :     const auto & sys_header = sys_name_header_pair.second;
     264       29212 :     if (!_es.has_system(sys_header.name))
     265          62 :       continue;
     266       29150 :     auto & sys = _es.get_system(sys_header.name);
     267             : 
     268       29150 :     bool modified_sys = false;
     269             : 
     270      151520 :     for (const auto & vec_name_header_pair : sys_header.vectors)
     271             :     {
     272      122370 :       bool modified_vec = false;
     273             : 
     274      122370 :       const auto & vec_header = vec_name_header_pair.second;
     275      122370 :       const bool is_solution = vec_header.name == SystemHeader::system_solution_name;
     276             : 
     277      122370 :       if (!is_solution && !sys.have_vector(vec_header.name))
     278             :       {
     279         341 :         if (_load_all_vectors)
     280         257 :           sys.add_vector(vec_header.name, vec_header.projections, vec_header.type);
     281             :         else
     282          84 :           continue;
     283             :       }
     284             : 
     285      122286 :       auto & vec = is_solution ? *sys.solution : sys.get_vector(vec_header.name);
     286             : 
     287      242706 :       for (const auto & var_name_header_pair : sys_header.variables)
     288             :       {
     289      120420 :         const auto & var_header = var_name_header_pair.second;
     290      120420 :         if (!sys.has_variable(var_header.name))
     291          14 :           continue;
     292      120406 :         const auto & var = sys.variable(sys.variable_number(var_header.name));
     293      120406 :         if (var.type() != var_header.type)
     294           0 :           continue;
     295             : 
     296      120406 :         restore(sys_header, vec_header, var_header, sys, vec, var, stream);
     297      120406 :         modified_vec = true;
     298             :       }
     299             : 
     300      122286 :       if (modified_vec)
     301             :       {
     302       98374 :         vec.close();
     303       98374 :         modified_sys = true;
     304             :       }
     305             :     }
     306             : 
     307       29150 :     if (modified_sys)
     308       22258 :       sys.update();
     309             :   }
     310             : 
     311             :   // Move the stream to the end of our data so that we make RestartableDataReader happy
     312       14538 :   stream.seekg(_loaded_stream_data_begin + _loaded_header.data_size);
     313       14538 : }
     314             : 
     315             : bool
     316           0 : RestartableEquationSystems::isVariableRestored(const std::string & system_name,
     317             :                                                const std::string & vector_name,
     318             :                                                const std::string & variable_name) const
     319             : {
     320           0 :   std::tuple<std::string, std::string, std::string> key(system_name, vector_name, variable_name);
     321           0 :   return _loaded_variables.count(key);
     322           0 : }
     323             : 
     324             : void
     325      120406 : RestartableEquationSystems::restore(const SystemHeader & from_sys_header,
     326             :                                     const VectorHeader & from_vec_header,
     327             :                                     const VariableHeader & from_var_header,
     328             :                                     const libMesh::System & to_sys,
     329             :                                     libMesh::NumericVector<libMesh::Number> & to_vec,
     330             :                                     const libMesh::Variable & to_var,
     331             :                                     std::istream & stream)
     332             : {
     333             : #ifndef NDEBUG
     334             :   const auto sys_it = _loaded_header.systems.find(from_sys_header.name);
     335             :   mooseAssert(sys_it != _loaded_header.systems.end(), "System does not exist");
     336             :   const auto & sys_header = sys_it->second;
     337             :   mooseAssert(sys_header == from_sys_header, "Not my system");
     338             :   const auto vec_it = sys_header.vectors.find(from_vec_header.name);
     339             :   mooseAssert(vec_it != sys_header.vectors.end(), "Vector does not exist");
     340             :   const auto & vec_header = vec_it->second;
     341             :   mooseAssert(vec_header == from_vec_header, "Not my vector");
     342             :   const auto var_it = sys_header.variables.find(from_var_header.name);
     343             :   mooseAssert(var_it != sys_header.variables.end(), "Variable does not exist");
     344             :   const auto & var_header = var_it->second;
     345             :   mooseAssert(var_header == from_var_header, "Not my variable");
     346             :   mooseAssert(!isVariableRestored(from_sys_header.name, from_vec_header.name, from_var_header.name),
     347             :               "Variable already restored");
     348             : #endif
     349             : 
     350             :   const auto error =
     351           0 :       [&from_sys_header, &from_vec_header, &from_var_header, &to_sys, &to_var](auto... args)
     352             :   {
     353           0 :     mooseError("An error occured while restoring a system:\n",
     354             :                args...,
     355             :                "\n\nFrom system: ",
     356           0 :                from_sys_header.name,
     357             :                "\nFrom vector: ",
     358           0 :                from_vec_header.name,
     359             :                "\nFrom variable: ",
     360           0 :                from_var_header.name,
     361             :                "\nTo system: ",
     362           0 :                to_sys.name(),
     363             :                "\nTo variable: ",
     364           0 :                to_var.name());
     365      120406 :   };
     366             : 
     367      120406 :   if (from_var_header.type != to_var.type())
     368           0 :     error("Cannot restore to a variable of a different type");
     369             : 
     370      120406 :   const auto offset = from_vec_header.variable_offset.at(from_var_header.name);
     371      120406 :   stream.seekg(_loaded_stream_data_begin + offset);
     372             : 
     373             :   // Non-SCALAR variable
     374      120406 :   if (to_var.type().family != SCALAR)
     375             :   {
     376    27581028 :     for (const auto & obj : _loaded_ordered_objects)
     377    41693776 :       for (const auto comp : make_range(obj->n_comp(to_sys.number(), to_var.number())))
     378             :       {
     379             :         Real val;
     380    14232453 :         dataLoad(stream, val, nullptr);
     381    14232453 :         to_vec.set(obj->dof_number(to_sys.number(), to_var.number(), comp), val);
     382             :       }
     383             :   }
     384             :   // SCALAR variable on the last rank
     385         701 :   else if (_es.processor_id() == _es.n_processors() - 1)
     386             :   {
     387         698 :     const auto & dof_map = to_sys.get_dof_map();
     388         698 :     std::vector<dof_id_type> scalar_dofs;
     389         698 :     dof_map.SCALAR_dof_indices(scalar_dofs, to_var.number());
     390        1639 :     for (const auto dof : scalar_dofs)
     391             :     {
     392             :       Real val;
     393         941 :       dataLoad(stream, val, nullptr);
     394         941 :       to_vec.set(dof, val);
     395             :     }
     396         698 :   }
     397             : 
     398             :   // insert into the member variable
     399             :   std::tuple<std::string, std::string, std::string> _loaded_variable = {
     400      120406 :       from_sys_header.name, from_vec_header.name, from_var_header.name};
     401             : 
     402      120406 :   _loaded_variables.insert(_loaded_variable);
     403             : 
     404             :   mooseAssert(isVariableRestored(from_sys_header.name, from_vec_header.name, from_var_header.name),
     405             :               "Variable not marked as restored");
     406      120406 : }
     407             : 
     408             : void
     409       45777 : dataStore(std::ostream & stream, RestartableEquationSystems & res, void *)
     410             : {
     411       45777 :   res.store(stream);
     412       45777 : }
     413             : 
     414             : void
     415       14538 : dataLoad(std::istream & stream, RestartableEquationSystems & res, void *)
     416             : {
     417       14538 :   res.load(stream);
     418       14538 : }
     419             : 
     420             : void
     421       45777 : dataStore(std::ostream & stream, RestartableEquationSystems::EquationSystemsHeader & header, void *)
     422             : {
     423       45777 :   dataStore(stream, header.systems, nullptr);
     424       45777 :   dataStore(stream, header.data_size, nullptr);
     425       45777 : }
     426             : 
     427             : void
     428       14538 : dataLoad(std::istream & stream, RestartableEquationSystems::EquationSystemsHeader & header, void *)
     429             : {
     430       14538 :   dataLoad(stream, header.systems, nullptr);
     431       14538 :   dataLoad(stream, header.data_size, nullptr);
     432       14538 : }
     433             : 
     434             : void
     435       92597 : dataStore(std::ostream & stream, RestartableEquationSystems::SystemHeader & header, void *)
     436             : {
     437       92597 :   dataStore(stream, header.name, nullptr);
     438       92597 :   dataStore(stream, header.type, nullptr);
     439       92597 :   dataStore(stream, header.variables, nullptr);
     440       92597 :   dataStore(stream, header.vectors, nullptr);
     441       92597 : }
     442             : 
     443             : void
     444       29212 : dataLoad(std::istream & stream, RestartableEquationSystems::SystemHeader & header, void *)
     445             : {
     446       29212 :   dataLoad(stream, header.name, nullptr);
     447       29212 :   dataLoad(stream, header.type, nullptr);
     448       29212 :   dataLoad(stream, header.variables, nullptr);
     449       29212 :   dataLoad(stream, header.vectors, nullptr);
     450       29212 : }
     451             : 
     452             : void
     453       92258 : dataStore(std::ostream & stream, RestartableEquationSystems::VariableHeader & header, void *)
     454             : {
     455       92258 :   dataStore(stream, header.name, nullptr);
     456       92258 :   dataStore(stream, header.type, nullptr);
     457       92258 : }
     458             : void
     459       29544 : dataLoad(std::istream & stream, RestartableEquationSystems::VariableHeader & header, void *)
     460             : {
     461       29544 :   dataLoad(stream, header.name, nullptr);
     462       29544 :   dataLoad(stream, header.type, nullptr);
     463       29544 : }
     464             : 
     465             : void
     466      435235 : dataStore(std::ostream & stream, RestartableEquationSystems::VectorHeader & header, void *)
     467             : {
     468      435235 :   dataStore(stream, header.name, nullptr);
     469      435235 :   dataStore(stream, header.projections, nullptr);
     470      435235 :   dataStore(stream, header.type, nullptr);
     471      435235 :   dataStore(stream, header.variable_offset, nullptr);
     472      435235 : }
     473             : void
     474      122498 : dataLoad(std::istream & stream, RestartableEquationSystems::VectorHeader & header, void *)
     475             : {
     476      122498 :   dataLoad(stream, header.name, nullptr);
     477      122498 :   dataLoad(stream, header.projections, nullptr);
     478      122498 :   dataLoad(stream, header.type, nullptr);
     479      122498 :   dataLoad(stream, header.variable_offset, nullptr);
     480      122498 : }
     481             : 
     482             : void
     483          24 : to_json(nlohmann::json & json, const RestartableEquationSystems & res)
     484             : {
     485             : 
     486          24 :   nlohmann::json loaded_vars = nlohmann::json::array();
     487             : 
     488         240 :   for (const auto & [system, vector, variable] : res.getLoadedVariables())
     489             :   {
     490        2160 :     loaded_vars.push_back({{"system", system}, {"vector", vector}, {"variable", variable}});
     491             :   }
     492             : 
     493          24 :   json["loaded_variables"] = loaded_vars;
     494        1752 : }

Generated by: LCOV version 1.14