1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2020 QMCPACK developers.
6 //
7 // File developed by: Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
8 // Luke Shulenburger, lshulen@sandia.gov, Sandia National Laboratories
9 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
10 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
11 // Ying Wai Li, yingwaili@ornl.gov, Oak Ridge National Laboratory
12 // Mark Dewing, markdewing@gmail.com, University of Illinois at Urbana-Champaign
13 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
14 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
15 //
16 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
17 //////////////////////////////////////////////////////////////////////////////////////
18
19 #include <stdexcept>
20
21 #include "Configuration.h"
22 #include "Message/Communicate.h"
23 #include "Utilities/SimpleParser.h"
24 #include "Utilities/ProgressReportEngine.h"
25 #include "Platforms/Host/OutputManager.h"
26 #include "OhmmsData/FileUtility.h"
27 #include "Host/sysutil.h"
28 #include "Platforms/devices.h"
29 #include "OhmmsApp/ProjectData.h"
30 #include "QMCApp/QMCMain.h"
31 #include "Utilities/qmc_common.h"
32
33 void output_hardware_info(Communicate* comm, Libxml2Document& doc, xmlNodePtr root);
34
35 /** @file qmcapp.cpp
36 *@brief a main function for QMC simulation.
37 *
38 * @ingroup qmcapp
39 * @brief main function for qmcapp executable.
40 *
41 *Actual works are done by QMCAppBase and its derived classe.
42 *For other simulations, one can derive a class from QMCApps, similarly to MolecuApps.
43 */
main(int argc,char ** argv)44 int main(int argc, char** argv)
45 {
46 using namespace qmcplusplus;
47 #ifdef HAVE_MPI
48 mpi3::environment env(argc, argv);
49 OHMMS::Controller->initialize(env);
50 #endif
51 try
52 {
53 //qmc_common and MPI is initialized
54 qmcplusplus::qmc_common.initialize(argc, argv);
55 int clones = 1;
56 #ifdef QMC_CUDA
57 bool useGPU(true);
58 #else
59 bool useGPU(false);
60 #endif
61 std::vector<std::string> fgroup1, fgroup2;
62 int i = 1;
63 while (i < argc)
64 {
65 std::string c(argv[i]);
66 if (c[0] == '-')
67 {
68 if (c.find("gpu") < c.size())
69 useGPU = true;
70 if (c.find("clones") < c.size())
71 clones = atoi(argv[++i]);
72 if (c == "-debug")
73 ReportEngine::enableOutput();
74
75 // Default setting is 'timer_level_coarse'
76 if (c.find("-enable-timers") < c.size())
77 {
78 #ifndef ENABLE_TIMERS
79 std::cerr
80 << "The '-enable-timers' command line option will have no effect. This executable was built without "
81 "ENABLE_TIMER set."
82 << std::endl;
83 #endif
84 int pos = c.find("=");
85 if (pos != std::string::npos)
86 {
87 std::string timer_level = c.substr(pos + 1);
88 timer_manager.set_timer_threshold(timer_level);
89 }
90 }
91 if (c.find("-verbosity") < c.size())
92 {
93 int pos = c.find("=");
94 if (pos != std::string::npos)
95 {
96 std::string verbose_level = c.substr(pos + 1);
97 if (verbose_level == "low")
98 {
99 outputManager.setVerbosity(Verbosity::LOW);
100 }
101 else if (verbose_level == "high")
102 {
103 outputManager.setVerbosity(Verbosity::HIGH);
104 }
105 else if (verbose_level == "debug")
106 {
107 outputManager.setVerbosity(Verbosity::DEBUG);
108 }
109 else
110 {
111 std::cerr << "Unknown verbosity level: " << verbose_level << std::endl;
112 }
113 }
114 }
115 }
116 else
117 {
118 if (c.find("xml") < c.size())
119 fgroup1.push_back(argv[i]);
120 else
121 {
122 std::ifstream fin(argv[i], std::ifstream::in);
123 bool valid = !fin.fail();
124 while (valid)
125 {
126 std::vector<std::string> words;
127 getwords(words, fin);
128 if (words.size())
129 {
130 if (words[0].find("xml") < words[0].size())
131 {
132 int nc = 1;
133 if (words.size() > 1)
134 nc = atoi(words[1].c_str());
135 while (nc)
136 {
137 fgroup2.push_back(words[0]);
138 --nc;
139 }
140 }
141 }
142 else
143 valid = false;
144 }
145 }
146 }
147 ++i;
148 }
149 int in_files = fgroup1.size();
150 std::vector<std::string> inputs(in_files * clones + fgroup2.size());
151 copy(fgroup2.begin(), fgroup2.end(), inputs.begin());
152 i = fgroup2.size();
153 for (int k = 0; k < in_files; ++k)
154 for (int c = 0; c < clones; ++c)
155 inputs[i++] = fgroup1[k];
156 if (inputs.empty())
157 {
158 if (OHMMS::Controller->rank() == 0)
159 {
160 std::cerr << "No input file is given." << std::endl;
161 std::cerr << "Usage: qmcpack <input-files> " << std::endl;
162 }
163 OHMMS::Controller->finalize();
164 return 1;
165 }
166 if (useGPU)
167 Init_CUDA();
168 //safe to move on
169 Communicate* qmcComm = OHMMS::Controller;
170 if (inputs.size() > 1)
171 {
172 if (inputs.size() > OHMMS::Controller->size())
173 {
174 std::ostringstream msg;
175 msg << "main(). Current " << OHMMS::Controller->size() << " MPI ranks cannot accommodate all the "
176 << inputs.size() << " individual calculations in the ensemble. "
177 << "Increase the number of MPI ranks or reduce the number of calculations." << std::endl;
178 OHMMS::Controller->barrier_and_abort(msg.str());
179 }
180 qmcComm = new Communicate(*OHMMS::Controller, inputs.size());
181 qmc_common.mpi_groups = inputs.size();
182 }
183 std::stringstream logname;
184 int inpnum = (inputs.size() > 1) ? qmcComm->getGroupID() : 0;
185 std::string myinput = inputs[qmcComm->getGroupID()];
186 myinput = myinput.substr(0, myinput.size() - 4);
187 logname << myinput;
188
189 if (qmcComm->rank() != 0)
190 {
191 outputManager.shutOff();
192 // might need to redirect debug stream to a file per rank if debugging is enabled
193 }
194 if (inputs.size() > 1 && qmcComm->rank() == 0)
195 {
196 char fn[128];
197 snprintf(fn, 127, "%s.g%03d.qmc", logname.str().c_str(), qmcComm->getGroupID());
198 fn[127] = '\0';
199 infoSummary.redirectToFile(fn);
200 infoLog.redirectToSameStream(infoSummary);
201 infoError.redirectToSameStream(infoSummary);
202 }
203
204 //#if defined(MPIRUN_EXTRA_ARGUMENTS)
205 // //broadcast the input file name to other nodes
206 // MPI_Bcast(fname.c_str(),fname.size(),MPI_CHAR,0,OHMMS::Controller->getID());
207 //#endif
208
209 QMCMain* qmc = 0;
210 bool validInput = false;
211 app_log() << " Input file(s): ";
212 for (int k = 0; k < inputs.size(); ++k)
213 app_log() << inputs[k] << " ";
214 app_log() << std::endl;
215 qmc = new QMCMain(qmcComm);
216 if (inputs.size() > 1)
217 validInput = qmc->parse(inputs[qmcComm->getGroupID()]);
218 else
219 validInput = qmc->parse(inputs[0]);
220 if (!validInput)
221 qmcComm->barrier_and_abort("main(). Input invalid.");
222
223 bool qmcSuccess = qmc->execute();
224 if (!qmcSuccess)
225 qmcComm->barrier_and_abort("main(). QMC Execution failed.");
226
227 Libxml2Document timingDoc;
228 timingDoc.newDoc("resources");
229 output_hardware_info(qmcComm, timingDoc, timingDoc.getRoot());
230 timer_manager.output_timing(qmcComm, timingDoc, timingDoc.getRoot());
231 qmc->ptclPool->output_particleset_info(timingDoc, timingDoc.getRoot());
232 if (OHMMS::Controller->rank() == 0)
233 {
234 timingDoc.dump(qmc->getTitle() + ".info.xml");
235 }
236 timer_manager.print(qmcComm);
237 if (qmc)
238 delete qmc;
239 if (useGPU)
240 Finalize_CUDA();
241 }
242 catch (const std::exception& e)
243 {
244 app_error() << e.what() << std::endl;
245 APP_ABORT("Unhandled Exception");
246 }
247 catch (...)
248 {
249 app_error() << "Exception not derived from std::exception thrown" << std::endl;
250 APP_ABORT("Unhandled Exception");
251 }
252
253 if (OHMMS::Controller->rank() == 0)
254 std::cout << std::endl << "QMCPACK execution completed successfully" << std::endl;
255
256 OHMMS::Controller->finalize();
257
258 return 0;
259 }
260
output_hardware_info(Communicate * comm,Libxml2Document & doc,xmlNodePtr root)261 void output_hardware_info(Communicate* comm, Libxml2Document& doc, xmlNodePtr root)
262 {
263 xmlNodePtr hardware = doc.addChild(root, "hardware");
264
265 bool using_mpi = false;
266 #ifdef HAVE_MPI
267 using_mpi = true;
268 doc.addChild(hardware, "mpi_size", comm->size());
269 #endif
270 doc.addChild(hardware, "mpi", using_mpi);
271
272 bool using_openmp = false;
273 #ifdef ENABLE_OPENMP
274 using_openmp = true;
275 doc.addChild(hardware, "openmp_threads", omp_get_max_threads());
276 #endif
277 doc.addChild(hardware, "openmp", using_openmp);
278
279 bool using_gpu = false;
280 #ifdef QMC_CUDA
281 using_gpu = true;
282 #endif
283 doc.addChild(hardware, "gpu", using_gpu);
284 }
285