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