1 //////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source
3 // License.  See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by:
8 // Miguel A. Morales, moralessilva2@llnl.gov
9 //    Lawrence Livermore National Laboratory
10 //
11 // File created by:
12 // Miguel A. Morales, moralessilva2@llnl.gov
13 //    Lawrence Livermore National Laboratory
14 ////////////////////////////////////////////////////////////////////////////////
15 
16 #include <random>
17 
18 #include "hdf/hdf_archive.h"
19 #include "AFQMC/Utilities/readWfn.h"
20 #include "AFQMC/Matrix/csr_hdf5_readers.hpp"
21 #include "WavefunctionFactory.h"
22 #include "AFQMC/Wavefunctions/Wavefunction.hpp"
23 #include "AFQMC/SlaterDeterminantOperations/SlaterDetOperations.hpp"
24 #include "AFQMC/Wavefunctions/NOMSD.hpp"
25 #include "AFQMC/Wavefunctions/PHMSD.hpp"
26 #include "AFQMC/HamiltonianOperations/HamOpsIO.hpp"
27 #include "AFQMC/Wavefunctions/Excitations.hpp"
28 #include "AFQMC/Memory/buffer_managers.h"
29 
30 namespace qmcplusplus
31 {
32 namespace afqmc
33 {
fromASCII(TaskGroup_ & TGprop,TaskGroup_ & TGwfn,xmlNodePtr cur,WALKER_TYPES walker_type,Hamiltonian & h,RealType cutvn,int targetNW)34 Wavefunction WavefunctionFactory::fromASCII(TaskGroup_& TGprop,
35                                             TaskGroup_& TGwfn,
36                                             xmlNodePtr cur,
37                                             WALKER_TYPES walker_type,
38                                             Hamiltonian& h,
39                                             RealType cutvn,
40                                             int targetNW)
41 {
42   if (cur == NULL)
43     APP_ABORT("Error: NULL xml pointer in HamiltonianFactory::parse(). \n");
44 
45   std::string type("msd");
46   std::string info("info0");
47   std::string init_type("");
48   std::string name("");
49   OhmmsAttributeSet oAttrib;
50   oAttrib.add(type, "type");
51   oAttrib.add(info, "info");
52   oAttrib.add(init_type, "init");
53   oAttrib.add(name, "name");
54   oAttrib.put(cur);
55 
56   std::transform(type.begin(), type.end(), type.begin(), (int (*)(int))tolower);
57   std::transform(init_type.begin(), init_type.end(), init_type.begin(), (int (*)(int))tolower);
58 
59   if (InfoMap.find(info) == InfoMap.end())
60   {
61     app_error() << "ERROR: Undefined info in WavefunctionFactory. \n";
62     APP_ABORT("ERROR: Undefined info in WavefunctionFactory. \n");
63   }
64 
65   RealType cutv2(0.);
66   int ndets_to_read(-1); // if not set, read the entire file
67   int initial_configuration = 0;
68   double randomize_guess(0.0);
69   std::string str("false");
70   std::string filename("");
71   std::string restart_file("");
72   std::string write_trial_density_matrix("");
73   ParameterSet m_param;
74   m_param.add(filename, "filename");
75   m_param.add(restart_file, "restart_file");
76   m_param.add(write_trial_density_matrix, "trial_density_matrix");
77   m_param.add(cutv2, "cutoff");
78   m_param.add(ndets_to_read, "ndet");
79   m_param.add(initial_configuration, "initial_configuration");
80   m_param.add(randomize_guess, "randomize_guess");
81   m_param.put(cur);
82 
83   AFQMCInfo& AFinfo = InfoMap[info];
84   auto NCE          = h.getNuclearCoulombEnergy();
85 
86   int NMO  = AFinfo.NMO;
87   int NAEA = AFinfo.NAEA;
88   int NAEB = AFinfo.NAEB;
89   int NPOL = (walker_type == NONCOLLINEAR) ? 2 : 1;
90   if ((walker_type == NONCOLLINEAR) && (NAEB != 0))
91     APP_ABORT(" Error in Wavefunctions/WavefunctionFactory::fromASCII: noncollinear && NAEB!=0. \n\n\n ");
92 
93   std::ifstream in;
94   in.open(filename.c_str());
95   if (in.fail())
96   {
97     app_error() << "Problems opening file:  " << filename << std::endl;
98     APP_ABORT("Problems opening file. \n");
99   }
100   std::string wfn_type = getWfnType(in);
101 
102   using Alloc = shared_allocator<ComplexType>;
103   if (type == "msd" || type == "nomsd")
104   {
105     app_log() << " Wavefunction type: NOMSD\n";
106 
107     std::vector<ComplexType> ci;
108     std::vector<PsiT_Matrix> PsiT;
109     if (wfn_type == "occ" || wfn_type == "mixed")
110     {
111       std::vector<PsiT_Matrix> PsiT_MO; // read_ph_wavefunction returns the full MO matrix
112       // careful here!!!!
113       // number of terms in PsiT_MO depend on RHF/UHF type, not on walker_type!!!
114       ph_excitations<int, ComplexType> abij =
115           read_ph_wavefunction(in, ndets_to_read, walker_type, TGwfn.Node(), NMO, NAEA, NAEB, PsiT_MO);
116       assert(abij.number_of_configurations() == ndets_to_read);
117       int NEL = (walker_type == NONCOLLINEAR) ? (NAEA + NAEB) : NAEA;
118       int N_  = NPOL * NMO;
119       ComplexType one(1.0, 0.0);
120       if (walker_type == COLLINEAR)
121         PsiT.reserve(2 * ndets_to_read);
122       else
123         PsiT.reserve(ndets_to_read);
124       ci.reserve(ndets_to_read);
125       auto refc = abij.reference_configuration();
126       // add reference
127       ci.emplace_back(std::get<2>(*abij.configurations_begin()));
128       if (wfn_type == "occ")
129         PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{NEL, N_}, tp_ul_ul{0, 0}, 1, Alloc(TGwfn.Node())));
130       else
131         PsiT.emplace_back(
132             PsiT_Matrix(tp_ul_ul{NEL, N_}, tp_ul_ul{0, 0}, get_nnz(PsiT_MO[0], refc, NEL, 0), Alloc(TGwfn.Node())));
133       if (TGwfn.Node().root())
134       {
135         if (wfn_type == "occ")
136         {
137           for (int k = 0; k < NEL; k++)
138             PsiT.back().emplace_back({k, *(refc + k)}, one);
139         }
140         else
141         {
142           for (int k = 0; k < NEL; k++)
143           {
144             size_t ki = *(refc + k); // occupied state #k
145             auto col  = PsiT_MO[0].non_zero_indices2_data(ki);
146             auto val  = PsiT_MO[0].non_zero_values_data(ki);
147             for (size_t ic = 0, icend = PsiT_MO[0].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
148               PsiT.back().emplace_back({k, *col}, *val);
149           }
150         }
151       }
152       if (walker_type == COLLINEAR)
153       {
154         if (wfn_type == "occ")
155           PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{NAEB, NMO}, tp_ul_ul{0, 0}, 1, Alloc(TGwfn.Node())));
156         else
157           PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{NAEB, NMO}, tp_ul_ul{0, 0},
158                                         get_nnz(PsiT_MO.back(), refc + NAEA, NAEB, NMO), Alloc(TGwfn.Node())));
159         if (TGwfn.Node().root())
160         {
161           if (wfn_type == "occ")
162           {
163             for (int k = 0; k < NAEB; k++)
164               PsiT.back().emplace_back({k, *(refc + NAEA + k) - NMO}, one);
165           }
166           else
167           {
168             for (int k = 0; k < NAEB; k++)
169             {
170               size_t ki = *(refc + NAEA + k) - NMO; // occupied state #k
171               // this should be correct
172               auto col = PsiT_MO.back().non_zero_indices2_data(ki);
173               auto val = PsiT_MO.back().non_zero_values_data(ki);
174               for (size_t ic = 0, icend = PsiT_MO.back().num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
175                 PsiT.back().emplace_back({k, *col}, *val);
176             }
177           }
178         }
179       }
180       // work array
181       std::vector<int> iwork(NAEA);
182       auto configurations = abij.configurations_begin() + 1;
183       for (; configurations < abij.configurations_end(); ++configurations)
184       {
185         ci.emplace_back(std::get<2>(*configurations));
186         abij.get_alpha_configuration(std::get<0>(*configurations), iwork);
187         if (wfn_type == "occ")
188           PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{NEL, N_}, tp_ul_ul{0, 0}, 1, Alloc(TGwfn.Node())));
189         else
190           PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{NEL, N_}, tp_ul_ul{0, 0}, get_nnz(PsiT_MO[0], iwork.data(), NEL, 0),
191                                         Alloc(TGwfn.Node())));
192         if (TGwfn.Node().root())
193         {
194           // add excited configuration
195           if (wfn_type == "occ")
196           {
197             for (int k = 0; k < NEL; k++)
198               PsiT.back().emplace_back({k, iwork[k]}, one);
199           }
200           else
201           {
202             for (int k = 0; k < NEL; k++)
203             {
204               size_t ki = iwork[k]; // occupied state #k
205               auto col  = PsiT_MO[0].non_zero_indices2_data(ki);
206               auto val  = PsiT_MO[0].non_zero_values_data(ki);
207               for (size_t ic = 0, icend = PsiT_MO[0].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
208                 PsiT.back().emplace_back({k, *col}, *val);
209             }
210           }
211         }
212         if (walker_type == COLLINEAR)
213         {
214           abij.get_beta_configuration(std::get<1>(*configurations), iwork);
215           if (wfn_type == "occ")
216             PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{NAEB, NMO}, tp_ul_ul{0, 0}, 1, Alloc(TGwfn.Node())));
217           else
218             PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{NAEB, NMO}, tp_ul_ul{0, 0},
219                                           get_nnz(PsiT_MO.back(), iwork.data(), NAEB, NMO), Alloc(TGwfn.Node())));
220           if (TGwfn.Node().root())
221           {
222             if (wfn_type == "occ")
223             {
224               for (int k = 0; k < NAEB; k++)
225                 PsiT.back().emplace_back({k, iwork[k] - NMO}, one);
226             }
227             else
228             {
229               for (int k = 0; k < NAEB; k++)
230               {
231                 size_t ki = iwork[k] - NMO; // occupied state #k
232                 auto col  = PsiT_MO.back().non_zero_indices2_data(ki);
233                 auto val  = PsiT_MO.back().non_zero_values_data(ki);
234                 for (size_t ic = 0, icend = PsiT_MO.back().num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
235                   PsiT.back().emplace_back({k, *col}, *val);
236               }
237             }
238           }
239         }
240       }
241     }
242     else if (wfn_type == "matrix")
243     {
244       read_general_wavefunction(in, ndets_to_read, walker_type, TGwfn.Node(), NMO, NAEA, NAEB, PsiT, ci);
245     }
246     else
247     {
248       APP_ABORT("Error: Unknown wfn_type in WavefunctionFactory with MSD wavefunction.\n");
249     }
250     TGwfn.node_barrier();
251     // multideterminant NOMSD needs
252     auto HOps(getHamOps(restart_file, walker_type, NMO, NAEA, NAEB, PsiT,
253       TGprop, TGwfn, cutvn, cutv2, ndets_to_read, h));
254     TGwfn.node_barrier();
255     // add initial_guess
256     auto guess = initial_guess.find(name);
257     if (guess == initial_guess.end())
258     {
259       auto newg =
260           initial_guess.insert(std::make_pair(name, boost::multi::array<ComplexType, 3>({2, NPOL * NMO, NAEA})));
261       int iC = (walker_type != COLLINEAR ? initial_configuration : 2 * initial_configuration);
262       if (iC >= PsiT.size())
263         APP_ABORT(" Error: initial_configuration > ndets_to_read \n");
264       if (!newg.second)
265         APP_ABORT(" Error: Problems adding new initial guess. \n");
266       using ma::conj;
267       std::fill_n((newg.first)->second.origin(), 2 * NPOL * NMO * NAEA, ComplexType(0.0, 0.0));
268       {
269         auto pbegin = PsiT[iC].pointers_begin();
270         auto pend   = PsiT[iC].pointers_end();
271         auto p0     = pbegin[0];
272         auto v0     = PsiT[iC].non_zero_values_data();
273         auto c0     = PsiT[iC].non_zero_indices2_data();
274         for (int i = 0; i < PsiT[iC].size(0); i++)
275           for (int ip = pbegin[i]; ip < pend[i]; ip++)
276           {
277             ((newg.first)->second)[0][c0[ip - p0]][i] = ma::conj(v0[ip - p0]);
278           }
279       }
280       if (walker_type == COLLINEAR)
281       {
282         auto pbegin = PsiT[iC + 1].pointers_begin();
283         auto pend   = PsiT[iC + 1].pointers_end();
284         auto p0     = pbegin[0];
285         auto v0     = PsiT[iC + 1].non_zero_values_data();
286         auto c0     = PsiT[iC + 1].non_zero_indices2_data();
287         for (int i = 0; i < PsiT[iC + 1].size(0); i++)
288           for (int ip = pbegin[i]; ip < pend[i]; ip++)
289           {
290             ((newg.first)->second)[1][c0[ip - p0]][i] = ma::conj(v0[ip - p0]);
291           }
292       }
293     }
294     else
295       APP_ABORT(" Error: Problems adding new initial guess, already exists. \n");
296 
297     if (TGwfn.TG_local().size() > 1)
298     {
299       SlaterDetOperations SDetOp(SlaterDetOperations_shared<ComplexType>(NPOL * NMO, NAEA));
300       return Wavefunction(NOMSD<devcsr_Matrix>(AFinfo, cur, TGwfn, std::move(SDetOp), std::move(HOps), std::move(ci),
301                                                std::move(PsiT), walker_type, NCE, targetNW));
302     }
303     else
304     {
305       SlaterDetOperations SDetOp(
306           SlaterDetOperations_serial<ComplexType, DeviceBufferManager>(NPOL * NMO, NAEA, DeviceBufferManager{}));
307       return Wavefunction(NOMSD<devcsr_Matrix>(AFinfo, cur, TGwfn, std::move(SDetOp), std::move(HOps), std::move(ci),
308                                                std::move(PsiT), walker_type, NCE, targetNW));
309     }
310   }
311   else if (type == "phmsd")
312   {
313     app_log() << " Wavefunction type: PHMSD\n";
314 
315     /* Implementation notes:
316      *  - PsiT: [Nact, NMO] where Nact is the number of active space orbitals,
317      *                     those that participate in the ci expansion
318      *  - The half rotation is done with respect to the supermatrix PsiT
319      *  - Need to calculate Nact and create a mapping from orbital index to actice space index.
320      *    Those orbitals in the corresponding virtual space (not in active) map to -1 as a precaution.
321      */
322 
323     // assuming walker_type==COLLINEAR for now, specialize a type for perfect pairing PHMSD
324     // MAM: generatlize for NONCOLLINEAR later!!!
325     if (walker_type != COLLINEAR)
326       APP_ABORT("Error: PHMSD requires a COLLINEAR calculation.\n");
327     std::vector<PsiT_Matrix> PsiT_MO;
328     ph_excitations<int, ComplexType> abij =
329         read_ph_wavefunction(in, ndets_to_read, walker_type, TGwfn.Node(), NMO, NAEA, NAEB, PsiT_MO);
330     int N_ = (walker_type == NONCOLLINEAR) ? 2 * NMO : NMO;
331     if (wfn_type == "occ")
332     {
333       //build PsiT_MO
334       ComplexType one(1.0, 0.0);
335       // wfn_type == "occ" implies a single reference now, since integrals can't be UHF
336       PsiT_MO.reserve(1);
337       PsiT_MO.emplace_back(PsiT_Matrix(tp_ul_ul{N_, N_}, tp_ul_ul{0, 0}, 1, Alloc(TGwfn.Node())));
338       if (TGwfn.Node().root())
339         for (int k = 0; k < N_; k++)
340           PsiT_MO.back().emplace_back({k, k}, one);
341     }
342     else if (wfn_type == "mixed")
343     {
344       // nothing to do
345     }
346     else if (wfn_type == "matrix")
347     {
348       APP_ABORT("Error: wfn_type=matrix not allowed in WavefunctionFactory with PHMSD wavefunction.\n");
349     }
350     else
351     {
352       APP_ABORT("Error: Unknown wfn_type in WavefunctionFactory with MSD wavefunction.\n");
353     }
354     TGwfn.node_barrier();
355 
356     // find active space orbitals and create super trial matrix PsiT
357     std::vector<PsiT_Matrix> PsiT;
358     PsiT.reserve(PsiT_MO.size());
359     // expect mapped over range [0-2*NMO], but alpha and beta sectors with 0-based active indexes
360     std::map<int, int> mo2active(find_active_space(PsiT_MO.size() == 1, abij, NMO, NAEA, NAEB));
361     std::map<int, int> acta2mo;
362     std::map<int, int> actb2mo;
363     std::vector<int> active_alpha;
364     std::vector<int> active_beta;
365     std::vector<int> active_combined;
366     for (int i = 0; i < NMO; i++)
367     {
368       if (mo2active[i] >= 0)
369       {
370         active_alpha.push_back(i);
371         acta2mo[mo2active[i]] = i;
372       }
373       if (mo2active[i + NMO] >= 0)
374       {
375         active_beta.push_back(i);
376         actb2mo[mo2active[i + NMO]] = i + NMO;
377       }
378       if (mo2active[i] >= 0 || mo2active[i + NMO] >= 0)
379         active_combined.push_back(i);
380     }
381     if (PsiT_MO.size() == 1)
382     {
383       // RHF reference
384       PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{active_combined.size(), NMO}, tp_ul_ul{0, 0},
385                                     get_nnz(PsiT_MO[0], active_combined.data(), active_combined.size(), 0),
386                                     Alloc(TGwfn.Node())));
387       if (TGwfn.Node().root())
388       {
389         for (int k = 0; k < active_combined.size(); k++)
390         {
391           size_t ki = active_combined[k]; // occupied state #k
392           auto col  = PsiT_MO[0].non_zero_indices2_data(ki);
393           auto val  = PsiT_MO[0].non_zero_values_data(ki);
394           for (size_t ic = 0, icend = PsiT_MO[0].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
395             PsiT[0].emplace_back({k, *col}, *val);
396         }
397       }
398     }
399     else
400     {
401       // UHF reference
402       PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{active_alpha.size(), NMO}, tp_ul_ul{0, 0},
403                                     get_nnz(PsiT_MO[0], active_alpha.data(), active_alpha.size(), 0),
404                                     Alloc(TGwfn.Node())));
405       if (TGwfn.Node().root())
406       {
407         for (int k = 0; k < active_alpha.size(); k++)
408         {
409           size_t ki = active_alpha[k]; // occupied state #k
410           auto col  = PsiT_MO[0].non_zero_indices2_data(ki);
411           auto val  = PsiT_MO[0].non_zero_values_data(ki);
412           for (size_t ic = 0, icend = PsiT_MO[0].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
413             PsiT.back().emplace_back({k, *col}, *val);
414         }
415       }
416       PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{active_beta.size(), NMO}, tp_ul_ul{0, 0},
417                                     get_nnz(PsiT_MO[1], active_beta.data(), active_beta.size(), 0),
418                                     Alloc(TGwfn.Node())));
419       if (TGwfn.Node().root())
420       {
421         for (int k = 0; k < active_beta.size(); k++)
422         {
423           size_t ki = active_beta[k]; // occupied state #k
424           auto col  = PsiT_MO[1].non_zero_indices2_data(ki);
425           auto val  = PsiT_MO[1].non_zero_values_data(ki);
426           for (size_t ic = 0, icend = PsiT_MO[1].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
427             PsiT[1].emplace_back({k, *col}, *val);
428         }
429       }
430     }
431     // now that mappings have been constructed, map indexes of excited state orbitals
432     // to the corresponding active space indexes
433     if (TGwfn.Node().root())
434     {
435       // map reference
436       auto refc = abij.reference_configuration();
437       for (int i = 0; i < NAEA + NAEB; i++, ++refc)
438         *refc = mo2active[*refc];
439       for (int n = 1; n < abij.maximum_excitation_number()[0]; n++)
440       {
441         auto it  = abij.alpha_begin(n);
442         auto ite = abij.alpha_end(n);
443         for (; it < ite; ++it)
444         {
445           auto exct = (*it) + n; // only need to map excited state indexes
446           for (int np = 0; np < n; ++np, ++exct)
447             *exct = mo2active[*exct];
448         }
449       }
450       for (int n = 1; n < abij.maximum_excitation_number()[1]; n++)
451       {
452         auto it  = abij.beta_begin(n);
453         auto ite = abij.beta_end(n);
454         for (; it < ite; ++it)
455         {
456           auto exct = (*it) + n; // only need to map excited state indexes
457           for (int np = 0; np < n; ++np, ++exct)
458             *exct = mo2active[*exct];
459         }
460       }
461     }
462     // is PureSD actually faster??? CHECK!!!
463     // NOTE: For UHF reference, treat HOps as a 2 determinant wavefunction of a
464     //        CLOSED walker type. This way you can treat alpha/beta sectors independently in
465     //        HOps through the index corresponding 0/1.
466     // never add coulomb to half rotated v2 tensor in PHMSD
467     TGwfn.node_barrier();
468     auto HOps(getHamOps(restart_file, CLOSED, NMO, NAEA, NAEB, PsiT,
469       TGprop, TGwfn, cutvn, cutv2, false, h));
470     TGwfn.node_barrier();
471     // add initial_guess
472     // when propagating Nact states, change this here
473     auto guess = initial_guess.find(name);
474     if (guess == initial_guess.end())
475     {
476       auto newg = initial_guess.insert(std::make_pair(name, boost::multi::array<ComplexType, 3>({2, NMO, NAEA})));
477       if (!newg.second)
478         APP_ABORT(" Error: Problems adding new initial guess. \n");
479       auto& Psi0((newg.first)->second);
480       randomize_guess = std::abs(randomize_guess);
481       if (randomize_guess > 1e-12)
482         app_log() << " Randomizing initial guess with uniform distribution: " << randomize_guess << std::endl;
483       std::default_random_engine generator(777);
484       std::uniform_real_distribution<double> distribution(-randomize_guess, randomize_guess);
485       int iC = initial_configuration;
486       if (iC >= abij.number_of_configurations())
487         APP_ABORT(" Error: initial_configuration > ndets \n");
488       using ma::conj;
489       std::fill_n((newg.first)->second.origin(), 2 * NMO * NAEA, ComplexType(0.0, 0.0));
490       //auto refc = abij.reference_configuration();
491       {
492         std::vector<int> alphaC(NAEA);
493         abij.get_alpha_configuration(std::get<0>(*(abij.configurations_begin() + iC)), alphaC);
494         auto pbegin = PsiT[0].pointers_begin();
495         auto pend   = PsiT[0].pointers_end();
496         auto p0     = pbegin[0];
497         auto v0     = PsiT[0].non_zero_values_data();
498         auto c0     = PsiT[0].non_zero_indices2_data();
499         // only takinf NAEA states, increase later if super SM is needed
500         for (int i = 0; i < NAEA; i++)
501         {
502           //int ik = *(refc+i);
503           int ik = alphaC[i];
504           for (int ip = pbegin[ik]; ip < pend[ik]; ip++)
505             Psi0[0][c0[ip - p0]][i] = ma::conj(v0[ip - p0]);
506         }
507         if (randomize_guess > 1e-12)
508           for (int i = 0; i < NMO; i++)
509             for (int a = 0; a < NAEA; a++)
510               Psi0[0][i][a] += distribution(generator);
511       }
512       if (walker_type == COLLINEAR)
513       {
514         std::vector<int> betaC(NAEB);
515         abij.get_beta_configuration(std::get<1>(*(abij.configurations_begin() + iC)), betaC);
516         auto pbegin = PsiT.back().pointers_begin();
517         auto pend   = PsiT.back().pointers_end();
518         auto p0     = pbegin[0];
519         auto v0     = PsiT.back().non_zero_values_data();
520         auto c0     = PsiT.back().non_zero_indices2_data();
521         // only takinf NAEB states, increase later if super SM is needed
522         for (int i = 0; i < NAEB; i++)
523         {
524           //int ik = *(refc+NAEA+i);
525           int ik = betaC[i];
526           for (int ip = pbegin[ik]; ip < pend[ik]; ip++)
527             Psi0[1][c0[ip - p0]][i] = ma::conj(v0[ip - p0]);
528         }
529         if (randomize_guess > 1e-12)
530           for (int i = 0; i < NMO; i++)
531             for (int a = 0; a < NAEB; a++)
532               Psi0[1][i][a] += distribution(generator);
533       }
534     }
535     else
536       APP_ABORT(" Error: Problems adding new initial guess, already exists. \n");
537 
538     // setup configuration coupligs
539     using index_aos = ma::sparse::array_of_sequences<int, int, shared_allocator<int>, ma::sparse::is_root>;
540     //    std::allocator<ComplexType> alloc_{}; //shared_allocator<ComplexType>;
541     shared_allocator<int> alloc_{TGwfn.Node()};
542 
543     // alpha
544     std::vector<int> counts_alpha(abij.number_of_unique_excitations()[0]);
545     std::vector<int> counts_beta(abij.number_of_unique_excitations()[1]);
546     if (TGwfn.Node().root())
547     {
548       for (auto it = abij.configurations_begin(); it < abij.configurations_end(); ++it)
549       {
550         ++counts_alpha[std::get<0>(*it)];
551         ++counts_beta[std::get<1>(*it)];
552       }
553     }
554     TGwfn.Node().broadcast_n(counts_alpha.begin(), counts_alpha.size());
555     TGwfn.Node().broadcast_n(counts_beta.begin(), counts_beta.size());
556     index_aos beta_coupled_to_unique_alpha(counts_alpha.size(), counts_alpha, alloc_);
557     index_aos alpha_coupled_to_unique_beta(counts_beta.size(), counts_beta, alloc_);
558     if (TGwfn.Node().root())
559     {
560       int ni = 0;
561       for (auto it = abij.configurations_begin(); it < abij.configurations_end(); ++it, ++ni)
562       {
563         beta_coupled_to_unique_alpha.emplace_back(std::get<0>(*it), ni);
564         alpha_coupled_to_unique_beta.emplace_back(std::get<1>(*it), ni);
565       }
566     }
567     TGwfn.Node().barrier();
568 
569     //return Wavefunction{};
570     return Wavefunction(PHMSD(AFinfo, cur, TGwfn, std::move(HOps), std::move(acta2mo), std::move(actb2mo),
571                               std::move(abij), std::move(beta_coupled_to_unique_alpha),
572                               std::move(alpha_coupled_to_unique_beta), std::move(PsiT), walker_type, NCE, targetNW));
573   }
574   else if (type == "generalmsd")
575   {
576     app_error() << " Error: Wavefunction type GeneralMSD not yet implemented. \n";
577     APP_ABORT(" Error: Wavefunction type GeneralMSD not yet implemented. \n");
578     return Wavefunction{};
579   }
580   else
581   {
582     app_error() << " Error: Unknown wave-function type: " << type << std::endl;
583     APP_ABORT(" Error: Unknown wave-function type. \n");
584     return Wavefunction{};
585   }
586 }
587 
fromHDF5(TaskGroup_ & TGprop,TaskGroup_ & TGwfn,xmlNodePtr cur,WALKER_TYPES walker_type,Hamiltonian & h,RealType cutvn,int targetNW)588 Wavefunction WavefunctionFactory::fromHDF5(TaskGroup_& TGprop,
589                                            TaskGroup_& TGwfn,
590                                            xmlNodePtr cur,
591                                            WALKER_TYPES walker_type,
592                                            Hamiltonian& h,
593                                            RealType cutvn,
594                                            int targetNW)
595 {
596   if (cur == NULL)
597     APP_ABORT("Error: NULL xml pointer in HamiltonianFactory::parse(). \n");
598 
599   std::string type("MSD");
600   std::string info("info0");
601   std::string init_type("");
602   std::string name("");
603   OhmmsAttributeSet oAttrib;
604   oAttrib.add(type, "type");
605   oAttrib.add(info, "info");
606   oAttrib.add(init_type, "init");
607   oAttrib.add(name, "name");
608   oAttrib.put(cur);
609 
610   std::transform(type.begin(), type.end(), type.begin(), (int (*)(int))tolower);
611   std::transform(init_type.begin(), init_type.end(), init_type.begin(), (int (*)(int))tolower);
612 
613   if (InfoMap.find(info) == InfoMap.end())
614   {
615     app_error() << "ERROR: Undefined info in WavefunctionFactory. \n";
616     APP_ABORT("ERROR: Undefined info in WavefunctionFactory. \n");
617   }
618 
619   RealType cutv2(0.);
620   int ndets_to_read(-1); // if not set, read the entire file
621   std::string str("false");
622   std::string filename("");
623   std::string restart_file("");
624   std::string rediag("");
625   std::string dense_trial("");
626   ParameterSet m_param;
627   m_param.add(filename, "filename");
628   m_param.add(restart_file, "restart_file");
629   m_param.add(cutv2, "cutoff");
630   m_param.add(rediag, "rediag");
631   m_param.add(ndets_to_read, "ndet");
632   m_param.add(dense_trial, "dense_trial");
633   m_param.put(cur);
634   bool recompute_ci = false;
635   std::transform(rediag.begin(), rediag.end(), rediag.begin(), (int (*)(int))tolower);
636   if (rediag == "yes" || rediag == "true")
637     recompute_ci = true;
638 
639   AFQMCInfo& AFinfo = InfoMap[info];
640   ValueType NCE     = 0.0;
641 
642   int NMO  = AFinfo.NMO;
643   int NAEA = AFinfo.NAEA;
644   int NAEB = AFinfo.NAEB;
645   int NPOL = (walker_type == NONCOLLINEAR) ? 2 : 1;
646   if ((walker_type == NONCOLLINEAR) && (NAEB != 0))
647     APP_ABORT(" Error in Wavefunctions/WavefunctionFactory::fromASCII: noncollinear && NAEB!=0. \n\n\n ");
648 
649   std::vector<int> excitations;
650 
651   using Alloc = shared_allocator<ComplexType>;
652   // HOps, ci, PsiT, NCE
653   hdf_archive dump(TGwfn.Global());
654   if (!dump.open(filename, H5F_ACC_RDONLY))
655   {
656     app_error() << " Error hdf5 file in WavefunctionFactory. \n";
657     APP_ABORT("");
658   }
659   if (!dump.push("Wavefunction", false))
660   {
661     app_error() << " Error in WavefunctionFactory: Group Wavefunction not found. \n";
662     APP_ABORT("");
663   }
664 
665   if (type == "msd" || type == "nomsd")
666   {
667     app_log() << " Wavefunction type: NOMSD" << std::endl;
668     if (!dump.push("NOMSD", false))
669     {
670       app_error() << " Error in WavefunctionFactory: Group NOMSD not found.\n";
671       APP_ABORT("");
672     }
673     std::vector<ComplexType> ci;
674 
675     // Read common trial wavefunction input options.
676     WALKER_TYPES input_wtype;
677     getCommonInput(dump, NMO, NAEA, NAEB, ndets_to_read, ci, input_wtype, TGwfn.Global().root());
678     NCE = h.getNuclearCoulombEnergy();
679 
680     TGwfn.Global().broadcast_n(ci.data(), ci.size());
681     TGwfn.Global().broadcast_value(NCE);
682 
683     // Create Trial wavefunction.
684     int nd     = (walker_type == COLLINEAR ? 2 * ndets_to_read : ndets_to_read);
685     int ndread = nd;
686     if (walker_type == COLLINEAR and input_wtype == CLOSED)
687       ndread = ndets_to_read;
688     std::vector<PsiT_Matrix> PsiT;
689     PsiT.reserve(nd);
690     using Alloc = shared_allocator<ComplexType>;
691     for (int i = 0; i < ndread; ++i)
692     {
693       if (!dump.push(std::string("PsiT_") + std::to_string(i), false))
694       {
695         app_error() << " Error in WavefunctionFactory: Group PsiT not found. \n";
696         APP_ABORT("");
697       }
698       PsiT.emplace_back(csr_hdf5::HDF2CSR<PsiT_Matrix, Alloc>(dump, TGwfn.Node())); //,Alloc(TGwfn.Node())));
699       dump.pop();
700       if (walker_type == COLLINEAR and input_wtype == CLOSED)
701       {
702         if (NAEA != NAEB)
703           APP_ABORT(" Error: NAEA!=NAEB when initializing collinear wfn from closed shell file.\n");
704         // read them again
705         if (!dump.push(std::string("PsiT_") + std::to_string(i), false))
706         {
707           app_error() << " Error in WavefunctionFactory: Group PsiT not found. \n";
708           APP_ABORT("");
709         }
710         PsiT.emplace_back(csr_hdf5::HDF2CSR<PsiT_Matrix, Alloc>(dump, TGwfn.Node())); //,Alloc(TGwfn.Node())));
711         dump.pop();
712       }
713     }
714 
715     // Set initial walker's Slater matrix.
716     getInitialGuess(dump, name, NMO, NAEA, NAEB, walker_type);
717 
718     // Restore Hamiltonian Operations Object from file if it exists.
719     TGwfn.node_barrier();
720     auto HOps(getHamOps(restart_file, walker_type, NMO, NAEA, NAEB, PsiT,
721       TGprop, TGwfn, cutvn, cutv2, ndets_to_read, h));
722     TGwfn.node_barrier();
723 
724     // if not set, get default based on HamTYpe
725     // use sparse trial only on KP runs
726     if (dense_trial == "")
727     {
728       dense_trial = std::string("yes");
729       if (HOps.getHamType() == KPFactorized || HOps.getHamType() == KPTHC)
730         dense_trial = std::string("no");
731     }
732 
733     if (TGwfn.TG_local().size() > 1)
734     {
735       SlaterDetOperations SDetOp(SlaterDetOperations_shared<ComplexType>(NPOL * NMO, NAEA));
736       if (dense_trial == "yes")
737       {
738         using MType = ComplexMatrix<node_allocator<ComplexType>>;
739         std::vector<MType> PsiT_;
740         PsiT_.reserve(PsiT.size());
741         auto alloc_shared_(make_node_allocator<ComplexType>(TGwfn));
742         for (auto& v : PsiT)
743         {
744           PsiT_.emplace_back(MType({v.size(0), v.size(1)}, alloc_shared_));
745           ma::Matrix2MAREF('N', v, PsiT_.back());
746         }
747         return Wavefunction(NOMSD<MType>(AFinfo, cur, TGwfn, std::move(SDetOp), std::move(HOps), std::move(ci),
748                                          std::move(PsiT_), walker_type, NCE, targetNW));
749       }
750       else
751       {
752         return Wavefunction(NOMSD<devcsr_Matrix>(AFinfo, cur, TGwfn, std::move(SDetOp), std::move(HOps), std::move(ci),
753                                                  std::move(PsiT), walker_type, NCE, targetNW));
754       }
755     }
756     else
757     {
758       SlaterDetOperations SDetOp(
759           SlaterDetOperations_serial<ComplexType, DeviceBufferManager>(NPOL * NMO, NAEA, DeviceBufferManager{}));
760       if (dense_trial == "yes")
761       {
762         using MType = ComplexMatrix<node_allocator<ComplexType>>;
763         std::vector<MType> PsiT_;
764         PsiT_.reserve(PsiT.size());
765         auto alloc_shared_(make_node_allocator<ComplexType>(TGwfn));
766         for (auto& v : PsiT)
767         {
768           PsiT_.emplace_back(MType({v.size(0), v.size(1)}, alloc_shared_));
769           ma::Matrix2MAREF('N', v, PsiT_.back());
770         }
771         return Wavefunction(NOMSD<MType>(AFinfo, cur, TGwfn, std::move(SDetOp), std::move(HOps), std::move(ci),
772                                          std::move(PsiT_), walker_type, NCE, targetNW));
773       }
774       else
775       {
776         return Wavefunction(NOMSD<devcsr_Matrix>(AFinfo, cur, TGwfn, std::move(SDetOp), std::move(HOps), std::move(ci),
777                                                  std::move(PsiT), walker_type, NCE, targetNW));
778       }
779     }
780   }
781   else if (type == "phmsd")
782   {
783     app_log() << " Wavefunction type: PHMSD" << std::endl;
784 
785     /* Implementation notes:
786      *  - PsiT: [Nact, NMO] where Nact is the number of active space orbitals,
787      *                     those that participate in the ci expansion
788      *  - The half rotation is done with respect to the supermatrix PsiT
789      *  - Need to calculate Nact and create a mapping from orbital index to actice space index.
790      *    Those orbitals in the corresponding virtual space (not in active) map to -1 as a precaution.
791      */
792 
793     // assuming walker_type==COLLINEAR for now, specialize a type for perfect pairing PHMSD
794     if (walker_type != COLLINEAR)
795       APP_ABORT("Error: PHMSD requires a COLLINEAR calculation.\n");
796     std::vector<PsiT_Matrix> PsiT_MO;
797     std::string wfn_type;
798     if (!dump.push("PHMSD", false))
799     {
800       app_error() << " Error in WavefunctionFactory: Group PHMSD not found. \n";
801       APP_ABORT("");
802     }
803     std::vector<int> occbuff;
804     std::vector<ComplexType> coeffs;
805     // 1. Read occupancies and coefficients.
806     app_log() << " Reading PHMSD wavefunction from " << filename << std::endl;
807     read_ph_wavefunction_hdf(dump, coeffs, occbuff, ndets_to_read, walker_type, TGwfn.Node(), NMO, NAEA, NAEB, PsiT_MO,
808                              wfn_type);
809     app_log() << " Finished reading PHMSD wavefunction " << std::endl;
810     boost::multi::array_ref<int, 2> occs(to_address(occbuff.data()), {ndets_to_read, NAEA + NAEB});
811     // 2. Compute Variational Energy / update coefficients
812     app_log() << " Computing variational energy of trial wavefunction." << std::endl;
813     computeVariationalEnergyPHMSD(TGwfn, h, occs, coeffs, ndets_to_read, NAEA, NAEB, NMO, recompute_ci);
814     app_log() << " Finished computing variational energy of trial wavefunction." << std::endl;
815     // 3. Construct Structures.
816     ph_excitations<int, ComplexType> abij = build_ph_struct(coeffs, occs, ndets_to_read, TGwfn.Node(), NMO, NAEA, NAEB);
817     int N_                                = (walker_type == NONCOLLINEAR) ? 2 * NMO : NMO;
818     if (wfn_type == "occ")
819     {
820       //build PsiT_MO
821       ComplexType one(1.0, 0.0);
822       // wfn_type == "occ" implies a single reference now, since integrals can't be UHF
823       PsiT_MO.reserve(1);
824       PsiT_MO.emplace_back(PsiT_Matrix(tp_ul_ul{N_, N_}, tp_ul_ul{0, 0}, 1, Alloc(TGwfn.Node())));
825       if (TGwfn.Node().root())
826         for (int k = 0; k < N_; k++)
827           PsiT_MO.back().emplace_back({k, k}, one);
828     }
829     else if (wfn_type == "mixed")
830     {
831       // nothing to do
832     }
833     else if (wfn_type == "matrix")
834     {
835       APP_ABORT("Error: wfn_type=matrix not allowed in WavefunctionFactory with PHMSD wavefunction.\n");
836     }
837     else
838     {
839       APP_ABORT("Error: Unknown wfn_type in WavefunctionFactory with MSD wavefunction.\n");
840     }
841     TGwfn.node_barrier();
842 
843     // find active space orbitals and create super trial matrix PsiT
844     std::vector<PsiT_Matrix> PsiT;
845     PsiT.reserve(PsiT_MO.size());
846     // expect mapped over range [0-2*NMO], but alpha and beta sectors with 0-based active indexes
847     std::map<int, int> mo2active(find_active_space(PsiT_MO.size() == 1, abij, NMO, NAEA, NAEB));
848     std::map<int, int> acta2mo;
849     std::map<int, int> actb2mo;
850     std::vector<int> active_alpha;
851     std::vector<int> active_beta;
852     std::vector<int> active_combined;
853     for (int i = 0; i < NMO; i++)
854     {
855       if (mo2active[i] >= 0)
856       {
857         active_alpha.push_back(i);
858         acta2mo[mo2active[i]] = i;
859       }
860       if (mo2active[i + NMO] >= 0)
861       {
862         active_beta.push_back(i);
863         actb2mo[mo2active[i + NMO]] = i + NMO;
864       }
865       if (mo2active[i] >= 0 || mo2active[i + NMO] >= 0)
866         active_combined.push_back(i);
867     }
868     if (PsiT_MO.size() == 1)
869     {
870       // RHF reference
871       PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{active_combined.size(), NMO}, tp_ul_ul{0, 0},
872                                     get_nnz(PsiT_MO[0], active_combined.data(), active_combined.size(), 0),
873                                     Alloc(TGwfn.Node())));
874       if (TGwfn.Node().root())
875       {
876         for (int k = 0; k < active_combined.size(); k++)
877         {
878           size_t ki = active_combined[k]; // occupied state #k
879           auto col  = PsiT_MO[0].non_zero_indices2_data(ki);
880           auto val  = PsiT_MO[0].non_zero_values_data(ki);
881           for (size_t ic = 0, icend = PsiT_MO[0].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
882             PsiT[0].emplace_back({k, *col}, *val);
883         }
884       }
885     }
886     else
887     {
888       // UHF reference
889       PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{active_alpha.size(), NMO}, tp_ul_ul{0, 0},
890                                     get_nnz(PsiT_MO[0], active_alpha.data(), active_alpha.size(), 0),
891                                     Alloc(TGwfn.Node())));
892       if (TGwfn.Node().root())
893       {
894         for (int k = 0; k < active_alpha.size(); k++)
895         {
896           size_t ki = active_alpha[k]; // occupied state #k
897           auto col  = PsiT_MO[0].non_zero_indices2_data(ki);
898           auto val  = PsiT_MO[0].non_zero_values_data(ki);
899           for (size_t ic = 0, icend = PsiT_MO[0].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
900             PsiT.back().emplace_back({k, *col}, *val);
901         }
902       }
903       PsiT.emplace_back(PsiT_Matrix(tp_ul_ul{active_beta.size(), NMO}, tp_ul_ul{0, 0},
904                                     get_nnz(PsiT_MO[1], active_beta.data(), active_beta.size(), 0),
905                                     Alloc(TGwfn.Node())));
906       if (TGwfn.Node().root())
907       {
908         for (int k = 0; k < active_beta.size(); k++)
909         {
910           size_t ki = active_beta[k]; // occupied state #k
911           auto col  = PsiT_MO[1].non_zero_indices2_data(ki);
912           auto val  = PsiT_MO[1].non_zero_values_data(ki);
913           for (size_t ic = 0, icend = PsiT_MO[1].num_non_zero_elements(ki); ic < icend; ic++, ++col, ++val)
914             PsiT[1].emplace_back({k, *col}, *val);
915         }
916       }
917     }
918     // now that mappings have been constructed, map indexes of excited state orbitals
919     // to the corresponding active space indexes
920     if (TGwfn.Node().root())
921     {
922       // map reference
923       auto refc = abij.reference_configuration();
924       for (int i = 0; i < NAEA + NAEB; i++, ++refc)
925         *refc = mo2active[*refc];
926       for (int n = 1; n < abij.maximum_excitation_number()[0]; n++)
927       {
928         auto it  = abij.alpha_begin(n);
929         auto ite = abij.alpha_end(n);
930         for (; it < ite; ++it)
931         {
932           auto exct = (*it) + n; // only need to map excited state indexes
933           for (int np = 0; np < n; ++np, ++exct)
934             *exct = mo2active[*exct];
935         }
936       }
937       for (int n = 1; n < abij.maximum_excitation_number()[1]; n++)
938       {
939         auto it  = abij.beta_begin(n);
940         auto ite = abij.beta_end(n);
941         for (; it < ite; ++it)
942         {
943           auto exct = (*it) + n; // only need to map excited state indexes
944           for (int np = 0; np < n; ++np, ++exct)
945             *exct = mo2active[*exct];
946         }
947       }
948     }
949 
950     // is PureSD actually faster??? CHECK!!!
951     // NOTE: For UHF reference, treat HOps as a 2 determinant wavefunction of a
952     //        CLOSED walker type. This way you can treat alpha/beta sectors independently in
953     //        HOps through the index corresponding 0/1.
954     // never add coulomb to half rotated v2 tensor in PHMSD
955     getInitialGuess(dump, name, NMO, NAEA, NAEB, walker_type);
956 
957     TGwfn.node_barrier();
958     auto HOps(getHamOps(restart_file, CLOSED, NMO, NAEA, NAEB, PsiT,
959       TGprop, TGwfn, cutvn, cutv2, false, h));
960     TGwfn.node_barrier();
961     // setup configuration couplings
962     using index_aos = ma::sparse::array_of_sequences<int, int, shared_allocator<int>, ma::sparse::is_root>;
963     shared_allocator<int> alloc_{TGwfn.Node()};
964 
965     // alpha
966     std::vector<int> counts_alpha(abij.number_of_unique_excitations()[0]);
967     std::vector<int> counts_beta(abij.number_of_unique_excitations()[1]);
968     if (TGwfn.Node().root())
969     {
970       for (auto it = abij.configurations_begin(); it < abij.configurations_end(); ++it)
971       {
972         ++counts_alpha[std::get<0>(*it)];
973         ++counts_beta[std::get<1>(*it)];
974       }
975     }
976     TGwfn.Node().broadcast_n(counts_alpha.begin(), counts_alpha.size());
977     TGwfn.Node().broadcast_n(counts_beta.begin(), counts_beta.size());
978     index_aos beta_coupled_to_unique_alpha(counts_alpha.size(), counts_alpha, alloc_);
979     index_aos alpha_coupled_to_unique_beta(counts_beta.size(), counts_beta, alloc_);
980     if (TGwfn.Node().root())
981     {
982       int ni = 0;
983       for (auto it = abij.configurations_begin(); it < abij.configurations_end(); ++it, ++ni)
984       {
985         beta_coupled_to_unique_alpha.emplace_back(std::get<0>(*it), ni);
986         alpha_coupled_to_unique_beta.emplace_back(std::get<1>(*it), ni);
987       }
988     }
989     TGwfn.Node().barrier();
990 
991     return Wavefunction(PHMSD(AFinfo, cur, TGwfn, std::move(HOps), std::move(acta2mo), std::move(actb2mo),
992                               std::move(abij), std::move(beta_coupled_to_unique_alpha),
993                               std::move(alpha_coupled_to_unique_beta), std::move(PsiT), walker_type, NCE, targetNW));
994     app_error() << " Error: Wavefunction type PHMSD not yet implemented. \n";
995     APP_ABORT(" Error: Wavefunction type PHMSD not yet implemented. \n");
996     return Wavefunction();
997   }
998   else if (type == "generalmsd")
999   {
1000     app_error() << " Error: Wavefunction type GeneralMSD not yet implemented. \n";
1001     APP_ABORT(" Error: Wavefunction type GeneralMSD not yet implemented. \n");
1002     return Wavefunction{};
1003   }
1004   else
1005   {
1006     app_error() << " Error: Unknown wave-function type: " << type << std::endl;
1007     APP_ABORT(" Error: Unknown wave-function type. \n");
1008     return Wavefunction{};
1009   }
1010 }
1011 
1012 /*
1013  * Read Initial walker from file.
1014 */
getInitialGuess(hdf_archive & dump,std::string & name,int NMO,int NAEA,int NAEB,WALKER_TYPES walker_type)1015 void WavefunctionFactory::getInitialGuess(hdf_archive& dump,
1016                                           std::string& name,
1017                                           int NMO,
1018                                           int NAEA,
1019                                           int NAEB,
1020                                           WALKER_TYPES walker_type)
1021 {
1022   int NPOL = (walker_type == NONCOLLINEAR) ? 2 : 1;
1023   std::vector<int> dims(5);
1024   if (!dump.readEntry(dims, "dims"))
1025   {
1026     app_error() << " Error in getCommonInput(): Problems reading dims. \n";
1027     APP_ABORT("");
1028   }
1029   WALKER_TYPES wtype(initWALKER_TYPES(dims[3]));
1030   auto guess = initial_guess.find(name);
1031   if (guess == initial_guess.end())
1032   {
1033     auto newg = initial_guess.insert(std::make_pair(name, boost::multi::array<ComplexType, 3>({2, NPOL * NMO, NAEA})));
1034     if (!newg.second)
1035       APP_ABORT(" Error: Problems adding new initial guess. \n");
1036     using ma::conj;
1037     std::fill_n((newg.first)->second.origin(), 2 * NPOL * NMO * NAEA, ComplexType(0.0, 0.0));
1038     {
1039       boost::multi::array<ComplexType, 2> Psi0Alpha({NPOL * NMO, NAEA});
1040       if (!dump.readEntry(Psi0Alpha, "Psi0_alpha"))
1041       {
1042         app_error() << " Error in WavefunctionFactory: Initial wavefunction Psi0_alpha not found. \n";
1043         APP_ABORT("");
1044       }
1045       for (int i = 0; i < NPOL * NMO; i++)
1046         for (int j = 0; j < NAEA; j++)
1047           ((newg.first)->second)[0][i][j] = Psi0Alpha[i][j];
1048     }
1049     if (walker_type == COLLINEAR)
1050     {
1051       if (wtype == COLLINEAR)
1052       {
1053         boost::multi::array<ComplexType, 2> Psi0Beta({NMO, NAEB});
1054         if (!dump.readEntry(Psi0Beta, "Psi0_beta"))
1055         {
1056           app_error() << " Error in WavefunctionFactory: Initial wavefunction Psi0_beta not found. \n";
1057           APP_ABORT("");
1058         }
1059         for (int i = 0; i < NMO; i++)
1060           for (int j = 0; j < NAEB; j++)
1061             ((newg.first)->second)[1][i][j] = Psi0Beta[i][j];
1062       }
1063       else if (wtype == CLOSED)
1064       {
1065         boost::multi::array<ComplexType, 2> Psi0Beta({NMO, NAEA});
1066         assert(NAEA == NAEB);
1067         if (!dump.readEntry(Psi0Beta, "Psi0_alpha"))
1068         {
1069           app_error() << " Error in WavefunctionFactory: Initial wavefunction Psi0_beta not found. \n";
1070           APP_ABORT("");
1071         }
1072         for (int i = 0; i < NMO; i++)
1073           for (int j = 0; j < NAEB; j++)
1074             ((newg.first)->second)[1][i][j] = Psi0Beta[i][j];
1075       }
1076       else
1077         APP_ABORT(" Error: Unknown wtype. \n");
1078     }
1079   }
1080   else
1081     APP_ABORT(" Error: Problems adding new initial guess, already exists. \n");
1082 }
1083 
1084 
computeVariationalEnergyPHMSD(TaskGroup_ & TG,Hamiltonian & ham,boost::multi::array_ref<int,2> & occs,std::vector<ComplexType> & coeff,int ndets,int NAEA,int NAEB,int NMO,bool recompute_ci)1085 void WavefunctionFactory::computeVariationalEnergyPHMSD(TaskGroup_& TG,
1086                                                         Hamiltonian& ham,
1087                                                         boost::multi::array_ref<int, 2>& occs,
1088                                                         std::vector<ComplexType>& coeff,
1089                                                         int ndets,
1090                                                         int NAEA,
1091                                                         int NAEB,
1092                                                         int NMO,
1093                                                         bool recompute_ci)
1094 {
1095   // CI coefficients can in general be complex and want to avoid two mpi communications so
1096   // keep everything complex even if Hamiltonian matrix elements are real.
1097   // Allocate H in Node's shared memory, but use as a raw array with proper synchronization
1098   int dim((recompute_ci ? ndets : 0));
1099   boost::multi::array<ComplexType, 2, shared_allocator<ComplexType>> H({dim, dim}, TG.Node());
1100   boost::multi::array<ComplexType, 1> energy(iextensions<1u>{2});
1101   using std::fill_n;
1102   fill_n(H.origin(), H.num_elements(), ComplexType(0.0));           // this call synchronizes
1103   fill_n(energy.origin(), energy.num_elements(), ComplexType(0.0)); // this call synchronizes
1104   ValueType enuc = ham.getNuclearCoulombEnergy();
1105   for (int idet = 0; idet < ndets; idet++)
1106   {
1107     // These should already be sorted.
1108     boost::multi::array_ref<int, 1> deti(occs[idet].origin(), {NAEA + NAEB});
1109     ComplexType cidet = coeff[idet];
1110     for (int jdet = idet; jdet < ndets; jdet++)
1111     {
1112       // Compute <Di|H|Dj>
1113       if ((idet * ndets + jdet) % TG.Global().size() == TG.Global().rank())
1114       {
1115         if (idet == jdet)
1116         {
1117           ComplexType Hii(0.0);
1118           Hii = slaterCondon0(ham, deti, NMO) + enuc;
1119           energy[0] += ma::conj(cidet) * cidet * Hii;
1120           energy[1] += ma::conj(cidet) * cidet;
1121           if (recompute_ci)
1122             H[idet][idet] = Hii;
1123         }
1124         else
1125         {
1126           ComplexType Hij(0.0);
1127           boost::multi::array_ref<int, 1> detj(occs[jdet].origin(), {NAEA + NAEB});
1128           ComplexType cjdet = coeff[jdet];
1129           int perm          = 1;
1130           std::vector<int> excit;
1131           int nexcit = getExcitation(deti, detj, excit, perm);
1132           if (nexcit == 1)
1133           {
1134             Hij = ComplexType(perm) * slaterCondon1(ham, excit, detj, NMO);
1135           }
1136           else if (nexcit == 2)
1137           {
1138             Hij = ComplexType(perm) * slaterCondon2(ham, excit, NMO);
1139           }
1140           energy[0] += ma::conj(cidet) * cjdet * Hij + ma::conj(cjdet) * cidet * ma::conj(Hij);
1141           if (recompute_ci)
1142           {
1143             H[idet][jdet] = Hij;
1144             H[jdet][idet] = ma::conj(Hij);
1145           }
1146         }
1147       }
1148     }
1149   }
1150   TG.Node().barrier();
1151   if (TG.Node().root() && recompute_ci)
1152     TG.Cores().all_reduce_in_place_n(to_address(H.origin()), H.num_elements(), std::plus<>());
1153   TG.Global().all_reduce_in_place_n(energy.origin(), 2, std::plus<>());
1154   app_log() << " - Variational energy of trial wavefunction: " << std::setprecision(16) << energy[0] / energy[1]
1155             << "\n";
1156   if (recompute_ci)
1157   {
1158     app_log() << " - Diagonalizing CI matrix.\n";
1159     using RVector = boost::multi::array<RealType, 1>;
1160     using CMatrix = boost::multi::array<ComplexType, 2>;
1161     // Want a "unique" solution for all cores/nodes.
1162     if (TG.Global().rank() == 0)
1163     {
1164       std::pair<RVector, CMatrix> Sol = ma::symEigSelect<RVector, CMatrix>(H, 1);
1165       app_log() << " - Updating CI coefficients. \n";
1166       app_log() << " - Recomputed coe  // only makes Sparse ham. 2e rotation more effiecientfficient of first determinant: " << Sol.second[0][0] << "\n";
1167       for (int idet = 0; idet < ndets; idet++)
1168       {
1169         ComplexType ci = Sol.second[0][idet];
1170         // Do we want this much output?
1171         //app_log() << idet << " old: " << coeff[idet] << " new: " << ci << "\n";
1172         coeff[idet] = ci;
1173       }
1174       app_log() << " - Recomputed variational energy of trial wavefunction: " << Sol.first[0] << "\n";
1175     }
1176     TG.Global().broadcast_n(to_address(coeff.data()), coeff.size(), 0);
1177   }
1178 }
1179 /*
1180  * Helper function to get HamOps object from file or from scratch.
1181 */
getHamOps(const std::string & restart_file,WALKER_TYPES type,int NMO,int NAEA,int NAEB,std::vector<PsiT_Matrix> & PsiT,TaskGroup_ & TGprop,TaskGroup_ & TGwfn,RealType cutvn,RealType cutv2,int ndets_to_read,Hamiltonian & h)1182 HamiltonianOperations WavefunctionFactory::getHamOps(const std::string& restart_file,
1183                                                      WALKER_TYPES type,
1184                                                      int NMO,
1185                                                      int NAEA,
1186                                                      int NAEB,
1187                                                      std::vector<PsiT_Matrix>& PsiT,
1188                                                      TaskGroup_& TGprop,
1189                                                      TaskGroup_& TGwfn,
1190                                                      RealType cutvn,
1191                                                      RealType cutv2,
1192                                                      int ndets_to_read,
1193                                                      Hamiltonian& h)
1194 {
1195   // if requested, create restart file
1196   // Will use phdf5 in the future, for now only head node writes
1197   hdf_archive restart(TGwfn.Global());
1198   if (restart_file != "")
1199   {
1200     if (TGwfn.Global().root())
1201     {
1202       app_log() << " Open " << restart_file << " for HamOps\n";
1203       // first, try open existing restart file
1204       if (!restart.open(restart_file, H5F_ACC_RDONLY))
1205       { // make new restart file if cannot open existing
1206         app_log() << " No restart_file create anew.\n";
1207         if (!restart.create(restart_file, H5F_ACC_EXCL))
1208         {
1209           app_error() << " Error in WavefunctionFactory: Failed to create restart_file" << restart_file << "\n";
1210           APP_ABORT("");
1211         }
1212       }
1213     }
1214   }
1215 
1216   bool read = restart.is_group("HamiltonianOperations");
1217   if (read)
1218   {
1219     app_log() << " getHamOps using restart file\n";
1220     return loadHamOps(restart, type, NMO, NAEA, NAEB, PsiT, TGprop, TGwfn, cutvn, cutv2);
1221   }
1222   else
1223   {
1224     app_log() << " getHamOps from scratch\n";
1225     bool pureSD = false;  // make Sparse ham. 2e rotation more effiecient
1226     // pureSD only matters during setup of a large run. Avoid Sparse in that case.
1227     return h.getHamiltonianOperations(pureSD, ndets_to_read > 1, type, PsiT, cutvn, cutv2, TGprop, TGwfn, restart);
1228   }
1229 
1230 //  if(restart_file != "")
1231 //  {
1232 //    if(TGwfn.Global().root()) {
1233 //      restart.close();
1234 //    }
1235 //  }
1236 }
1237 /**
1238  * Compute the excitation level between two determinants.
1239  */
getExcitation(boost::multi::array_ref<int,1> & deti,boost::multi::array_ref<int,1> & detj,std::vector<int> & excit,int & perm)1240 int WavefunctionFactory::getExcitation(boost::multi::array_ref<int, 1>& deti,
1241                                        boost::multi::array_ref<int, 1>& detj,
1242                                        std::vector<int>& excit,
1243                                        int& perm)
1244 {
1245   std::vector<int> from_orb, to_orb;
1246   // Work out which orbitals are excited from / to.
1247   std::set_difference(detj.begin(), detj.end(), deti.begin(), deti.end(), std::inserter(from_orb, from_orb.begin()));
1248   std::set_difference(deti.begin(), deti.end(), detj.begin(), detj.end(), std::inserter(to_orb, to_orb.begin()));
1249   int nexcit = from_orb.size();
1250   if (nexcit <= 2)
1251   {
1252     for (int i = 0; i < from_orb.size(); i++)
1253       excit.push_back(from_orb[i]);
1254     for (int i = 0; i < to_orb.size(); i++)
1255       excit.push_back(to_orb[i]);
1256     int nperm = 0;
1257     int nmove = 0;
1258     for (auto o : from_orb)
1259     {
1260       auto it = std::find(detj.begin(), detj.end(), o);
1261       int loc = std::distance(detj.begin(), it);
1262       nperm += loc - nmove;
1263       nmove += 1;
1264     }
1265     nmove = 0;
1266     for (auto o : to_orb)
1267     {
1268       auto it = std::find(deti.begin(), deti.end(), o);
1269       int loc = std::distance(deti.begin(), it);
1270       nperm += loc - nmove;
1271       nmove += 1;
1272     }
1273     perm = nperm % 2 == 1 ? -1 : 1;
1274   }
1275   return nexcit;
1276 }
1277 
slaterCondon0(Hamiltonian & ham,boost::multi::array_ref<int,1> & det,int NMO)1278 ComplexType WavefunctionFactory::slaterCondon0(Hamiltonian& ham, boost::multi::array_ref<int, 1>& det, int NMO)
1279 {
1280   ValueType one_body = ValueType(0.0);
1281   ValueType two_body = ValueType(0.0);
1282   for (int i = 0; i < det.size(); i++)
1283   {
1284     int oi = det[i];
1285     one_body += ham.H(oi, oi);
1286     for (int j = i + 1; j < det.size(); j++)
1287     {
1288       int oj = det[j];
1289       two_body += ham.H(oi, oj, oi, oj) - ham.H(oi, oj, oj, oi);
1290     }
1291   }
1292   return ComplexType(one_body + two_body);
1293 }
1294 
slaterCondon1(Hamiltonian & ham,std::vector<int> & excit,boost::multi::array_ref<int,1> & det,int NMO)1295 ComplexType WavefunctionFactory::slaterCondon1(Hamiltonian& ham,
1296                                                std::vector<int>& excit,
1297                                                boost::multi::array_ref<int, 1>& det,
1298                                                int NMO)
1299 {
1300   int i              = excit[0];
1301   int a              = excit[1];
1302   ValueType one_body = ham.H(i, a);
1303   ValueType two_body = ValueType(0.0);
1304   for (auto j : det)
1305   {
1306     two_body += ham.H(i, j, a, j) - ham.H(i, j, j, a);
1307   }
1308   return ComplexType(one_body + two_body);
1309 }
1310 
slaterCondon2(Hamiltonian & ham,std::vector<int> & excit,int NMO)1311 ComplexType WavefunctionFactory::slaterCondon2(Hamiltonian& ham, std::vector<int>& excit, int NMO)
1312 {
1313   int i = excit[0];
1314   int j = excit[1];
1315   int a = excit[2];
1316   int b = excit[3];
1317   return ComplexType(ham.H(i, j, a, b) - ham.H(i, j, b, a));
1318 }
1319 
1320 //ComplexType WavefunctionFactory::contractOneBody(std::vector<int>& det, std::vector<int>& excit, boost::multi::array_ref<ComplexType,2>& HSPot, int NMO)
1321 //{
1322 //ComplexType oneBody = ComplexType(0.0);
1323 //int spini, spina;
1324 //if(excit.size()==0) {
1325 //for(auto i : det) {
1326 //int oi = decodeSpinOrbital(i, spini, NMO);
1327 //oneBody += HSPot[oi][oi];
1328 //}
1329 //} else {
1330 //int oi = decodeSpinOrbital(excit[0], spini, NMO);
1331 //int oa = decodeSpinOrbital(excit[1], spina, NMO);
1332 //oneBody = HSPot[oi][oa];
1333 //}
1334 //return oneBody;
1335 //}
1336 
1337 
1338 } // namespace afqmc
1339 } // namespace qmcplusplus
1340