MercuryDPM  Trunk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CombineParallelDataFiles.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <fstream>
3 #include <File.h>
4 #include <Math/Helpers.h>
5 #include "Logger.h"
6 #include "vector"
7 #include "string"
8 
12 std::string getName(int argc, char *argv[]) {
13  logger.assert_always(argc>1,"Please provide name of first data file as input argument");
14  return std::string(argv[1]);
15 }
16 
17 
18 struct IFile {
19  IFile (std::ifstream* file_, unsigned n_) : file(file_), n(n_) {}
20  std::ifstream* file;
21  unsigned n;
23 };
24 
25 class DataFiles {
26  std::vector<IFile> iFiles;
27  std::ofstream oFile;
28  unsigned oCount = 0;
29  std::string ending = "";
30 
31 public:
32 
36  DataFiles(int argc, char *argv[])
37  {
38  std::string name = getName(argc, argv);
39 
40  //check if there is an ending (the user might just specify the file root)
41  size_t dot = name.find_last_of('.');
42  // if no ending is found, assume .data0
43  if (dot==std::string::npos) {
44  name += ".data0";
45  }
46 
47  //take off ending .0000 if necessary
48  dot = name.find_last_of('.');
49  char afterDot = name[dot + 1];
50  //if last ending is a number
51  if (afterDot >= '0' && afterDot <= '9') {
52  ending = name.substr(dot);
53  name.resize(dot);
54  }
55 
56  // take off ending .data0
57  {
58  size_t dot = name.find_last_of('.');
59  name.resize(dot);
60  }
61 
62  // opens the input data files, if they exist
63  for(unsigned processorID = 0; true; ++processorID) {
64  //get input file name
65  std::string fileName = name + ".data" + std::to_string(processorID) + ending;
66  auto* file = new std::ifstream(fileName.c_str());
67  if (file->fail()) {
68  break;
69  } else {
70  iFiles.emplace_back(file,0);
71  logger(INFO,"Opened % for input",fileName);
72  }
73  }
74  logger.assert_always(!iFiles.empty(),"No input file found with name % ",name + ".data0" + ending);
75 
76  // opens output data file
77  std::string oFileName = name + ".data" + ending;
78  oFile.open(oFileName);
79  if (oFile.fail()) {
80  logger(ERROR,"% could not be opened",oFileName);
81  } else {
82  logger(INFO, "Opened % for output", oFileName);
83  }
84 
85  write();
86  }
87 
92  for (auto iFile : iFiles) {
93  delete iFile.file;
94  }
95  }
96 
100  void write() {
101  while (writeTimeStep()) {};
102  if (oCount!=1) logger(INFO,"Written % time steps",oCount);
103  }
104 
105 private:
106 
110  bool writeTimeStep() {
111  // read header line
112  static Mdouble time = 0;
113  unsigned n = 0;
114  std::string line;
115  for(auto& iFile : iFiles) {
116  // read number of particles
117  *iFile.file >> iFile.n;
118  n += iFile.n;
119  // read time stamp
120  *iFile.file >> iFile.time;
121  //stop if this was last time step
122  if (iFile.file->fail()) return false;
123  //read rest of line
124  std::getline(*iFile.file, line);
125  //check this is indeed a header line
126  static std::string headerLine = line;
127  // this is the error-catching routine:
128  // if this is not a true header line, or the timestamp is in the past, keep reading
129  if (line != headerLine || iFile.time < time) {
130  do {
131  *iFile.file >> iFile.n;
132  n += iFile.n;
133  *iFile.file >> iFile.time;
134  if (iFile.file->fail()) return false;
135  std::getline(*iFile.file, line);
136  } while (line != headerLine || iFile.time < time);
137  logger(WARN,"Mistake detected; moving forward to time %",iFile.time);
138  oCount--; //remove last-written timestep (if MULTIPLE_FILES)
139  }
140  time = iFile.time;
141  }
142  time *= 1.000000001; //so the next time step is surely bigger than the last
143 
144  //write header
145  oFile << n << ' ' << time << line << '\n';
146  logger(INFO,"Writing % %%",n,time,line);
147  // write content
148  for(auto& iFile : iFiles) {
149  for (unsigned i=0; i<iFile.n; ++i) {
150  std::getline(*iFile.file, line);
151  oFile << line << '\n';
152  }
153  }
154  ++oCount;
155  return true;
156  }
157 };
158 
159 int main (int argc, char *argv[])
160 {
161  DataFiles dataFiles(argc,argv);
162  return 0;
163 }
164 
165 /*
166  * Note: to merge muilti-file input data, use
167  for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
168  echo $i && ls -1 -t -r name.data$i.* | xargs cat > name.data$i;
169  done
170  */
std::string getName(int argc, char *argv[])
extracts the file name from the command line input
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
double Mdouble
Definition: GeneralDefine.h:34
DataFiles(int argc, char *argv[])
opens the input and output data files
const std::complex< Mdouble > i
Definition: ExtendedMath.h:50
bool writeTimeStep()
writes single timestep
std::ifstream * file
int main(int argc, char *argv[])
IFile(std::ifstream *file_, unsigned n_)
std::string to_string(const T &n)
Definition: Helpers.h:227
~DataFiles()
closes the input/output data files
void write()
write all time steps
std::vector< IFile > iFiles