1 // See LICENSE file in top directory for details.
2 //
3 // Copyright (c) 2020 QMCPACK developers.
4 //
5 // File developed by: Bryan Clark, bclark@Princeton.edu, Princeton University
6 // Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
7 // Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 // Raymond Clay III, j.k.rofling@gmail.com, Lawrence Livermore National Laboratory
11 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
12 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
13 // Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
14 //
15 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
16 //////////////////////////////////////////////////////////////////////////////////////
17
18 #include "DiracDeterminant.h"
19 #include <stdexcept>
20 #include "CPU/BLAS.hpp"
21 #include "CPU/SIMD/simd.hpp"
22 #include "Numerics/DeterminantOperators.h"
23 #include "Numerics/MatrixOperators.h"
24
25 namespace qmcplusplus
26 {
27 /** constructor
28 *@param spos the single-particle orbital set
29 *@param first index of the first particle
30 */
31 template<typename DU_TYPE>
DiracDeterminant(std::shared_ptr<SPOSet> && spos,int first)32 DiracDeterminant<DU_TYPE>::DiracDeterminant(std::shared_ptr<SPOSet>&& spos, int first)
33 : DiracDeterminantBase("DiracDeterminant", std::move(spos), first), ndelay(1), invRow_id(-1)
34 {}
35
36 /** set the index of the first particle in the determinant and reset the size of the determinant
37 *@param first index of first particle
38 *@param nel number of particles in the determinant
39 */
40 template<typename DU_TYPE>
set(int first,int nel,int delay)41 void DiracDeterminant<DU_TYPE>::set(int first, int nel, int delay)
42 {
43 FirstIndex = first;
44 ndelay = delay;
45
46 resize(nel, nel);
47
48 if (Optimizable)
49 Phi->buildOptVariables(nel);
50
51 if (Phi->getOrbitalSetSize() < nel)
52 {
53 std::ostringstream err_msg;
54 err_msg << "The SPOSet " << Phi->getName() << " only has " << Phi->getOrbitalSetSize() << " orbitals "
55 << "but this determinant needs at least " << nel << std::endl;
56 throw std::runtime_error(err_msg.str());
57 }
58 }
59
60 template<typename DU_TYPE>
invertPsiM(const ValueMatrix_t & logdetT,ValueMatrix_t & invMat)61 void DiracDeterminant<DU_TYPE>::invertPsiM(const ValueMatrix_t& logdetT, ValueMatrix_t& invMat)
62 {
63 ScopedTimer local_timer(InverseTimer);
64 updateEng.invert_transpose(logdetT, invMat, LogValue);
65 }
66
67
68 ///reset the size: with the number of particles and number of orbtials
69 template<typename DU_TYPE>
resize(int nel,int morb)70 void DiracDeterminant<DU_TYPE>::resize(int nel, int morb)
71 {
72 if (Bytes_in_WFBuffer > 0)
73 throw std::runtime_error("DiracDeterimnant just went out of sync with buffer");
74 int norb = morb;
75 if (norb <= 0)
76 norb = nel; // for morb == -1 (default)
77 updateEng.resize(norb, ndelay);
78 psiM.resize(nel, norb);
79 dpsiM.resize(nel, norb);
80 d2psiM.resize(nel, norb);
81 psiV.resize(norb);
82 invRow.resize(norb);
83 psiM_temp.resize(nel, norb);
84 LastIndex = FirstIndex + nel;
85 NumPtcls = nel;
86 NumOrbitals = norb;
87
88 dpsiV.resize(NumOrbitals);
89 dspin_psiV.resize(NumOrbitals);
90 d2psiV.resize(NumOrbitals);
91 FirstAddressOfdV = &(dpsiM(0, 0)[0]); //(*dpsiM.begin())[0]);
92 LastAddressOfdV = FirstAddressOfdV + NumPtcls * NumOrbitals * DIM;
93 }
94
95 template<typename DU_TYPE>
evalGrad(ParticleSet & P,int iat)96 typename DiracDeterminant<DU_TYPE>::GradType DiracDeterminant<DU_TYPE>::evalGrad(ParticleSet& P, int iat)
97 {
98 ScopedTimer local_timer(RatioTimer);
99 const int WorkingIndex = iat - FirstIndex;
100 assert(WorkingIndex >= 0);
101 invRow_id = WorkingIndex;
102 updateEng.getInvRow(psiM, WorkingIndex, invRow);
103 GradType g = simd::dot(invRow.data(), dpsiM[WorkingIndex], invRow.size());
104 assert(checkG(g));
105 return g;
106 }
107
108 template<typename DU_TYPE>
evalGradWithSpin(ParticleSet & P,int iat,ComplexType & spingrad)109 typename DiracDeterminant<DU_TYPE>::GradType DiracDeterminant<DU_TYPE>::evalGradWithSpin(ParticleSet& P,
110 int iat,
111 ComplexType& spingrad)
112 {
113 Phi->evaluate_spin(P, iat, psiV, dspin_psiV);
114 ScopedTimer local_timer(RatioTimer);
115 const int WorkingIndex = iat - FirstIndex;
116 assert(WorkingIndex >= 0);
117 invRow_id = WorkingIndex;
118 updateEng.getInvRow(psiM, WorkingIndex, invRow);
119 GradType g = simd::dot(invRow.data(), dpsiM[WorkingIndex], invRow.size());
120 ComplexType spin_g = simd::dot(invRow.data(), dspin_psiV.data(), invRow.size());
121 spingrad += spin_g;
122
123 return g;
124 }
125
126 template<typename DU_TYPE>
ratioGrad(ParticleSet & P,int iat,GradType & grad_iat)127 typename DiracDeterminant<DU_TYPE>::PsiValueType DiracDeterminant<DU_TYPE>::ratioGrad(ParticleSet& P,
128 int iat,
129 GradType& grad_iat)
130 {
131 {
132 ScopedTimer local_timer(SPOVGLTimer);
133 Phi->evaluateVGL(P, iat, psiV, dpsiV, d2psiV);
134 }
135 return ratioGrad_compute(iat, grad_iat);
136 }
137
138 template<typename DU_TYPE>
ratioGrad_compute(int iat,GradType & grad_iat)139 typename DiracDeterminant<DU_TYPE>::PsiValueType DiracDeterminant<DU_TYPE>::ratioGrad_compute(int iat,
140 GradType& grad_iat)
141 {
142 ScopedTimer local_timer(RatioTimer);
143
144 UpdateMode = ORB_PBYP_PARTIAL;
145 const int WorkingIndex = iat - FirstIndex;
146 assert(WorkingIndex >= 0);
147 // This is an satefy mechanism.
148 // check invRow_id against WorkingIndex to see if getInvRow() has been called already
149 // when evalGrad has not been called already or the particle id is not consistent,
150 // invRow is recomputed.
151 if (invRow_id != WorkingIndex)
152 {
153 invRow_id = WorkingIndex;
154 updateEng.getInvRow(psiM, WorkingIndex, invRow);
155 }
156 curRatio = simd::dot(invRow.data(), psiV.data(), invRow.size());
157 grad_iat += static_cast<ValueType>(static_cast<PsiValueType>(1.0) / curRatio) *
158 simd::dot(invRow.data(), dpsiV.data(), invRow.size());
159 return curRatio;
160 }
161
162 template<typename DU_TYPE>
ratioGradWithSpin(ParticleSet & P,int iat,GradType & grad_iat,ComplexType & spingrad_iat)163 typename DiracDeterminant<DU_TYPE>::PsiValueType DiracDeterminant<DU_TYPE>::ratioGradWithSpin(ParticleSet& P,
164 int iat,
165 GradType& grad_iat,
166 ComplexType& spingrad_iat)
167 {
168 {
169 ScopedTimer local_timer(SPOVGLTimer);
170 Phi->evaluateVGL_spin(P, iat, psiV, dpsiV, d2psiV, dspin_psiV);
171 }
172
173 {
174 ScopedTimer local_timer(RatioTimer);
175 UpdateMode = ORB_PBYP_PARTIAL;
176 const int WorkingIndex = iat - FirstIndex;
177 assert(WorkingIndex >= 0);
178 // This is an optimization.
179 // check invRow_id against WorkingIndex to see if getInvRow() has been called already
180 // Some code paths call evalGrad before calling ratioGrad.
181 if (invRow_id != WorkingIndex)
182 {
183 invRow_id = WorkingIndex;
184 updateEng.getInvRow(psiM, WorkingIndex, invRow);
185 }
186 curRatio = simd::dot(invRow.data(), psiV.data(), invRow.size());
187 grad_iat += static_cast<ValueType>(static_cast<PsiValueType>(1.0) / curRatio) *
188 simd::dot(invRow.data(), dpsiV.data(), invRow.size());
189
190 spingrad_iat += static_cast<ValueType>(static_cast<PsiValueType>(1.0) / curRatio) *
191 simd::dot(invRow.data(), dspin_psiV.data(), invRow.size());
192 }
193
194 return curRatio;
195 }
196
197 template<typename DU_TYPE>
mw_ratioGrad(const RefVectorWithLeader<WaveFunctionComponent> & wfc_list,const RefVectorWithLeader<ParticleSet> & p_list,int iat,std::vector<PsiValueType> & ratios,std::vector<GradType> & grad_new) const198 void DiracDeterminant<DU_TYPE>::mw_ratioGrad(const RefVectorWithLeader<WaveFunctionComponent>& wfc_list,
199 const RefVectorWithLeader<ParticleSet>& p_list,
200 int iat,
201 std::vector<PsiValueType>& ratios,
202 std::vector<GradType>& grad_new) const
203 {
204 {
205 ScopedTimer local_timer(SPOVGLTimer);
206 RefVectorWithLeader<SPOSet> phi_list(*Phi);
207 phi_list.reserve(wfc_list.size());
208 RefVector<ValueVector_t> psi_v_list;
209 psi_v_list.reserve(wfc_list.size());
210 RefVector<GradVector_t> dpsi_v_list;
211 dpsi_v_list.reserve(wfc_list.size());
212 RefVector<ValueVector_t> d2psi_v_list;
213 d2psi_v_list.reserve(wfc_list.size());
214
215 for (WaveFunctionComponent& wfc : wfc_list)
216 {
217 auto& det = static_cast<DiracDeterminant<DU_TYPE>&>(wfc);
218 phi_list.push_back(*det.Phi);
219 psi_v_list.push_back(det.psiV);
220 dpsi_v_list.push_back(det.dpsiV);
221 d2psi_v_list.push_back(det.d2psiV);
222 }
223
224 Phi->mw_evaluateVGL(phi_list, p_list, iat, psi_v_list, dpsi_v_list, d2psi_v_list);
225 }
226
227 for (int iw = 0; iw < wfc_list.size(); iw++)
228 ratios[iw] = wfc_list.getCastedElement<DiracDeterminant<DU_TYPE>>(iw).ratioGrad_compute(iat, grad_new[iw]);
229 }
230
231
232 /** move was accepted, update the real container
233 */
234 template<typename DU_TYPE>
acceptMove(ParticleSet & P,int iat,bool safe_to_delay)235 void DiracDeterminant<DU_TYPE>::acceptMove(ParticleSet& P, int iat, bool safe_to_delay)
236 {
237 ScopedTimer local_timer(UpdateTimer);
238 const int WorkingIndex = iat - FirstIndex;
239 assert(WorkingIndex >= 0);
240 LogValue += convertValueToLog(curRatio);
241 updateEng.acceptRow(psiM, WorkingIndex, psiV, curRatio);
242 if (!safe_to_delay)
243 updateEng.updateInvMat(psiM);
244 // invRow becomes invalid after accepting a move
245 invRow_id = -1;
246 if (UpdateMode == ORB_PBYP_PARTIAL)
247 {
248 simd::copy(dpsiM[WorkingIndex], dpsiV.data(), NumOrbitals);
249 simd::copy(d2psiM[WorkingIndex], d2psiV.data(), NumOrbitals);
250 }
251 curRatio = 1.0;
252 }
253
254 /** move was rejected. copy the real container to the temporary to move on
255 */
256 template<typename DU_TYPE>
restore(int iat)257 void DiracDeterminant<DU_TYPE>::restore(int iat)
258 {
259 curRatio = 1.0;
260 }
261
262 template<typename DU_TYPE>
completeUpdates()263 void DiracDeterminant<DU_TYPE>::completeUpdates()
264 {
265 ScopedTimer local_timer(UpdateTimer);
266 // invRow becomes invalid after updating the inverse matrix
267 invRow_id = -1;
268 updateEng.updateInvMat(psiM);
269 }
270
271 template<typename DU_TYPE>
updateAfterSweep(const ParticleSet & P,ParticleSet::ParticleGradient_t & G,ParticleSet::ParticleLaplacian_t & L)272 void DiracDeterminant<DU_TYPE>::updateAfterSweep(const ParticleSet& P,
273 ParticleSet::ParticleGradient_t& G,
274 ParticleSet::ParticleLaplacian_t& L)
275 {
276 if (UpdateMode == ORB_PBYP_RATIO)
277 { //need to compute dpsiM and d2psiM. Do not touch psiM!
278 ScopedTimer local_timer(SPOVGLTimer);
279 Phi->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_temp, dpsiM, d2psiM);
280 }
281
282 if (NumPtcls == 1)
283 {
284 ValueType y = psiM(0, 0);
285 GradType rv = y * dpsiM(0, 0);
286 G[FirstIndex] += rv;
287 L[FirstIndex] += y * d2psiM(0, 0) - dot(rv, rv);
288 }
289 else
290 {
291 for (size_t i = 0, iat = FirstIndex; i < NumPtcls; ++i, ++iat)
292 {
293 mValueType dot_temp = simd::dot(psiM[i], d2psiM[i], NumOrbitals);
294 mGradType rv = simd::dot(psiM[i], dpsiM[i], NumOrbitals);
295 G[iat] += rv;
296 L[iat] += dot_temp - dot(rv, rv);
297 }
298 }
299 }
300
301 template<typename DU_TYPE>
registerData(ParticleSet & P,WFBufferType & buf)302 void DiracDeterminant<DU_TYPE>::registerData(ParticleSet& P, WFBufferType& buf)
303 {
304 if (Bytes_in_WFBuffer == 0)
305 {
306 //add the data: inverse, gradient and laplacian
307 Bytes_in_WFBuffer = buf.current();
308 buf.add(psiM.first_address(), psiM.last_address());
309 buf.add(FirstAddressOfdV, LastAddressOfdV);
310 buf.add(d2psiM.first_address(), d2psiM.last_address());
311 Bytes_in_WFBuffer = buf.current() - Bytes_in_WFBuffer;
312 // free local space
313 psiM.free();
314 dpsiM.free();
315 d2psiM.free();
316 }
317 else
318 {
319 buf.forward(Bytes_in_WFBuffer);
320 #ifndef NDEBUG
321 // this causes too much output in the legacy code.
322 // \todo turn this back on after legacy is dropped,
323 // I don't think it should print at all in the new design
324 // std::cerr << ("You really should know whether you have registered this objects data previously!, consider this an error in the unified code");
325 #endif
326 }
327 buf.add(LogValue);
328 }
329
330 template<typename DU_TYPE>
evaluateGL(const ParticleSet & P,ParticleSet::ParticleGradient_t & G,ParticleSet::ParticleLaplacian_t & L,bool fromscratch)331 typename DiracDeterminant<DU_TYPE>::LogValueType DiracDeterminant<DU_TYPE>::evaluateGL(
332 const ParticleSet& P,
333 ParticleSet::ParticleGradient_t& G,
334 ParticleSet::ParticleLaplacian_t& L,
335 bool fromscratch)
336 {
337 if (fromscratch)
338 evaluateLog(P, G, L);
339 else
340 updateAfterSweep(P, G, L);
341 return LogValue;
342 }
343
344 template<typename DU_TYPE>
updateBuffer(ParticleSet & P,WFBufferType & buf,bool fromscratch)345 typename DiracDeterminant<DU_TYPE>::LogValueType DiracDeterminant<DU_TYPE>::updateBuffer(ParticleSet& P,
346 WFBufferType& buf,
347 bool fromscratch)
348 {
349 evaluateGL(P, P.G, P.L, fromscratch);
350 {
351 ScopedTimer local_timer(BufferTimer);
352 buf.forward(Bytes_in_WFBuffer);
353 buf.put(LogValue);
354 }
355 return LogValue;
356 }
357
358 template<typename DU_TYPE>
copyFromBuffer(ParticleSet & P,WFBufferType & buf)359 void DiracDeterminant<DU_TYPE>::copyFromBuffer(ParticleSet& P, WFBufferType& buf)
360 {
361 ScopedTimer local_timer(BufferTimer);
362 psiM.attachReference(buf.lendReference<ValueType>(psiM.size()));
363 dpsiM.attachReference(buf.lendReference<GradType>(dpsiM.size()));
364 d2psiM.attachReference(buf.lendReference<ValueType>(d2psiM.size()));
365 buf.get(LogValue);
366 // start with invRow labelled invalid
367 invRow_id = -1;
368 updateEng.initializeInv(psiM);
369 }
370
371 /** return the ratio only for the iat-th partcle move
372 * @param P current configuration
373 * @param iat the particle thas is being moved
374 */
375 template<typename DU_TYPE>
ratio(ParticleSet & P,int iat)376 typename DiracDeterminant<DU_TYPE>::PsiValueType DiracDeterminant<DU_TYPE>::ratio(ParticleSet& P, int iat)
377 {
378 UpdateMode = ORB_PBYP_RATIO;
379 const int WorkingIndex = iat - FirstIndex;
380 assert(WorkingIndex >= 0);
381 {
382 ScopedTimer local_timer(SPOVTimer);
383 Phi->evaluateValue(P, iat, psiV);
384 }
385 {
386 ScopedTimer local_timer(RatioTimer);
387 // This is an optimization.
388 // check invRow_id against WorkingIndex to see if getInvRow() has been called
389 // This is intended to save redundant compuation in TM1 and TM3
390 if (invRow_id != WorkingIndex)
391 {
392 invRow_id = WorkingIndex;
393 updateEng.getInvRow(psiM, WorkingIndex, invRow);
394 }
395 curRatio = simd::dot(invRow.data(), psiV.data(), invRow.size());
396 }
397 return curRatio;
398 }
399
400 template<typename DU_TYPE>
evaluateRatios(const VirtualParticleSet & VP,std::vector<ValueType> & ratios)401 void DiracDeterminant<DU_TYPE>::evaluateRatios(const VirtualParticleSet& VP, std::vector<ValueType>& ratios)
402 {
403 {
404 ScopedTimer local_timer(RatioTimer);
405 const int WorkingIndex = VP.refPtcl - FirstIndex;
406 assert(WorkingIndex >= 0);
407 std::copy_n(psiM[WorkingIndex], invRow.size(), invRow.data());
408 }
409 {
410 ScopedTimer local_timer(SPOVTimer);
411 Phi->evaluateDetRatios(VP, psiV, invRow, ratios);
412 }
413 }
414
415 template<typename DU_TYPE>
mw_evaluateRatios(const RefVectorWithLeader<WaveFunctionComponent> & wfc_list,const RefVector<const VirtualParticleSet> & vp_list,std::vector<std::vector<ValueType>> & ratios) const416 void DiracDeterminant<DU_TYPE>::mw_evaluateRatios(const RefVectorWithLeader<WaveFunctionComponent>& wfc_list,
417 const RefVector<const VirtualParticleSet>& vp_list,
418 std::vector<std::vector<ValueType>>& ratios) const
419 {
420 const size_t nw = wfc_list.size();
421
422 RefVectorWithLeader<SPOSet> phi_list(*Phi);
423 RefVector<ValueVector_t> psiV_list;
424 std::vector<const ValueType*> invRow_ptr_list;
425 phi_list.reserve(nw);
426 psiV_list.reserve(nw);
427 invRow_ptr_list.reserve(nw);
428
429 {
430 ScopedTimer local_timer(RatioTimer);
431 for (size_t iw = 0; iw < nw; iw++)
432 {
433 auto& det = wfc_list.getCastedElement<DiracDeterminant<DU_TYPE>>(iw);
434 const VirtualParticleSet& vp(vp_list[iw]);
435 const int WorkingIndex = vp.refPtcl - FirstIndex;
436 assert(WorkingIndex >= 0);
437 // If DiracDeterminant is in a valid state this copy_n is not necessary.
438 // That is at minimum a call to evaluateLog and ...
439 // std::copy_n(det.psiM[WorkingIndex], det.invRow.s.ize(), det.invRow.data());
440 // build lists
441 phi_list.push_back(*det.Phi);
442 psiV_list.push_back(det.psiV);
443 invRow_ptr_list.push_back(det.psiM[WorkingIndex]);
444 }
445 }
446
447 {
448 ScopedTimer local_timer(SPOVTimer);
449 // Phi->isOMPoffload() requires device invRow pointers for mw_evaluateDetRatios.
450 // evaluateDetRatios only requires host invRow pointers.
451 if (Phi->isOMPoffload())
452 for (int iw = 0; iw < phi_list.size(); iw++)
453 {
454 Vector<ValueType> invRow(const_cast<ValueType*>(invRow_ptr_list[iw]), psiV_list[iw].get().size());
455 phi_list[iw].evaluateDetRatios(vp_list[iw], psiV_list[iw], invRow, ratios[iw]);
456 }
457 else
458 Phi->mw_evaluateDetRatios(phi_list, vp_list, psiV_list, invRow_ptr_list, ratios);
459 }
460 }
461
462 template<typename DU_TYPE>
evaluateRatiosAlltoOne(ParticleSet & P,std::vector<ValueType> & ratios)463 void DiracDeterminant<DU_TYPE>::evaluateRatiosAlltoOne(ParticleSet& P, std::vector<ValueType>& ratios)
464 {
465 ScopedTimer local_timer(SPOVTimer);
466 Phi->evaluateValue(P, -1, psiV);
467 MatrixOperators::product(psiM, psiV.data(), &ratios[FirstIndex]);
468 }
469
470
471 template<typename DU_TYPE>
resizeScratchObjectsForIonDerivs()472 void DiracDeterminant<DU_TYPE>::resizeScratchObjectsForIonDerivs()
473 {
474 grad_source_psiM.resize(NumPtcls, NumOrbitals);
475 grad_lapl_source_psiM.resize(NumPtcls, NumOrbitals);
476 grad_grad_source_psiM.resize(NumPtcls, NumOrbitals);
477 phi_alpha_Minv.resize(NumPtcls, NumOrbitals);
478 grad_phi_Minv.resize(NumPtcls, NumOrbitals);
479 lapl_phi_Minv.resize(NumPtcls, NumOrbitals);
480 grad_phi_alpha_Minv.resize(NumPtcls, NumOrbitals);
481 }
482
483 template<typename DU_TYPE>
evalGradSource(ParticleSet & P,ParticleSet & source,int iat)484 typename DiracDeterminant<DU_TYPE>::GradType DiracDeterminant<DU_TYPE>::evalGradSource(ParticleSet& P,
485 ParticleSet& source,
486 int iat)
487 {
488 GradType g(0.0);
489 if (Phi->hasIonDerivs())
490 {
491 resizeScratchObjectsForIonDerivs();
492 Phi->evaluateGradSource(P, FirstIndex, LastIndex, source, iat, grad_source_psiM);
493 g = simd::dot(psiM.data(), grad_source_psiM.data(), psiM.size());
494 }
495
496 return g;
497 }
498
499 template<typename DU_TYPE>
evaluateHessian(ParticleSet & P,HessVector_t & grad_grad_psi)500 void DiracDeterminant<DU_TYPE>::evaluateHessian(ParticleSet& P, HessVector_t& grad_grad_psi)
501 {
502 // Hessian is not often used, so only resize/allocate if used
503 grad_grad_source_psiM.resize(psiM.rows(), psiM.cols());
504 //IM A HACK. Assumes evaluateLog has already been executed.
505 Phi->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_temp, dpsiM, grad_grad_source_psiM);
506 invertPsiM(psiM_temp, psiM);
507
508 phi_alpha_Minv = 0.0;
509 grad_phi_Minv = 0.0;
510 lapl_phi_Minv = 0.0;
511 grad_phi_alpha_Minv = 0.0;
512 //grad_grad_psi.resize(NumPtcls);
513
514 for (int i = 0, iat = FirstIndex; i < NumPtcls; i++, iat++)
515 {
516 GradType rv = simd::dot(psiM[i], dpsiM[i], NumOrbitals);
517 // HessType hess_tmp=simd::dot(psiM[i],grad_grad_source_psiM[i],NumOrbitals);
518 HessType hess_tmp;
519 hess_tmp = 0.0;
520 hess_tmp = simd::dot(psiM[i], grad_grad_source_psiM[i], NumOrbitals);
521 grad_grad_psi[iat] = hess_tmp - outerProduct(rv, rv);
522 }
523 }
524
525 template<typename DU_TYPE>
evalGradSource(ParticleSet & P,ParticleSet & source,int iat,TinyVector<ParticleSet::ParticleGradient_t,OHMMS_DIM> & grad_grad,TinyVector<ParticleSet::ParticleLaplacian_t,OHMMS_DIM> & lapl_grad)526 typename DiracDeterminant<DU_TYPE>::GradType DiracDeterminant<DU_TYPE>::evalGradSource(
527 ParticleSet& P,
528 ParticleSet& source,
529 int iat,
530 TinyVector<ParticleSet::ParticleGradient_t, OHMMS_DIM>& grad_grad,
531 TinyVector<ParticleSet::ParticleLaplacian_t, OHMMS_DIM>& lapl_grad)
532 {
533 GradType gradPsi(0.0);
534 if (Phi->hasIonDerivs())
535 {
536 resizeScratchObjectsForIonDerivs();
537 Phi->evaluateGradSource(P, FirstIndex, LastIndex, source, iat, grad_source_psiM, grad_grad_source_psiM,
538 grad_lapl_source_psiM);
539 // HACK HACK HACK
540 // Phi->evaluateVGL(P, FirstIndex, LastIndex, psiM, dpsiM, d2psiM);
541 // psiM_temp = psiM;
542 // LogValue=InvertWithLog(psiM.data(),NumPtcls,NumOrbitals,
543 // WorkSpace.data(),Pivot.data(),PhaseValue);
544 // for (int i=0; i<NumPtcls; i++)
545 // for (int j=0; j<NumPtcls; j++) {
546 // double val = 0.0;
547 // for (int k=0; k<NumPtcls; k++)
548 // val += psiM(i,k) * psiM_temp(k,j);
549 // val -= (i == j) ? 1.0 : 0.0;
550 // if (std::abs(val) > 1.0e-12)
551 // std::cerr << "Error in inverse.\n";
552 // }
553 // for (int i=0; i<NumPtcls; i++) {
554 // P.G[FirstIndex+i] = GradType();
555 // for (int j=0; j<NumOrbitals; j++)
556 // P.G[FirstIndex+i] += psiM(i,j)*dpsiM(i,j);
557 // }
558 // Compute matrices
559 phi_alpha_Minv = 0.0;
560 grad_phi_Minv = 0.0;
561 lapl_phi_Minv = 0.0;
562 grad_phi_alpha_Minv = 0.0;
563 for (int i = 0; i < NumPtcls; i++)
564 for (int j = 0; j < NumOrbitals; j++)
565 {
566 lapl_phi_Minv(i, j) = 0.0;
567 for (int k = 0; k < NumOrbitals; k++)
568 lapl_phi_Minv(i, j) += d2psiM(i, k) * psiM(j, k);
569 }
570 for (int dim = 0; dim < OHMMS_DIM; dim++)
571 {
572 for (int i = 0; i < NumPtcls; i++)
573 for (int j = 0; j < NumOrbitals; j++)
574 {
575 for (int k = 0; k < NumOrbitals; k++)
576 {
577 phi_alpha_Minv(i, j)[dim] += grad_source_psiM(i, k)[dim] * psiM(j, k);
578 grad_phi_Minv(i, j)[dim] += dpsiM(i, k)[dim] * psiM(j, k);
579 for (int dim_el = 0; dim_el < OHMMS_DIM; dim_el++)
580 grad_phi_alpha_Minv(i, j)(dim, dim_el) += grad_grad_source_psiM(i, k)(dim, dim_el) * psiM(j, k);
581 }
582 }
583 }
584 for (int i = 0, iel = FirstIndex; i < NumPtcls; i++, iel++)
585 {
586 HessType dval(0.0);
587 GradType d2val(0.0);
588 for (int dim = 0; dim < OHMMS_DIM; dim++)
589 for (int dim_el = 0; dim_el < OHMMS_DIM; dim_el++)
590 dval(dim, dim_el) = grad_phi_alpha_Minv(i, i)(dim, dim_el);
591 for (int j = 0; j < NumOrbitals; j++)
592 {
593 gradPsi += grad_source_psiM(i, j) * psiM(i, j);
594 for (int dim = 0; dim < OHMMS_DIM; dim++)
595 for (int k = 0; k < OHMMS_DIM; k++)
596 dval(dim, k) -= phi_alpha_Minv(j, i)[dim] * grad_phi_Minv(i, j)[k];
597 }
598 for (int dim = 0; dim < OHMMS_DIM; dim++)
599 {
600 for (int k = 0; k < OHMMS_DIM; k++)
601 grad_grad[dim][iel][k] += dval(dim, k);
602 for (int j = 0; j < NumOrbitals; j++)
603 {
604 // First term, eq 9
605 lapl_grad[dim][iel] += grad_lapl_source_psiM(i, j)[dim] * psiM(i, j);
606 // Second term, eq 9
607 if (j == i)
608 for (int dim_el = 0; dim_el < OHMMS_DIM; dim_el++)
609 lapl_grad[dim][iel] -=
610 (RealType)2.0 * grad_phi_alpha_Minv(j, i)(dim, dim_el) * grad_phi_Minv(i, j)[dim_el];
611 // Third term, eq 9
612 // First term, eq 10
613 lapl_grad[dim][iel] -= phi_alpha_Minv(j, i)[dim] * lapl_phi_Minv(i, j);
614 // Second term, eq 11
615 for (int dim_el = 0; dim_el < OHMMS_DIM; dim_el++)
616 lapl_grad[dim][iel] +=
617 (RealType)2.0 * phi_alpha_Minv(j, i)[dim] * grad_phi_Minv(i, i)[dim_el] * grad_phi_Minv(i, j)[dim_el];
618 }
619 }
620 }
621 }
622 return gradPsi;
623 }
624
625
626 /** Calculate the log value of the Dirac determinant for particles
627 *@param P input configuration containing N particles
628 *@param G a vector containing N gradients
629 *@param L a vector containing N laplacians
630 *@return the value of the determinant
631 *
632 *\f$ (first,first+nel). \f$ Add the gradient and laplacian
633 *contribution of the determinant to G(radient) and L(aplacian)
634 *for local energy calculations.
635 */
636 template<typename DU_TYPE>
evaluateLog(const ParticleSet & P,ParticleSet::ParticleGradient_t & G,ParticleSet::ParticleLaplacian_t & L)637 typename DiracDeterminant<DU_TYPE>::LogValueType DiracDeterminant<DU_TYPE>::evaluateLog(
638 const ParticleSet& P,
639 ParticleSet::ParticleGradient_t& G,
640 ParticleSet::ParticleLaplacian_t& L)
641 {
642 recompute(P);
643
644 if (NumPtcls == 1)
645 {
646 ValueType y = psiM(0, 0);
647 GradType rv = y * dpsiM(0, 0);
648 G[FirstIndex] += rv;
649 L[FirstIndex] += y * d2psiM(0, 0) - dot(rv, rv);
650 }
651 else
652 {
653 for (int i = 0, iat = FirstIndex; i < NumPtcls; i++, iat++)
654 {
655 mGradType rv = simd::dot(psiM[i], dpsiM[i], NumOrbitals);
656 mValueType lap = simd::dot(psiM[i], d2psiM[i], NumOrbitals);
657 G[iat] += rv;
658 L[iat] += lap - dot(rv, rv);
659 }
660 }
661 return LogValue;
662 }
663
664 template<typename DU_TYPE>
recompute(const ParticleSet & P)665 void DiracDeterminant<DU_TYPE>::recompute(const ParticleSet& P)
666 {
667 {
668 ScopedTimer local_timer(SPOVGLTimer);
669 Phi->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_temp, dpsiM, d2psiM);
670 }
671 if (NumPtcls == 1)
672 {
673 ValueType det = psiM_temp(0, 0);
674 psiM(0, 0) = RealType(1) / det;
675 LogValue = convertValueToLog(det);
676 }
677 else
678 invertPsiM(psiM_temp, psiM);
679
680 // invRow becomes invalid after updating the inverse matrix
681 invRow_id = -1;
682 }
683
684 template<typename DU_TYPE>
evaluateDerivatives(ParticleSet & P,const opt_variables_type & active,std::vector<ValueType> & dlogpsi,std::vector<ValueType> & dhpsioverpsi)685 void DiracDeterminant<DU_TYPE>::evaluateDerivatives(ParticleSet& P,
686 const opt_variables_type& active,
687 std::vector<ValueType>& dlogpsi,
688 std::vector<ValueType>& dhpsioverpsi)
689 {
690 Phi->evaluateDerivatives(P, active, dlogpsi, dhpsioverpsi, FirstIndex, LastIndex);
691 }
692
693 template<typename DU_TYPE>
makeCopy(std::shared_ptr<SPOSet> && spo) const694 DiracDeterminant<DU_TYPE>* DiracDeterminant<DU_TYPE>::makeCopy(std::shared_ptr<SPOSet>&& spo) const
695 {
696 DiracDeterminant<DU_TYPE>* dclone = new DiracDeterminant<DU_TYPE>(std::move(spo));
697 dclone->set(FirstIndex, LastIndex - FirstIndex, ndelay);
698 return dclone;
699 }
700
701 template<typename DU_TYPE>
createResource(ResourceCollection & collection) const702 void DiracDeterminant<DU_TYPE>::createResource(ResourceCollection& collection) const
703 {
704 Phi->createResource(collection);
705 }
706
707 template<typename DU_TYPE>
acquireResource(ResourceCollection & collection)708 void DiracDeterminant<DU_TYPE>::acquireResource(ResourceCollection& collection)
709 {
710 Phi->acquireResource(collection);
711 }
712
713 template<typename DU_TYPE>
releaseResource(ResourceCollection & collection)714 void DiracDeterminant<DU_TYPE>::releaseResource(ResourceCollection& collection)
715 {
716 Phi->releaseResource(collection);
717 }
718
719 template class DiracDeterminant<>;
720 #if defined(ENABLE_CUDA)
721 template class DiracDeterminant<DelayedUpdateCUDA<QMCTraits::ValueType, QMCTraits::QTFull::ValueType>>;
722 #endif
723
724 } // namespace qmcplusplus
725