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