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 #ifndef QMCPLUSPLUS_AFQMC_WALKERSETUPDATES_HPP
17 #define QMCPLUSPLUS_AFQMC_WALKERSETUPDATES_HPP
18 
19 #include <algorithm>
20 
21 #include "Configuration.h"
22 #include "AFQMC/config.h"
23 #include "AFQMC/Numerics/ma_blas.hpp"
24 #include "AFQMC/Walkers/WalkerConfig.hpp"
25 
26 namespace qmcplusplus
27 {
28 namespace afqmc
29 {
30 template<class Wlk, class OMat, class Mat, class WMat>
free_projection_walker_update(Wlk && w,RealType dt,OMat && overlap,Mat && MFfactor,RealType Eshift,Mat && hybrid_weight,WMat & work)31 void free_projection_walker_update(Wlk&& w,
32                                    RealType dt,
33                                    OMat&& overlap,
34                                    Mat&& MFfactor,
35                                    RealType Eshift,
36                                    Mat&& hybrid_weight,
37                                    WMat& work)
38 {
39   int nwalk = w.size();
40   // constexpr if can be used to avoid the memory copy, by comparing the pointer types
41   // between WMat and Mat/OMat
42   if (work.size(0) < 7 || work.size(1) < nwalk)
43     work.reextent({7, nwalk});
44 
45   w.getProperty(WEIGHT, work[0]);
46   w.getProperty(PHASE, work[1]);
47   w.getProperty(PSEUDO_ELOC_, work[2]);
48   w.getProperty(OVLP, work[3]);
49   using std::copy_n;
50   copy_n(overlap.origin(), nwalk, work[4].origin());
51   copy_n(MFfactor.origin(), nwalk, work[5].origin());
52   copy_n(hybrid_weight.origin(), nwalk, work[6].origin());
53 
54   for (int i = 0; i < nwalk; i++)
55   {
56     ComplexType old_ovlp = work[3][i];
57     ComplexType old_eloc = work[2][i];
58     ComplexType eloc;
59     ComplexType ratioOverlaps = ComplexType(1.0, 0.0);
60     eloc                      = work[5][i] / dt;
61     ComplexType factor        = std::exp(-dt * (0.5 * (eloc + old_eloc) - Eshift));
62     work[0][i] *= std::abs(factor);
63     work[1][i] *= factor / std::abs(factor);
64     work[2][i] = eloc;
65     work[3][i] = work[4][i];
66   }
67 
68   w.setProperty(WEIGHT, work[0]);
69   w.setProperty(PHASE, work[1]);
70   w.setProperty(PSEUDO_ELOC_, work[2]);
71   w.setProperty(OVLP, work[3]);
72 }
73 
74 template<class Wlk, class OMat, class Mat, class WMat>
hybrid_walker_update(Wlk && w,RealType dt,bool apply_constrain,bool imp_sampl,RealType Eshift,OMat && overlap,Mat && MFfactor,Mat && hybrid_weight,WMat & work)75 void hybrid_walker_update(Wlk&& w,
76                           RealType dt,
77                           bool apply_constrain,
78                           bool imp_sampl,
79                           RealType Eshift,
80                           OMat&& overlap,
81                           Mat&& MFfactor,
82                           Mat&& hybrid_weight,
83                           WMat& work)
84 {
85   int nwalk = w.size();
86   // constexpr if can be used to avoid the memory copy, by comparing the pointer types
87   // between WMat and Mat/OMat
88   if (work.size(0) < 7 || work.size(1) < nwalk)
89     work.reextent({7, nwalk});
90 
91   bool BackProp = (w.getBPPos() >= 0 && w.getBPPos() < w.NumBackProp());
92 
93   w.getProperty(WEIGHT, work[0]);
94   w.getProperty(PSEUDO_ELOC_, work[1]);
95   w.getProperty(OVLP, work[2]);
96   using std::copy_n;
97   copy_n(overlap.origin(), nwalk, work[4].origin());
98   copy_n(MFfactor.origin(), nwalk, work[5].origin());
99   copy_n(hybrid_weight.origin(), nwalk, work[6].origin());
100 
101   for (int i = 0; i < nwalk; i++)
102   {
103     ComplexType old_ovlp = work[2][i];
104     ComplexType old_eloc = work[1][i];
105     ComplexType eloc;
106     RealType scale            = 1.0;
107     ComplexType ratioOverlaps = ComplexType(1.0, 0.0);
108 
109     if (imp_sampl)
110       ratioOverlaps = work[4][i] / old_ovlp;
111     if (!std::isfinite(ratioOverlaps.real()) && apply_constrain && imp_sampl)
112     {
113       scale = 0.0;
114       eloc  = old_eloc;
115     }
116     else
117     {
118       scale = (apply_constrain ? (std::max(0.0, std::cos(std::arg(ratioOverlaps) - work[5][i].imag()))) : 1.0);
119       if (imp_sampl)
120         eloc = (work[5][i] - work[6][i] - std::log(ratioOverlaps)) / dt;
121       else
122         eloc = work[5][i] / dt;
123     }
124     ComplexType eloc_ = eloc;
125 
126     if ((!std::isfinite(eloc.real())) || (std::abs(eloc.real()) < std::numeric_limits<RealType>::min()))
127     {
128       scale = 0.0;
129       eloc  = old_eloc;
130     }
131     else
132     {
133       eloc = ComplexType(std::max(std::min(eloc.real(), Eshift + std::sqrt(2.0 / dt)), Eshift - std::sqrt(2.0 / dt)),
134                          eloc.imag());
135     }
136 //#define __AFQMC_DEBUG_VERBOSE__
137 #if defined(__AFQMC_DEBUG_VERBOSE__)
138     std::cout << " update: "
139               << "    eloc:          " << eloc << "\n"
140               << "    eloc_:         " << eloc_ << "\n"
141               << "    ov:            " << work[4][i] << "\n"
142               << "    old_ov:        " << old_ovlp << "\n"
143               << "    ratio:         " << ratioOverlaps << "\n"
144               << "    MFfactor:      " << work[5][i] << "\n"
145               << "    hybrid_weight: " << work[6][i] << "\n"
146               << "    scale:         " << scale << "\n"
147               << std::endl;
148 #endif
149 
150     work[0][i] *= ComplexType(scale * std::exp(-dt * (0.5 * (eloc.real() + old_eloc.real()) - Eshift)), 0.0);
151     work[1][i] = eloc;
152     work[2][i] = work[4][i];
153     work[3][i] = std::exp(-ComplexType(0.0, dt) * (0.5 * (eloc.imag() + old_eloc.imag()))) / scale;
154   }
155   w.setProperty(WEIGHT, work[0]);
156   w.setProperty(PSEUDO_ELOC_, work[1]);
157   w.setProperty(OVLP, work[2]);
158   if (BackProp)
159   {
160     auto&& WFac((*w.getWeightFactors())[w.getHistoryPos()]);
161     using std::copy_n;
162     copy_n(work[3].origin(), nwalk, WFac.origin());
163     auto&& WHis((*w.getWeightHistory())[w.getHistoryPos()]);
164     copy_n(work[0].origin(), nwalk, WHis.origin());
165   }
166 }
167 
168 template<class Wlk, class EMat, class OMat, class Mat, class WMat>
local_energy_walker_update(Wlk && w,RealType dt,bool apply_constrain,RealType Eshift,OMat && overlap,EMat && energies,Mat && MFfactor,Mat && hybrid_weight,WMat & work)169 void local_energy_walker_update(Wlk&& w,
170                                 RealType dt,
171                                 bool apply_constrain,
172                                 RealType Eshift,
173                                 OMat&& overlap,
174                                 EMat&& energies,
175                                 Mat&& MFfactor,
176                                 Mat&& hybrid_weight,
177                                 WMat& work)
178 {
179   int nwalk = w.size();
180   // constexpr if can be used to avoid the memory copy, by comparing the pointer types
181   // between WMat and Mat/OMat
182   if (work.size(0) < 12 || work.size(1) < nwalk)
183     work.reextent({12, nwalk});
184 
185   bool BackProp = (w.getBPPos() >= 0 && w.getBPPos() < w.NumBackProp());
186 
187   w.getProperty(WEIGHT, work[0]);
188   w.getProperty(PSEUDO_ELOC_, work[1]);
189   w.getProperty(OVLP, work[2]);
190   w.getProperty(E1_, work[3]);
191   w.getProperty(EXX_, work[4]);
192   w.getProperty(EJ_, work[5]);
193   using std::copy_n;
194   copy_n(overlap.origin(), nwalk, work[7].origin());
195   copy_n(MFfactor.origin(), nwalk, work[8].origin());
196   ma::copy(energies({0, nwalk}, 0), work[9]);
197   ma::copy(energies({0, nwalk}, 1), work[10]);
198   ma::copy(energies({0, nwalk}, 2), work[11]);
199 
200   for (int i = 0; i < nwalk; i++)
201   {
202     ComplexType old_ovlp      = work[2][i];
203     ComplexType old_eloc      = work[1][i];
204     ComplexType eloc          = work[9][i] + work[10][i] + work[11][i];
205     RealType scale            = 1.0;
206     ComplexType ratioOverlaps = work[7][i] / old_ovlp;
207 
208     if (!std::isfinite((ratioOverlaps * work[8][i]).real()) && apply_constrain)
209     {
210       scale = 0.0;
211       eloc  = old_eloc;
212     }
213     else
214       scale = (apply_constrain ? (std::max(0.0, std::cos(std::arg(ratioOverlaps) - work[8][i].imag()))) : 1.0);
215 
216     if ((!std::isfinite(eloc.real())) || (std::abs(eloc.real()) < std::numeric_limits<RealType>::min()))
217     {
218       scale = 0.0;
219       eloc  = old_eloc;
220     }
221     else
222     {
223       eloc = ComplexType(std::max(std::min(eloc.real(), Eshift + std::sqrt(2.0 / dt)), Eshift - std::sqrt(2.0 / dt)),
224                          eloc.imag());
225     }
226 
227     work[0][i] *= ComplexType(scale * std::exp(-dt * (0.5 * (eloc.real() + old_eloc.real()) - Eshift)), 0.0);
228     work[6][i] = std::exp(-ComplexType(0.0, dt) * (0.5 * (eloc.imag() + old_eloc.imag()))) / scale;
229     work[1][i] = eloc;
230     work[2][i] = work[7][i];
231     work[3][i] = work[9][i];
232     work[4][i] = work[10][i];
233     work[5][i] = work[11][i];
234   }
235 
236   w.setProperty(WEIGHT, work[0]);
237   w.setProperty(PSEUDO_ELOC_, work[1]);
238   w.setProperty(OVLP, work[2]);
239   w.setProperty(E1_, work[3]);
240   w.setProperty(EXX_, work[4]);
241   w.setProperty(EJ_, work[5]);
242   if (BackProp)
243   {
244     auto&& WFac((*w.getWeightFactors())[w.getHistoryPos()]);
245     using std::copy_n;
246     copy_n(work[6].origin(), nwalk, WFac.origin());
247     auto&& WHis((*w.getWeightHistory())[w.getHistoryPos()]);
248     copy_n(work[0].origin(), nwalk, WHis.origin());
249   }
250 }
251 
252 } // namespace afqmc
253 
254 } // namespace qmcplusplus
255 
256 #endif
257