www.mooseframework.org
RestartableDataIO.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 // MOOSE includes
11 #include "RestartableDataIO.h"
12 
13 #include "AuxiliarySystem.h"
14 #include "FEProblem.h"
15 #include "MooseApp.h"
16 #include "MooseUtils.h"
17 #include "NonlinearSystem.h"
18 
19 #include <stdio.h>
20 #include <fstream>
21 
22 RestartableDataIO::RestartableDataIO(FEProblemBase & fe_problem) : _fe_problem(fe_problem)
23 {
24  _in_file_handles.resize(libMesh::n_threads());
25 }
26 
27 void
28 RestartableDataIO::writeRestartableData(std::string base_file_name,
29  const RestartableDatas & restartable_datas,
30  std::set<std::string> & /*_recoverable_data*/)
31 {
32  unsigned int n_threads = libMesh::n_threads();
33  processor_id_type proc_id = _fe_problem.processor_id();
34 
35  for (unsigned int tid = 0; tid < n_threads; tid++)
36  {
37  std::ofstream out;
38 
39  std::ostringstream file_name_stream;
40  file_name_stream << base_file_name;
41 
42  file_name_stream << "-" << proc_id;
43 
44  if (n_threads > 1)
45  file_name_stream << "-" << tid;
46 
47  std::string file_name = file_name_stream.str();
48  out.open(file_name.c_str(), std::ios::out | std::ios::binary);
49  if (out.fail())
50  mooseError("Unable to open file ", file_name);
51 
52  serializeRestartableData(restartable_datas[tid], out);
53 
54  out.close();
55  }
56 }
57 
58 void
60  const std::map<std::string, std::unique_ptr<RestartableDataValue>> & restartable_data,
61  std::ostream & stream)
62 {
63  unsigned int n_threads = libMesh::n_threads();
64  processor_id_type n_procs = _fe_problem.n_processors();
65 
66  const unsigned int file_version = 2;
67 
68  { // Write out header
69  char id[] = {'R', 'D'};
70 
71  stream.write(id, 2);
72  stream.write((const char *)&file_version, sizeof(file_version));
73 
74  stream.write((const char *)&n_procs, sizeof(n_procs));
75  stream.write((const char *)&n_threads, sizeof(n_threads));
76 
77  // number of RestartableData
78  unsigned int n_data = restartable_data.size();
79  stream.write((const char *)&n_data, sizeof(n_data));
80 
81  // data names
82  for (const auto & it : restartable_data)
83  {
84  std::string name = it.first;
85  stream.write(name.c_str(), name.length() + 1); // trailing 0!
86  }
87  }
88  {
89  std::ostringstream data_blk;
90 
91  for (const auto & it : restartable_data)
92  {
93  std::ostringstream data;
94  it.second->store(data);
95 
96  // Store the size of the data then the data
97  unsigned int data_size = static_cast<unsigned int>(data.tellp());
98  data_blk.write((const char *)&data_size, sizeof(data_size));
99  data_blk << data.str();
100  }
101 
102  // Write out this proc's block size
103  unsigned int data_blk_size = static_cast<unsigned int>(data_blk.tellp());
104  stream.write((const char *)&data_blk_size, sizeof(data_blk_size));
105 
106  // Write out the values
107  stream << data_blk.str();
108  }
109 }
110 
111 void
113  const std::map<std::string, std::unique_ptr<RestartableDataValue>> & restartable_data,
114  std::istream & stream,
115  const std::set<std::string> & recoverable_data)
116 {
117  bool recovering = _fe_problem.getMooseApp().isRecovering();
118 
119  std::vector<std::string> ignored_data;
120 
121  // number of data
122  unsigned int n_data = 0;
123  stream.read((char *)&n_data, sizeof(n_data));
124 
125  // data names
126  std::vector<std::string> data_names(n_data);
127 
128  for (unsigned int i = 0; i < n_data; i++)
129  {
130  std::string data_name;
131  char ch = 0;
132  do
133  {
134  stream.read(&ch, 1);
135  if (ch != '\0')
136  data_name += ch;
137  } while (ch != '\0');
138  data_names[i] = data_name;
139  }
140 
141  // Grab this processor's block size
142  unsigned int data_blk_size = 0;
143  stream.read((char *)&data_blk_size, sizeof(data_blk_size));
144 
145  for (unsigned int i = 0; i < n_data; i++)
146  {
147  std::string current_name = data_names[i];
148 
149  unsigned int data_size = 0;
150  stream.read((char *)&data_size, sizeof(data_size));
151 
152  // Determine if the current data is recoverable
153  bool is_data_restartable = restartable_data.find(current_name) != restartable_data.end();
154  bool is_data_recoverable = recoverable_data.find(current_name) != recoverable_data.end();
155  if (is_data_restartable // Only restore values if they're currently being used
156  &&
157  (recovering || !is_data_recoverable)) // Only read this value if we're either recovering or
158  // this hasn't been specified to be recovery only data
159 
160  {
161  // Moose::out<<"Loading "<<current_name<<std::endl;
162 
163  try
164  {
165  auto & current_data = restartable_data.at(current_name);
166  current_data->load(stream);
167  }
168  catch (...)
169  {
170  mooseError("restartable_data missing ", current_name, "\n");
171  }
172  }
173  else
174  {
175  // Skip this piece of data and do not report if restarting and recoverable data is not used
176  stream.seekg(data_size, std::ios_base::cur);
177  if (recovering && !is_data_recoverable)
178  ignored_data.push_back(current_name);
179  }
180  }
181 
182  // Produce a warning if restarting and restart data is being skipped
183  // Do not produce the warning with recovery b/c in cases the parent defines a something as
184  // recoverable,
185  // but only certain child classes use the value in recovery (i.e., FileOutput::_num_files is
186  // needed by Exodus but not Checkpoint)
187  if (ignored_data.size() && !recovering)
188  {
189  std::ostringstream names;
190  for (unsigned int i = 0; i < ignored_data.size(); i++)
191  names << ignored_data[i] << "\n";
192  mooseWarning("The following RestartableData was found in restart file but is being ignored:\n",
193  names.str());
194  }
195 }
196 
197 void
199 {
200  storeHelper(stream, static_cast<SystemBase &>(_fe_problem.getNonlinearSystemBase()), nullptr);
201  storeHelper(stream, static_cast<SystemBase &>(_fe_problem.getAuxiliarySystem()), nullptr);
202 }
203 
204 void
206 {
207  loadHelper(stream, static_cast<SystemBase &>(_fe_problem.getNonlinearSystemBase()), nullptr);
208  loadHelper(stream, static_cast<SystemBase &>(_fe_problem.getAuxiliarySystem()), nullptr);
209 }
210 
211 void
213 {
214  unsigned int n_threads = libMesh::n_threads();
215  processor_id_type n_procs = _fe_problem.n_processors();
216  processor_id_type proc_id = _fe_problem.processor_id();
217 
218  for (unsigned int tid = 0; tid < n_threads; tid++)
219  {
220  std::ostringstream file_name_stream;
221  file_name_stream << base_file_name;
222  file_name_stream << "-" << proc_id;
223 
224  if (n_threads > 1)
225  file_name_stream << "-" << tid;
226 
227  std::string file_name = file_name_stream.str();
228 
230 
231  const unsigned int file_version = 2;
232 
233  _in_file_handles[tid] =
234  std::make_shared<std::ifstream>(file_name.c_str(), std::ios::in | std::ios::binary);
235 
236  // header
237  char id[2];
238  _in_file_handles[tid]->read(id, 2);
239 
240  unsigned int this_file_version;
241  _in_file_handles[tid]->read((char *)&this_file_version, sizeof(this_file_version));
242 
243  processor_id_type this_n_procs = 0;
244  unsigned int this_n_threads = 0;
245 
246  _in_file_handles[tid]->read((char *)&this_n_procs, sizeof(this_n_procs));
247  _in_file_handles[tid]->read((char *)&this_n_threads, sizeof(this_n_threads));
248 
249  // check the header
250  if (id[0] != 'R' || id[1] != 'D')
251  mooseError("Corrupted restartable data file!");
252 
253  // check the file version
254  if (this_file_version > file_version)
255  mooseError("Trying to restart from a newer file version - you need to update MOOSE");
256 
257  if (this_file_version < file_version)
258  mooseError("Trying to restart from an older file version - you need to checkout an older "
259  "version of MOOSE.");
260 
261  if (this_n_procs != n_procs)
262  mooseError("Cannot restart using a different number of processors!");
263 
264  if (this_n_threads != n_threads)
265  mooseError("Cannot restart using a different number of threads!");
266  }
267 }
268 
269 void
271  const std::set<std::string> & recoverable_data)
272 {
273  unsigned int n_threads = libMesh::n_threads();
274  std::vector<std::string> ignored_data;
275 
276  for (unsigned int tid = 0; tid < n_threads; tid++)
277  {
278  const auto & restartable_data = restartable_datas[tid];
279 
280  if (!_in_file_handles[tid].get() || !_in_file_handles[tid]->is_open())
281  mooseError("In RestartableDataIO: Need to call readRestartableDataHeader() before calling "
282  "readRestartableData()");
283 
284  deserializeRestartableData(restartable_data, *_in_file_handles[tid], recoverable_data);
285 
286  _in_file_handles[tid]->close();
287  }
288 }
289 
290 std::shared_ptr<Backup>
292 {
293  std::shared_ptr<Backup> backup = std::make_shared<Backup>();
294 
295  serializeSystems(backup->_system_data);
296 
297  const RestartableDatas & restartable_datas = _fe_problem.getMooseApp().getRestartableData();
298 
299  unsigned int n_threads = libMesh::n_threads();
300 
301  backup->_restartable_data.resize(n_threads);
302 
303  for (unsigned int tid = 0; tid < n_threads; tid++)
304  serializeRestartableData(restartable_datas[tid], *backup->_restartable_data[tid]);
305 
306  return backup;
307 }
308 
309 void
310 RestartableDataIO::restoreBackup(std::shared_ptr<Backup> backup, bool for_restart)
311 {
312  unsigned int n_threads = libMesh::n_threads();
313 
314  // Make sure we read from the beginning
315  backup->_system_data.seekg(0);
316  for (unsigned int tid = 0; tid < n_threads; tid++)
317  backup->_restartable_data[tid]->seekg(0);
318 
319  deserializeSystems(backup->_system_data);
320 
321  const RestartableDatas & restartable_datas = _fe_problem.getMooseApp().getRestartableData();
322 
323  for (unsigned int tid = 0; tid < n_threads; tid++)
324  {
325  // header
326  char id[2];
327  backup->_restartable_data[tid]->read(id, 2);
328 
329  unsigned int this_file_version;
330  backup->_restartable_data[tid]->read((char *)&this_file_version, sizeof(this_file_version));
331 
332  processor_id_type this_n_procs = 0;
333  unsigned int this_n_threads = 0;
334 
335  backup->_restartable_data[tid]->read((char *)&this_n_procs, sizeof(this_n_procs));
336  backup->_restartable_data[tid]->read((char *)&this_n_threads, sizeof(this_n_threads));
337 
338  std::set<std::string> & recoverable_data = _fe_problem.getMooseApp().getRecoverableData();
339 
340  if (for_restart) // When doing restart - make sure we don't read data that is only for
341  // recovery...
343  restartable_datas[tid], *backup->_restartable_data[tid], recoverable_data);
344  else
346  restartable_datas[tid], *backup->_restartable_data[tid], std::set<std::string>());
347  }
348 }
std::vector< std::shared_ptr< std::ifstream > > _in_file_handles
A vector of file handles, one per thread.
std::vector< std::map< std::string, std::unique_ptr< RestartableDataValue > >> RestartableDatas
Container for storing material properties.
NonlinearSystemBase & getNonlinearSystemBase()
void serializeSystems(std::ostream &stream)
Serializes the data for the Systems in FEProblemBase.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:207
void writeRestartableData(std::string base_file_name, const RestartableDatas &restartable_datas, std::set< std::string > &_recoverable_data)
Write out the restartable data.
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition: MooseError.h:219
FEProblemBase & _fe_problem
Reference to a FEProblemBase being restarted.
RestartableDataIO(FEProblemBase &fe_problem)
std::set< std::string > & getRecoverableData()
Return a reference to the recoverable data object.
Definition: MooseApp.h:487
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
void storeHelper(std::ostream &stream, P &data, void *context)
Scalar helper routine.
Definition: DataIO.h:677
void serializeRestartableData(const std::map< std::string, std::unique_ptr< RestartableDataValue >> &restartable_data, std::ostream &stream)
Serializes the data into the stream object.
bool checkFileReadable(const std::string &filename, bool check_line_endings=false, bool throw_on_unreadable=true)
Checks to see if a file is readable (exists and permissions)
Definition: MooseUtils.C:146
void readRestartableDataHeader(std::string base_file_name)
Read restartable data header to verify that we are restarting on the correct number of processors and...
AuxiliarySystem & getAuxiliarySystem()
void deserializeRestartableData(const std::map< std::string, std::unique_ptr< RestartableDataValue >> &restartable_data, std::istream &stream, const std::set< std::string > &recoverable_data)
Deserializes the data from the stream object.
const RestartableDatas & getRestartableData()
Return reference to the restatable data object.
Definition: MooseApp.h:481
void readRestartableData(const RestartableDatas &restartable_datas, const std::set< std::string > &_recoverable_data)
Read the restartable data.
MooseApp & getMooseApp() const
Get the MooseApp this object is associated with.
Definition: MooseObject.h:94
std::shared_ptr< Backup > createBackup()
Create a Backup for the current system.
bool isRecovering() const
Whether or not this is a "recover" calculation.
Definition: MooseApp.C:859
void loadHelper(std::istream &stream, P &data, void *context)
Scalar helper routine.
Definition: DataIO.h:741
void restoreBackup(std::shared_ptr< Backup > backup, bool for_restart=false)
Restore a Backup for the current system.
void deserializeSystems(std::istream &stream)
Deserializes the data for the Systems in FEProblemBase.