OpenMPCD
main.cpp
7 
8 #include <boost/chrono.hpp>
9 #include <boost/filesystem.hpp>
10 #include <boost/program_options.hpp>
11 
12 #include <ctime>
13 #include <fstream>
14 #include <signal.h>
15 #include <sstream>
16 #include <sys/stat.h>
17 
18 using namespace OpenMPCD;
19 
20 static const char* const defaultConfigPath="./config.txt";
21 
22 
23 static const std::string getCurrentDateTimeString()
24 {
25  char datetimeString[512];
26  const time_t datetime=std::time(0);
27  struct tm* datetimeTM=localtime(&datetime);
28  if(datetimeTM==NULL)
29  OPENMPCD_THROW(Exception, "Failed to get current datetime.");
30 
31  if(strftime(datetimeString, sizeof(datetimeString), "%F_%T", datetimeTM)==0)
32  OPENMPCD_THROW(Exception, "Failed to format current datetime.");
33 
34  return datetimeString;
35 }
36 
37 static void createRundir(
38  std::string* const rundir_ptr, std::string* const configPath_ptr)
39 {
40  std::string& rundir=*rundir_ptr;
41 
42  if(rundir.empty())
43  {
44  rundir="runs/";
45  rundir+=getCurrentDateTimeString();
46  }
47 
48  if(boost::filesystem::exists(rundir))
49  {
50  typedef boost::filesystem::directory_iterator DI;
51  for(DI it(rundir); it != DI(); ++it)
52  {
53  if(it->path().filename() == "config.txt")
54  {
55  *configPath_ptr = it->path().string();
56  }
57  else if(it->path().filename() == "input")
58  {
59  }
60  else
61  {
62  OPENMPCD_THROW(Exception, "Specified rundir is non-empty.");
63  }
64  }
65  }
66  else
67  {
68  if(!boost::filesystem::create_directory(rundir))
69  OPENMPCD_THROW(Exception, "Failed to create run directory.");
70  }
71 }
72 
73 
74 
75 static bool terminateProgram = false;
76 static bool earlySave = false;
77 
78 #ifdef OPENMPCD_PLATFORM_POSIX
79  static void signalHandler(int signum)
80  {
81  switch(signum)
82  {
83  case SIGHUP:
84  break;
85 
86  case SIGINT:
87  case SIGTERM:
88  if(terminateProgram)
89  {
90  std::cout << "Multiple termination signals caught. "
91  "Aborting execution.\n";
92  abort();
93  }
94  else
95  {
96  terminateProgram = true;
97  std::cout << "Termination signal caught. "
98  "The simulation will gracefully end after the "
99  "current sweep.\n";
100  }
101  break;
102 
103  case SIGUSR1:
104  earlySave = true;
105  std::cout<<"Triggered early save..."<<std::flush;
106  break;
107  }
108  }
109 #endif
110 
111 static void installSignalHandler()
112 {
113  #ifdef OPENMPCD_PLATFORM_POSIX
114  struct sigaction signalAction;
115 
116  signalAction.sa_handler = &signalHandler;
117  signalAction.sa_flags = 0;
118  if(sigemptyset(&signalAction.sa_mask)!=0)
119  {
121  Exception,
122  "Failed to install signal handlers (sigemptyset). Aborting.\n");
123  }
124 
125  int ret = 0;
126  ret+=sigaction(SIGHUP, &signalAction, NULL);
127  ret+=sigaction(SIGINT, &signalAction, NULL);
128  ret+=sigaction(SIGTERM, &signalAction, NULL);
129  ret+=sigaction(SIGUSR1, &signalAction, NULL);
130  if(ret!=0)
131  {
133  Exception,
134  "Failed to install signal handlers (sigaction). Aborting.\n");
135  }
136  #endif
137 }
138 
139 static unsigned int generateSeed()
140 {
141  const unsigned int seed_1 = std::time(0);
142  const unsigned int seed_2 =
143  boost::chrono::duration_cast<boost::chrono::nanoseconds>(
144  boost::chrono::high_resolution_clock::now().time_since_epoch()
145  ).count();
146 
147  return seed_1 + seed_2;
148 }
149 
150 static void run(const unsigned int maxRuntime, std::string rundir)
151 {
152  installSignalHandler();
153 
154 
155  std::string configPath = defaultConfigPath;
156  createRundir(&rundir, &configPath);
157 
158 
159  const unsigned int rngSeed = generateSeed();
160 
161  CUDA::Simulation sim(configPath, rngSeed, rundir);
162  CUDA::Instrumentation instrumentation(&sim, rngSeed, getGitCommitIdentifier());
163  instrumentation.setAutosave(rundir);
164 
165  const Configuration& config = sim.getConfiguration();
166 
167  const unsigned int sweepCount = config.read<unsigned int>("mpc.sweeps");
168 
169  const time_t startTime = std::time(0);
170 
171  sim.warmup();
172 
173  for(unsigned int i=0; i<sweepCount; ++i)
174  {
175  if(maxRuntime != 0)
176  {
177  if(std::time(0) - startTime > maxRuntime)
178  {
179  std::cout<<"Runtime limit has been reached. Terminating.\n";
180  break;
181  }
182  }
183 
184  if(terminateProgram)
185  {
186  std::cout<<"Terminating prematurely.\n";
187  break;
188  }
189 
190  if(earlySave)
191  {
192  earlySave = false;
193 
194  try
195  {
196  const std::string earlyRundir = rundir + "/EarlySave_" + getCurrentDateTimeString();
197 
198  if(!boost::filesystem::create_directory(earlyRundir))
199  OPENMPCD_THROW(IOException, "Failed to create early save directory: "+earlyRundir);
200 
201  instrumentation.save(earlyRundir);
202  std::cout<<" done\n"<<std::flush;
203  }
204  catch(const Exception& e)
205  {
206  std::cerr<<"\n\n\t*** non-fatal exception ***\n";
207  std::cerr<<"Encountered during early save:\n";
208  std::cerr<<e.getMessage();
209  std::cerr<<"\n\n";
210  }
211  }
212 
213  sim.sweep();
214  instrumentation.measure();
215 
216  if(i%100==0)
217  std::cout<<"Done with sweep "<<i<<"\n";
218  }
219 }
220 
221 int main(int argc, char** argv)
222 {
223  try
224  {
225  namespace BPO = boost::program_options;
226  namespace BPOS = BPO::command_line_style;
227 
228  unsigned int maxRuntime;
229  std::string rundir;
230 
231  BPO::options_description cmdLineDesc("Supported command line options");
232  cmdLineDesc.add_options()
233  ("help", "Print help message.")
234  ("maxRuntime", BPO::value<unsigned int>(&maxRuntime)->default_value(0),
235  "The maximum (wall-time) runtime of the program, in seconds. 0 for no limit.")
236  ("rundir", BPO::value<std::string>(&rundir),
237  "Specify the directory to save the run data in. If the "
238  "directory does not exist, it will be created. If it does "
239  "exist, it may at most contain the file `config.txt`, which "
240  "then will be used as the input configuration file, and "
241  "the directory may also contain an entry named `input`.");
242 
243  const BPO::positional_options_description positionalOptions;
244 
245  BPO::variables_map cmdLineVariables;
246  BPO::store(
247  BPO::command_line_parser(argc, argv).
248  options(cmdLineDesc).
249  positional(positionalOptions).
250  style(
251  BPOS::allow_short |
252  BPOS::allow_dash_for_short |
253  BPOS::short_allow_next |
254  BPOS::allow_long |
255  BPOS::long_allow_adjacent
256  ).
257  run(),
258  cmdLineVariables);
259  BPO::notify(cmdLineVariables);
260 
261  if(cmdLineVariables.count("help"))
262  {
263  std::cout << cmdLineDesc << "\n";
264  return 1;
265  }
266 
267 
268  if(maxRuntime != 0)
269  {
270  std::cout<<"Running for at most "<<maxRuntime<<" seconds.\n";
271  }
272  else
273  {
274  std::cout<<"No runtime bound specified.\n";
275  }
276 
277  run(maxRuntime, rundir);
278  }
279  catch(const Exception& e)
280  {
281  std::cerr<<"\n\n\t*** EXCEPTION ***\n";
282  std::cerr<<e.getMessage();
283  std::cerr<<"\n\n";
284  return 1;
285  }
286  catch(const boost::program_options::error& e)
287  {
288  std::cerr<<"\n\n\t*** EXCEPTION (boost::program_options::error) ***\n";
289  std::cerr<<e.what();
290  std::cerr<<"\n\n";
291  std::cerr<<"Try invoking this program with the `--help` option.";
292  std::cerr<<"\n\n";
293  }
294  catch(const std::exception& e)
295  {
296  std::cerr<<"\n\n\t*** EXCEPTION (std::exception) ***\n";
297  std::cerr<<e.what();
298  std::cerr<<"\n\n";
299  return 2;
300  }
301  catch(...)
302  {
303  std::cerr<<"\n\n\t*** UNKNOWN EXCEPTION ***\n";
304  return 3;
305  }
306 
307  return 0;
308 }
AnalyticQuantities.hpp
OpenMPCD::Configuration
Represents the configuration of the simulation.
Definition: Configuration.hpp:28
Exceptions.hpp
getGitCommitIdentifier.hpp
OPENMPCD_THROW
#define OPENMPCD_THROW(ExceptionType, message)
Throws the given ExceptionType, passing the given message along with file and line number information...
Definition: Exceptions.hpp:22
OpenMPCD::IOException
Error on IO.
Definition: Exceptions.hpp:160
OpenMPCD::Configuration::read
void read(const std::pair< const char *, ValueType * >(&settingsAndValues)[settingsCount]) const
Reads the specified settings from the given configuration file and stores them in the given location.
Definition: Configuration.hpp:523
OpenMPCD::Exception::getMessage
const std::string & getMessage() const
Returns the exception message.
Definition: Exceptions.hpp:52
OpenMPCD::CUDA::Simulation
MPCD simulation with Molecular Dynamics on CUDA-capable GPUs.
Definition: CUDA/Simulation.hpp:48
OpenMPCD::getGitCommitIdentifier
const std::string getGitCommitIdentifier()
Returns a string identifying the current git commit of the source code.
OpenMPCD::CUDA::Instrumentation
Class doing measurements in a CUDA simulation.
Definition: Instrumentation.hpp:26
Simulation.hpp
Instrumentation.hpp
AnalyticQuantitiesGaussianDumbbell.hpp
OpenMPCD::Exception
The base exception class for OpenMPCD.
Definition: Exceptions.hpp:37