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) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
8 //
9 // File created by: Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 #undef NDEBUG
13 
14 #include "catch.hpp"
15 
16 #include "Configuration.h"
17 
18 #include "OhmmsData/Libxml2Doc.h"
19 #include "OhmmsApp/ProjectData.h"
20 #include "hdf/hdf_archive.h"
21 #include "Utilities/RandomGenerator.h"
22 #include "Utilities/TimerManager.h"
23 
24 #undef APP_ABORT
25 #define APP_ABORT(x)             \
26   {                              \
27     std::cout << x << std::endl; \
28     throw;                       \
29   }
30 
31 #include <string>
32 #include <vector>
33 #include <complex>
34 #include <iomanip>
35 
36 #include "AFQMC/Utilities/test_utils.hpp"
37 //#include "AFQMC/Utilities/myTimer.h"
38 #include "Utilities/Timer.h"
39 #include "AFQMC/Hamiltonians/HamiltonianFactory.h"
40 #include "AFQMC/Hamiltonians/Hamiltonian.hpp"
41 #include "AFQMC/Wavefunctions/WavefunctionFactory.h"
42 #include "AFQMC/Wavefunctions/Wavefunction.hpp"
43 #include "AFQMC/Propagators/PropagatorFactory.h"
44 #include "AFQMC/Propagators/Propagator.hpp"
45 #include "AFQMC/Walkers/WalkerSet.hpp"
46 #include "AFQMC/Memory/buffer_managers.h"
47 
48 #include "AFQMC/Matrix/csr_matrix_construct.hpp"
49 #include "AFQMC/Numerics/ma_blas.hpp"
50 
51 using std::cerr;
52 using std::complex;
53 using std::cout;
54 using std::endl;
55 using std::ifstream;
56 using std::setprecision;
57 using std::string;
58 
59 extern std::string UTEST_HAMIL, UTEST_WFN;
60 
61 namespace qmcplusplus
62 {
63 using namespace afqmc;
64 
propg_fac_shared(boost::mpi3::communicator & world)65 void propg_fac_shared(boost::mpi3::communicator& world)
66 {
67   if (check_hamil_wfn_for_utest("propg_fac_shared", UTEST_WFN, UTEST_HAMIL))
68   {
69     timer_manager.set_timer_threshold(timer_level_coarse);
70     setup_timers(AFQMCTimers, AFQMCTimerNames, timer_level_coarse);
71 
72     // Global Task Group
73     afqmc::GlobalTaskGroup gTG(world);
74 
75     int NMO, NAEA, NAEB;
76     std::tie(NMO, NAEA, NAEB) = read_info_from_hdf(UTEST_HAMIL);
77     WALKER_TYPES type         = afqmc::getWalkerType(UTEST_WFN);
78     int NPOL                  = (type == NONCOLLINEAR) ? 2 : 1;
79 
80     std::map<std::string, AFQMCInfo> InfoMap;
81     InfoMap.insert(std::pair<std::string, AFQMCInfo>("info0", AFQMCInfo{"info0", NMO, NAEA, NAEB}));
82     HamiltonianFactory HamFac(InfoMap);
83     std::string hamil_xml = "<Hamiltonian name=\"ham0\" info=\"info0\"> \
84 <parameter name=\"filetype\">hdf5</parameter> \
85 <parameter name=\"filename\">" +
86         UTEST_HAMIL + "</parameter> \
87 <parameter name=\"cutoff_decomposition\">1e-5</parameter> \
88 </Hamiltonian> \
89 ";
90     const char* ham_xml_block = hamil_xml.c_str();
91     Libxml2Document doc;
92     bool okay = doc.parseFromString(ham_xml_block);
93     REQUIRE(okay);
94     std::string ham_name("ham0");
95     HamFac.push(ham_name, doc.getRoot());
96     Hamiltonian& ham = HamFac.getHamiltonian(gTG, ham_name);
97 
98     auto TG   = TaskGroup_(gTG, std::string("WfnTG"), 1, gTG.getTotalCores());
99     int nwalk = 11; // choose prime number to force non-trivial splits in shared routines
100     RandomGenerator_t rng;
101 
102     const char* wlk_xml_block_closed = "<WalkerSet name=\"wset0\">  \
103       <parameter name=\"walker_type\">closed</parameter>  \
104     </WalkerSet> \
105     ";
106     const char* wlk_xml_block_coll   = "<WalkerSet name=\"wset0\">  \
107       <parameter name=\"walker_type\">collinear</parameter>  \
108     </WalkerSet> \
109     ";
110     const char* wlk_xml_block_noncol = "<WalkerSet name=\"wset0\">  \
111       <parameter name=\"walker_type\">noncollinear</parameter>  \
112     </WalkerSet> \
113     ";
114     const char* wlk_xml_block =
115         ((type == CLOSED) ? (wlk_xml_block_closed) : (type == COLLINEAR ? wlk_xml_block_coll : wlk_xml_block_noncol));
116     Libxml2Document doc3;
117     okay = doc3.parseFromString(wlk_xml_block);
118     REQUIRE(okay);
119 
120     // Create unique restart filename to avoid issues with running tests in parallel
121     // through ctest.
122     std::string restart_file = create_test_hdf(UTEST_WFN, UTEST_HAMIL);
123     app_log() << " propg_fac_shared destroy restart_file " << restart_file << "\n";
124     if (!remove_file(restart_file)) APP_ABORT("failed to remove restart_file");
125     std::string wfn_xml      = "<Wavefunction name=\"wfn0\" info=\"info0\"> \
126       <parameter name=\"filetype\">ascii</parameter> \
127       <parameter name=\"filename\">" +
128         UTEST_WFN + "</parameter> \
129       <parameter name=\"cutoff\">1e-6</parameter> \
130       <parameter name=\"dense_trial\">yes</parameter> \
131       <parameter name=\"restart_file\">" +
132         restart_file + "</parameter> \
133   </Wavefunction> \
134 ";
135     const char* wfn_xml_block = wfn_xml.c_str();
136     Libxml2Document doc2;
137     okay = doc2.parseFromString(wfn_xml_block);
138     REQUIRE(okay);
139     std::string wfn_name("wfn0");
140     WavefunctionFactory WfnFac(InfoMap);
141     WfnFac.push(wfn_name, doc2.getRoot());
142     Wavefunction& wfn = WfnFac.getWavefunction(TG, TG, wfn_name, type, &ham, 1e-6, nwalk);
143 
144     WalkerSet wset(TG, doc3.getRoot(), InfoMap["info0"], &rng);
145     auto initial_guess = WfnFac.getInitialGuess(wfn_name);
146     REQUIRE(initial_guess.size(0) == 2);
147     REQUIRE(initial_guess.size(1) == NPOL * NMO);
148     REQUIRE(initial_guess.size(2) == NAEA);
149     wset.resize(nwalk, initial_guess[0], initial_guess[0]);
150     //                         initial_guess[1](XXX.extension(0),{0,NAEB}));
151 
152     const char* propg_xml_block = "<Propagator name=\"prop0\">  \
153 </Propagator> \
154 ";
155     Libxml2Document doc4;
156     okay = doc4.parseFromString(propg_xml_block);
157     REQUIRE(okay);
158     std::string prop_name("prop0");
159     PropagatorFactory PropgFac(InfoMap);
160     PropgFac.push(prop_name, doc4.getRoot());
161     Propagator& prop = PropgFac.getPropagator(TG, prop_name, wfn, &rng);
162 
163     std::cout << setprecision(12);
164     wfn.Energy(wset);
165     {
166       ComplexType eav = 0, ov = 0;
167       for (auto it = wset.begin(); it != wset.end(); ++it)
168       {
169         eav += *it->weight() * (it->energy());
170         ov += *it->weight();
171       }
172       app_log() << " Initial Energy: " << (eav / ov).real() << std::endl;
173     }
174     double tot_time = 0;
175     RealType dt     = 0.01;
176     RealType Eshift = std::abs(ComplexType(*wset[0].overlap()));
177     for (int i = 0; i < 4; i++)
178     {
179       prop.Propagate(2, wset, Eshift, dt, 1);
180       wfn.Energy(wset);
181       ComplexType eav = 0, ov = 0;
182       for (auto it = wset.begin(); it != wset.end(); ++it)
183       {
184         eav += *it->weight() * (it->energy());
185         ov += *it->weight();
186       }
187       tot_time += 2 * dt;
188       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << std::endl;
189       wfn.Orthogonalize(wset, true);
190     }
191     for (int i = 0; i < 4; i++)
192     {
193       prop.Propagate(4, wset, Eshift, dt, 1);
194       wfn.Energy(wset);
195       ComplexType eav = 0, ov = 0;
196       for (auto it = wset.begin(); it != wset.end(); ++it)
197       {
198         eav += *it->weight() * (it->energy());
199         ov += *it->weight();
200       }
201       tot_time += 4 * dt;
202       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << std::endl;
203       wfn.Orthogonalize(wset, true);
204     }
205 
206     for (int i = 0; i < 4; i++)
207     {
208       prop.Propagate(4, wset, Eshift, dt, 2);
209       wfn.Energy(wset);
210       ComplexType eav = 0, ov = 0;
211       for (auto it = wset.begin(); it != wset.end(); ++it)
212       {
213         eav += *it->weight() * (it->energy());
214         ov += *it->weight();
215       }
216       tot_time += 4 * dt;
217       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << std::endl;
218       wfn.Orthogonalize(wset, true);
219     }
220     for (int i = 0; i < 4; i++)
221     {
222       prop.Propagate(5, wset, Eshift, 2 * dt, 2);
223       wfn.Energy(wset);
224       ComplexType eav = 0, ov = 0;
225       for (auto it = wset.begin(); it != wset.end(); ++it)
226       {
227         eav += *it->weight() * (it->energy());
228         ov += *it->weight();
229       }
230       tot_time += 5 * 2 * dt;
231       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << std::endl;
232       wfn.Orthogonalize(wset, true);
233     }
234 
235     timer_manager.print(nullptr);
236   }
237 }
238 
propg_fac_distributed(boost::mpi3::communicator & world,int ngrp)239 void propg_fac_distributed(boost::mpi3::communicator& world, int ngrp)
240 {
241   if (check_hamil_wfn_for_utest("propg_fac_distributed", UTEST_WFN, UTEST_HAMIL))
242   {
243     timer_manager.set_timer_threshold(timer_level_coarse);
244     setup_timers(AFQMCTimers, AFQMCTimerNames, timer_level_coarse);
245 
246     // Global Task Group
247     afqmc::GlobalTaskGroup gTG(world);
248 
249     int NMO, NAEA, NAEB;
250     std::tie(NMO, NAEA, NAEB) = read_info_from_hdf(UTEST_HAMIL);
251     WALKER_TYPES type         = afqmc::getWalkerType(UTEST_WFN);
252     int NPOL                  = (type == NONCOLLINEAR) ? 2 : 1;
253 
254     std::map<std::string, AFQMCInfo> InfoMap;
255     InfoMap.insert(std::pair<std::string, AFQMCInfo>("info0", AFQMCInfo{"info0", NMO, NAEA, NAEB}));
256     HamiltonianFactory HamFac(InfoMap);
257     std::string hamil_xml = "<Hamiltonian name=\"ham0\" info=\"info0\"> \
258 <parameter name=\"filetype\">hdf5</parameter> \
259 <parameter name=\"filename\">" +
260         UTEST_HAMIL + "</parameter> \
261 <parameter name=\"cutoff_decomposition\">1e-5</parameter> \
262 </Hamiltonian> \
263 ";
264     const char* ham_xml_block = hamil_xml.c_str();
265     Libxml2Document doc;
266     bool okay = doc.parseFromString(ham_xml_block);
267     REQUIRE(okay);
268     std::string ham_name("ham0");
269     HamFac.push(ham_name, doc.getRoot());
270     Hamiltonian& ham = HamFac.getHamiltonian(gTG, ham_name);
271 
272     auto TG     = TaskGroup_(gTG, std::string("WfnTG"), 1, gTG.getTotalCores());
273     auto TGprop = TaskGroup_(gTG, std::string("WfnTG"), ngrp, gTG.getTotalCores());
274     //int nwalk = 4; // choose prime number to force non-trivial splits in shared routines
275     int nwalk = 11; // choose prime number to force non-trivial splits in shared routines
276     RandomGenerator_t rng;
277     qmcplusplus::Timer Time;
278 
279     const char* wlk_xml_block_closed = "<WalkerSet name=\"wset0\">  \
280       <parameter name=\"walker_type\">closed</parameter>  \
281     </WalkerSet> \
282     ";
283     const char* wlk_xml_block_coll   = "<WalkerSet name=\"wset0\">  \
284       <parameter name=\"walker_type\">collinear</parameter>  \
285     </WalkerSet> \
286     ";
287     const char* wlk_xml_block_noncol = "<WalkerSet name=\"wset0\">  \
288       <parameter name=\"walker_type\">noncollinear</parameter>  \
289     </WalkerSet> \
290     ";
291     const char* wlk_xml_block =
292         ((type == CLOSED) ? (wlk_xml_block_closed) : (type == COLLINEAR ? wlk_xml_block_coll : wlk_xml_block_noncol));
293     Libxml2Document doc3;
294     okay = doc3.parseFromString(wlk_xml_block);
295     REQUIRE(okay);
296 
297     std::string restart_file = create_test_hdf(UTEST_WFN, UTEST_HAMIL);
298     app_log() << " propg_fac_distributed destroy restart_file " << restart_file << "\n";
299     if (!remove_file(restart_file)) APP_ABORT("failed to remove restart_file");
300     std::string wfn_xml      = "<Wavefunction name=\"wfn0\" info=\"info0\"> \
301       <parameter name=\"filetype\">ascii</parameter> \
302       <parameter name=\"filename\">" +
303         UTEST_WFN + "</parameter> \
304       <parameter name=\"cutoff\">1e-6</parameter> \
305       <parameter name=\"restart_file\">" +
306         restart_file + "</parameter> \
307   </Wavefunction> \
308 ";
309     const char* wfn_xml_block = wfn_xml.c_str();
310     Libxml2Document doc2;
311     okay = doc2.parseFromString(wfn_xml_block);
312     REQUIRE(okay);
313     std::string wfn_name("wfn0");
314     WavefunctionFactory WfnFac(InfoMap);
315     WfnFac.push(wfn_name, doc2.getRoot());
316     Wavefunction& wfn = WfnFac.getWavefunction(TGprop, TGprop, wfn_name, type, &ham, 1e-6, nwalk);
317 
318     WalkerSet wset(TG, doc3.getRoot(), InfoMap["info0"], &rng);
319     auto initial_guess = WfnFac.getInitialGuess(wfn_name);
320     REQUIRE(initial_guess.size(0) == 2);
321     REQUIRE(initial_guess.size(1) == NPOL * NMO);
322     REQUIRE(initial_guess.size(2) == NAEA);
323     wset.resize(nwalk, initial_guess[0], initial_guess[0]);
324 
325     const char* propg_xml_block0 = "<Propagator name=\"prop0\">  \
326       <parameter name=\"nnodes\">";
327     const char* propg_xml_block1 = "</parameter> \
328 </Propagator> \
329 ";
330     std::string str_             = std::string("<Propagator name=\"prop0\"> <parameter name=\"nnodes\">") +
331         std::to_string(gTG.getTotalNodes()) + std::string("</parameter> </Propagator>");
332     Libxml2Document doc4;
333     okay = doc4.parseFromString(str_.c_str());
334     REQUIRE(okay);
335     std::string prop_name("prop0");
336     PropagatorFactory PropgFac(InfoMap);
337     PropgFac.push(prop_name, doc4.getRoot());
338     Propagator& prop = PropgFac.getPropagator(TGprop, prop_name, wfn, &rng);
339     wfn.Energy(wset);
340     {
341       ComplexType eav = 0, ov = 0;
342       for (auto it = wset.begin(); it != wset.end(); ++it)
343       {
344         eav += *it->weight() * (it->energy());
345         ov += *it->weight();
346       }
347       app_log() << " Initial Energy: " << (eav / ov).real() << std::endl;
348     }
349     double tot_time = 0, t1;
350     RealType dt     = 0.01;
351     RealType Eshift = std::abs(ComplexType(*wset[0].overlap()));
352     Time.restart();
353     for (int i = 0; i < 4; i++)
354     {
355       prop.Propagate(2, wset, Eshift, dt, 1);
356       wfn.Energy(wset);
357       ComplexType eav = 0, ov = 0;
358       for (auto it = wset.begin(); it != wset.end(); ++it)
359       {
360         eav += *it->weight() * (it->energy());
361         ov += *it->weight();
362       }
363       tot_time += 2 * dt;
364       wfn.Orthogonalize(wset, true);
365       t1 = Time.elapsed();
366       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << " Time: " << t1 << std::endl;
367     }
368     for (int i = 0; i < 4; i++)
369     {
370       prop.Propagate(4, wset, Eshift, dt, 1);
371       wfn.Energy(wset);
372       ComplexType eav = 0, ov = 0;
373       for (auto it = wset.begin(); it != wset.end(); ++it)
374       {
375         eav += *it->weight() * (it->energy());
376         ov += *it->weight();
377       }
378       tot_time += 4 * dt;
379       wfn.Orthogonalize(wset, true);
380       t1 = Time.elapsed();
381       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << " Time: " << t1 << std::endl;
382     }
383 
384     for (int i = 0; i < 4; i++)
385     {
386       prop.Propagate(4, wset, Eshift, dt, 2);
387       wfn.Energy(wset);
388       ComplexType eav = 0, ov = 0;
389       for (auto it = wset.begin(); it != wset.end(); ++it)
390       {
391         eav += *it->weight() * (it->energy());
392         ov += *it->weight();
393       }
394       tot_time += 4 * dt;
395       wfn.Orthogonalize(wset, true);
396       t1 = Time.elapsed();
397       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << " Time: " << t1 << std::endl;
398     }
399     for (int i = 0; i < 4; i++)
400     {
401       prop.Propagate(5, wset, Eshift, 2 * dt, 2);
402       wfn.Energy(wset);
403       ComplexType eav = 0, ov = 0;
404       for (auto it = wset.begin(); it != wset.end(); ++it)
405       {
406         eav += *it->weight() * (it->energy());
407         ov += *it->weight();
408       }
409       tot_time += 5 * 2 * dt;
410       wfn.Orthogonalize(wset, true);
411       t1 = Time.elapsed();
412       app_log() << " -- " << i << " " << tot_time << " " << (eav / ov).real() << " Time: " << t1 << std::endl;
413     }
414 
415     timer_manager.print(nullptr);
416   }
417 }
418 
419 TEST_CASE("propg_fac_shared", "[propagator_factory]")
420 {
421   auto world = boost::mpi3::environment::get_world_instance();
422   if (not world.root())
423     infoLog.pause();
424   auto node = world.split_shared(world.rank());
425 
426 #if defined(ENABLE_CUDA) || defined(ENABLE_HIP)
427   arch::INIT(node);
428 #endif
429   setup_memory_managers(node, 10uL * 1024uL * 1024uL);
430 
431   propg_fac_shared(world);
432   release_memory_managers();
433 }
434 
435 TEST_CASE("propg_fac_distributed", "[propagator_factory]")
436 {
437   auto world = boost::mpi3::environment::get_world_instance();
438   if (not world.root())
439     infoLog.pause();
440   auto node = world.split_shared(world.rank());
441 
442 #if defined(ENABLE_CUDA) || defined(ENABLE_HIP)
443   int ngrp(world.size());
444   arch::INIT(node);
445 #else
446   int ngrp(world.size() / node.size());
447 #endif
448   setup_memory_managers(node, 10uL * 1024uL * 1024uL);
449 
450   propg_fac_distributed(world, ngrp);
451   release_memory_managers();
452 }
453 
454 } // namespace qmcplusplus
455