libMesh
Loading...
Searching...
No Matches
equation_systems_io.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19#include "libmesh/libmesh_common.h"
20#include "libmesh/libmesh_logging.h"
21
22
23// Local Includes
24#include "libmesh/libmesh_version.h"
25#include "libmesh/equation_systems.h"
26#include "libmesh/mesh_base.h"
27#include "libmesh/mesh_refinement.h"
28#include "libmesh/mesh_tools.h"
29#include "libmesh/parallel.h"
30#include "libmesh/utility.h"
31#include "libmesh/xdr_cxx.h"
32
33// C++ Includes
34#include <iomanip> // setfill
35#include <sstream>
36#include <string>
37
38namespace libMesh
39{
40
41// Forward Declarations
42
43// Anonymous namespace for implementation details.
44namespace {
45std::string local_file_name (const unsigned int processor_id,
46 std::string_view basename)
47{
48 std::ostringstream returnval;
49
50 std::string_view suffix;
51 if (Utility::ends_with(basename, ".bz2"))
52 {
53 basename.remove_suffix(4);
54 suffix = ".bz2";
55 }
56 else if (Utility::ends_with(basename, ".gz"))
57 {
58 basename.remove_suffix(3);
59 suffix = ".gz";
60 }
61
62 returnval << basename << '.';
63 returnval << std::setfill('0') << std::setw(4);
64 returnval << processor_id;
65 returnval << suffix;
66
67 return returnval.str();
68}
69}
70
71
72
73
74// ------------------------------------------------------------
75// EquationSystem class implementation
76template <typename InValType>
77void EquationSystems::read (std::string_view name,
78 const unsigned int read_flags,
79 bool partition_agnostic)
80{
81 XdrMODE mode = READ;
82 if (name.find(".xdr") != std::string::npos)
83 mode = DECODE;
84 this->read(name, mode, read_flags, partition_agnostic);
85}
86
87
88
89template <typename InValType>
90void EquationSystems::read (std::string_view name,
91 const XdrMODE mode,
92 const unsigned int read_flags,
93 bool partition_agnostic)
94{
95 // This will unzip a file with .bz2 as the extension, otherwise it
96 // simply returns the name if the file need not be unzipped.
97 Xdr io ((this->processor_id() == 0) ? std::string(name) : "", mode);
98
99 std::function<std::unique_ptr<Xdr>()> local_io_functor;
100 local_io_functor = [this,&name,&mode]() {
101 return std::make_unique<Xdr>(local_file_name(this->processor_id(), name), mode); };
102
103 this->read(io, local_io_functor, read_flags, partition_agnostic);
104}
105
106
107
108template <typename InValType>
110 std::function<std::unique_ptr<Xdr>()> & local_io_functor,
111 const unsigned int read_flags,
112 bool partition_agnostic)
113{
177 // Set booleans from the read_flags argument
178 const bool read_header = read_flags & EquationSystems::READ_HEADER;
179 const bool read_data = read_flags & EquationSystems::READ_DATA;
180 const bool read_additional_data = read_flags & EquationSystems::READ_ADDITIONAL_DATA;
181 const bool read_legacy_format = read_flags & EquationSystems::READ_LEGACY_FORMAT;
182 const bool try_read_ifems = read_flags & EquationSystems::TRY_READ_IFEMS;
183 const bool read_basic_only = read_flags & EquationSystems::READ_BASIC_ONLY;
184 bool read_parallel_files = false;
185
186 std::vector<std::pair<std::string, System *>> xda_systems;
187
188 libmesh_assert (io.reading());
189
190 {
191 // 1.)
192 // Read the version header.
193 std::string version = "legacy";
194 if (!read_legacy_format)
195 {
196 if (this->processor_id() == 0) io.data(version);
197 this->comm().broadcast(version);
198
199 // All processors have the version header, if it does not contain
200 // the libMesh_label string then it is a legacy file.
201 const std::string libMesh_label = "libMesh-";
202 std::string::size_type lm_pos = version.find(libMesh_label);
203 if (lm_pos==std::string::npos)
204 {
205 io.close();
206
207 // Recursively call this read() function but with the
208 // EquationSystems::READ_LEGACY_FORMAT bit set.
209 this->read (io, local_io_functor, (read_flags | EquationSystems::READ_LEGACY_FORMAT), partition_agnostic);
210 return;
211 }
212
213 // Figure out the libMesh version that created this file
214 std::istringstream iss(version.substr(lm_pos + libMesh_label.size()));
215 int ver_major = 0, ver_minor = 0, ver_patch = 0;
216 char dot;
217 iss >> ver_major >> dot >> ver_minor >> dot >> ver_patch;
218 io.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch));
219
220
221 read_parallel_files = Utility::contains(version, " parallel");
222
223 // If requested that we try to read infinite element information,
224 // and the string " with infinite elements" is not in the version,
225 // then tack it on. This is for compatibility reading ifem
226 // files written prior to 11/10/2008 - BSK
227 if (try_read_ifems)
228 if (!Utility::contains(version, " with infinite elements"))
229 version += " with infinite elements";
230
231 }
232 else
233 libmesh_deprecated();
234
235 LOG_SCOPE("read()", "EquationSystems");
236
237 // 2.)
238 // Read the number of systems
239 unsigned int n_sys=0;
240 if (this->processor_id() == 0) io.data (n_sys);
241 this->comm().broadcast(n_sys);
242
243 for (unsigned int sys=0; sys<n_sys; sys++)
244 {
245 // 3.)
246 // Read the name of the sys-th equation system
247 std::string sys_name;
248 if (this->processor_id() == 0) io.data (sys_name);
249 this->comm().broadcast(sys_name);
250
251 // 4.)
252 // Read the type of the sys-th equation system
253 std::string sys_type;
254 if (this->processor_id() == 0) io.data (sys_type);
255 this->comm().broadcast(sys_type);
256
257 if (read_header)
258 this->add_system (sys_type, sys_name);
259
260 // 5.) - 9.)
261 // Let System::read_header() do the job
262 System & new_system = this->get_system(sys_name);
263 new_system.read_header (io,
264 version,
265 read_header,
266 read_additional_data,
267 read_legacy_format);
268
269 xda_systems.emplace_back(sys_name, &new_system);
270
271 // If we're only creating "basic" systems, we need to tell
272 // each system that before we call init() later.
273 if (read_basic_only)
274 new_system.set_basic_system_only();
275 }
276 }
277
278
279
280 // Now we are ready to initialize the underlying data
281 // structures. This will initialize the vectors for
282 // storage, the dof_map, etc...
283 if (read_header)
284 this->init();
285
286 // 10.) & 11.)
287 // Read and set the numeric vector values
288 if (read_data)
289 {
290 std::unique_ptr<Xdr> local_io;
291
292 // the EquationSystems::read() method should look constant from the mesh
293 // perspective, but we need to assign a temporary numbering to the nodes
294 // and elements in the mesh, which requires that we abuse const_cast
295 if (!read_legacy_format && partition_agnostic)
296 {
297 MeshBase & mesh = const_cast<MeshBase &>(this->get_mesh());
299 }
300
301 for (auto & pr : xda_systems)
302 {
303 libmesh_error_msg_if(read_legacy_format,
304 "Reading legacy format XDR files is officially no longer supported.");
305
306 if (read_parallel_files)
307 {
308 if (!local_io)
309 {
310 local_io = local_io_functor();
311 libmesh_assert(local_io->reading());
312 }
313 pr.second->read_parallel_data<InValType> (*local_io, read_additional_data);
314 }
315 else
316 pr.second->read_serialized_data<InValType> (io, read_additional_data);
317 }
318
319 // Undo the temporary numbering.
320 if (!read_legacy_format && partition_agnostic)
322 }
323
324 // Localize each system's data
325 this->update();
326
327 #ifdef LIBMESH_ENABLE_AMR
328 MeshRefinement mesh_refine(_mesh);
329 mesh_refine.clean_refinement_flags();
330 #endif
331}
332
333
334
335void EquationSystems::write(std::string_view name,
336 const unsigned int write_flags,
337 bool partition_agnostic) const
338{
339 XdrMODE mode = WRITE;
340 if (name.find(".xdr") != std::string::npos)
341 mode = ENCODE;
342 this->write(name, mode, write_flags, partition_agnostic);
343}
344
345
346
347void EquationSystems::write(std::string_view name,
348 const XdrMODE mode,
349 const unsigned int write_flags,
350 bool partition_agnostic) const
351{
352 Xdr io((this->processor_id()==0) ? std::string(name) : "", mode);
353
354 std::unique_ptr<Xdr> local_io;
355 // open a parallel buffer if warranted
357 local_io = std::make_unique<Xdr>(local_file_name(this->processor_id(),name), mode);
358
359 this->write(io, write_flags, partition_agnostic, local_io.get());
360}
361
362
363
365 const unsigned int write_flags,
366 bool partition_agnostic,
367 Xdr * const local_io) const
368{
432 // the EquationSystems::write() method should look constant,
433 // but we need to assign a temporary numbering to the nodes
434 // and elements in the mesh, which requires that we abuse const_cast
435 if (partition_agnostic)
436 {
437 MeshBase & mesh = const_cast<MeshBase &>(this->get_mesh());
439 }
440
441 // set booleans from write_flags argument
442 const bool write_data = write_flags & EquationSystems::WRITE_DATA;
443 const bool write_additional_data = write_flags & EquationSystems::WRITE_ADDITIONAL_DATA;
444
445 // always write parallel files if we're instructed to write in
446 // parallel
447 const bool write_parallel_files =
449 // Even if we're on a distributed mesh, we may or may not have a
450 // consistent way of reconstructing the same mesh partitioning
451 // later, but we need the same mesh partitioning if we want to
452 // reread the parallel solution safely, so let's write a serial file
453 // unless specifically requested not to.
454 // ||
455 // // but also write parallel files if we haven't been instructed to
456 // // write in serial and we're on a distributed mesh
457 // (!(write_flags & EquationSystems::WRITE_SERIAL_FILES) &&
458 // !this->get_mesh().is_serial())
459 ;
460
461 if (write_parallel_files && write_data)
462 libmesh_assert(local_io);
463
464 {
465 libmesh_assert (io.writing());
466
467 LOG_SCOPE("write()", "EquationSystems");
468
469 const unsigned int proc_id = this->processor_id();
470
471 unsigned int n_sys = 0;
472 for (auto & pr : _systems)
473 if (!pr.second->hide_output())
474 n_sys++;
475
476 // set the version number in the Xdr object
477 io.set_version(LIBMESH_VERSION_ID(LIBMESH_MAJOR_VERSION,
478 LIBMESH_MINOR_VERSION,
479 LIBMESH_MICRO_VERSION));
480
481 // Only write the header information
482 // if we are processor 0.
483 if (proc_id == 0)
484 {
485 std::string comment;
486
487 // 1.)
488 // Write the version header
489 std::string version("libMesh-" + libMesh::get_io_compatibility_version());
490 if (write_parallel_files) version += " parallel";
491
492#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
493 version += " with infinite elements";
494#endif
495 io.data (version, "# File Format Identifier");
496
497 // 2.)
498 // Write the number of equation systems
499 io.data (n_sys, "# No. of Equation Systems");
500
501 for (auto & [sys_name, sys] : _systems)
502 {
503 // Ignore this system if it has been marked as hidden
504 if (sys->hide_output()) continue;
505
506 // 3.)
507 // Write the name of the sys_num-th system
508 {
509 const unsigned int sys_num = sys->number();
510
511 comment = "# Name, System No. ";
512 comment += std::to_string(sys_num);
513
514 // Note: There is no Xdr::data overload taking a "const
515 // std::string &" so we need to make a copy.
516 std::string copy = sys_name;
517 io.data (copy, comment);
518 }
519
520 // 4.)
521 // Write the type of system handled
522 {
523 const unsigned int sys_num = sys->number();
524 std::string sys_type = sys->system_type();
525
526 comment = "# Type, System No. ";
527 comment += std::to_string(sys_num);
528
529 io.data (sys_type, comment);
530 }
531
532 // 5.) - 9.)
533 // Let System::write_header() do the job
534 sys->write_header (io, version, write_additional_data);
535 }
536 }
537
538 // Start from the first system, again,
539 // to write vectors to disk, if wanted
540 if (write_data)
541 {
542 for (auto & pr : _systems)
543 {
544 // Ignore this system if it has been marked as hidden
545 if (pr.second->hide_output()) continue;
546
547 // 10.) + 11.)
548 if (write_parallel_files)
549 pr.second->write_parallel_data (*local_io,write_additional_data);
550 else
551 pr.second->write_serialized_data (io,write_additional_data);
552 }
553
554 if (local_io)
555 local_io->close();
556 }
557
558 io.close();
559 }
560
561 // the EquationSystems::write() method should look constant,
562 // but we need to undo the temporary numbering of the nodes
563 // and elements in the mesh, which requires that we abuse const_cast
564 if (partition_agnostic)
565 const_cast<MeshBase &>(_mesh).fix_broken_node_and_element_numbering();
566}
567
568
569
570// template specialization
571
572template LIBMESH_EXPORT void EquationSystems::read<Number> (Xdr & io, std::function<std::unique_ptr<Xdr>()> & local_io_functor, const unsigned int read_flags, bool partition_agnostic);
573template LIBMESH_EXPORT void EquationSystems::read<Number> (std::string_view name, const unsigned int read_flags, bool partition_agnostic);
574template LIBMESH_EXPORT void EquationSystems::read<Number> (std::string_view name, const XdrMODE mode, const unsigned int read_flags, bool partition_agnostic);
575#ifdef LIBMESH_USE_COMPLEX_NUMBERS
576template LIBMESH_EXPORT void EquationSystems::read<Real> (Xdr & io, std::function<std::unique_ptr<Xdr>()> & local_io_functor, const unsigned int read_flags, bool partition_agnostic);
577template LIBMESH_EXPORT void EquationSystems::read<Real> (std::string_view name, const unsigned int read_flags, bool partition_agnostic);
578template LIBMESH_EXPORT void EquationSystems::read<Real> (std::string_view name, const XdrMODE mode, const unsigned int read_flags, bool partition_agnostic);
579#endif
580
581} // namespace libMesh
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
void update()
Updates local values for all the systems.
void write(std::string_view name, const XdrMODE, const unsigned int write_flags=(WRITE_DATA), bool partition_agnostic=true) const
Write the systems to disk using the XDR data format.
void read(std::string_view name, const XdrMODE, const unsigned int read_flags=(READ_HEADER|READ_DATA), bool partition_agnostic=true)
Read & initialize the systems from disk using the XDR data format.
const MeshBase & get_mesh() const
MeshBase & _mesh
The mesh data structure.
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
const T_sys & get_system(std::string_view name) const
std::map< std::string, std::unique_ptr< System >, std::less<> > _systems
Data structure holding the systems.
This is the MeshBase class.
Definition mesh_base.h:81
virtual void fix_broken_node_and_element_numbering()=0
There is no reason for a user to ever call this function.
Implements (adaptive) mesh refinement algorithms for a MeshBase.
void clean_refinement_flags()
Sets the refinement flag to Elem::DO_NOTHING for each element in the mesh.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
void set_basic_system_only()
Sets the system to be "basic only": i.e.
Definition system.h:2465
void read_header(Xdr &io, std::string_view version, const bool read_header=true, const bool read_additional_data=true, const bool read_legacy_format=false)
Reads the basic data header for this System.
Definition system_io.C:97
This class implements a C++ interface to the XDR (eXternal Data Representation) format.
Definition xdr_cxx.h:68
bool writing() const
Definition xdr_cxx.h:129
void set_version(int ver)
Sets the version of the file that is being read.
Definition xdr_cxx.h:171
bool reading() const
Definition xdr_cxx.h:123
void close()
Closes the file if it is open.
Definition xdr_cxx.C:278
void data(T &a, std::string_view comment="")
Inputs or outputs a single value.
Definition xdr_cxx.C:860
MeshBase & mesh
void globally_renumber_nodes_and_elements(MeshBase &)
There is no reason for a user to ever call this function.
bool contains(std::string_view superstring, std::string_view substring)
Look for a substring within a string.
Definition utility.C:205
bool ends_with(std::string_view superstring, std::string_view suffix)
Look for a substring at the very end of a string.
Definition utility.C:213
The libMesh namespace provides an interface to certain functionality in the library.
std::string get_io_compatibility_version()
Specifier for I/O file compatibility features.
libmesh_assert(ctx)
XdrMODE
Defines an enum for read/write mode in Xdr format.