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