1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
8 //
9 // File created by: Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 #ifndef QMCPLUSPLUS_AFQMC_WALKERSETBASE_H
13 #define QMCPLUSPLUS_AFQMC_WALKERSETBASE_H
14 
15 #include <random>
16 #include <type_traits>
17 #include <memory>
18 
19 #include "Configuration.h"
20 #include "OhmmsData/libxmldefs.h"
21 #include "Utilities/TimerManager.h"
22 #include "Utilities/RandomGenerator.h"
23 
24 #include "AFQMC/config.h"
25 #include "AFQMC/Utilities/taskgroup.h"
26 #include "AFQMC/Numerics/ma_blas.hpp"
27 
28 #include "AFQMC/Walkers/Walkers.hpp"
29 #include "AFQMC/Walkers/WalkerControl.hpp"
30 #include "AFQMC/Walkers/WalkerConfig.hpp"
31 
32 namespace qmcplusplus
33 {
34 namespace afqmc
35 {
36 /*
37  * Class that contains and handles walkers.
38  * Implements communication, load balancing, and I/O operations.
39  * Walkers are always accessed through the handler.
40  */
41 template<class Alloc, class Ptr> //, class BPAlloc, class BPPtr>
42 class WalkerSetBase : public AFQMCInfo
43 {
44 protected:
45   enum WalkerSetBaseTimers
46   {
47     LoadBalance_t,
48     Branching_t
49   };
50 
51   using element       = typename std::pointer_traits<Ptr>::element_type;
52   using pointer       = Ptr;
53   using const_element = const element;
54   using const_pointer = const Ptr;
55   using Allocator     = Alloc;
56 
57   using bp_element       = SPComplexType;  //typename std::pointer_traits<BPPtr>::element_type;
58   using bp_pointer       = SPComplexType*; //BPPtr;
59   using const_bp_element = const bp_element;
60   using const_bp_pointer = const bp_pointer;
61   using BPAllocator      = shared_allocator<bp_element>; //BPAlloc;
62 
63   using CMatrix       = boost::multi::array<element, 2, Allocator>;
64   using BPCMatrix     = boost::multi::array<bp_element, 2, BPAllocator>;
65   using BPCVector_ref = boost::multi::array_ref<bp_element, 1, bp_pointer>;
66   using BPCMatrix_ref = boost::multi::array_ref<bp_element, 2, bp_pointer>;
67   using BPCTensor_ref = boost::multi::array_ref<bp_element, 3, bp_pointer>;
68 
69   using stdCMatrix_ptr = boost::multi::array_ptr<bp_element, 2>;
70   using stdCTensor_ptr = boost::multi::array_ptr<bp_element, 3>;
71 
72 public:
73   // contiguous_walker = true means that all the data of a walker is continguous in memory
74   static const bool contiguous_walker = true;
75   // contiguous_storage = true means that the data of all walker is continguous in memory
76   static const bool contiguous_storage = true;
77   static const bool fixed_population   = true;
78 
79   using reference = walker<pointer>;
80   using iterator  = walker_iterator<pointer>;
81   //using const_reference = const_walker<const_pointer>;
82   //using const_iterator = const_walker_iterator<const_pointer>;
83   using const_reference = walker<pointer>;
84   using const_iterator  = walker_iterator<pointer>;
85 
86   /// constructor
WalkerSetBase(afqmc::TaskGroup_ & tg_,xmlNodePtr cur,AFQMCInfo & info,RandomGenerator_t * r,Allocator alloc_,BPAllocator bpalloc_)87   WalkerSetBase(afqmc::TaskGroup_& tg_,
88                 xmlNodePtr cur,
89                 AFQMCInfo& info,
90                 RandomGenerator_t* r,
91                 Allocator alloc_,
92                 BPAllocator bpalloc_)
93       : AFQMCInfo(info),
94         TG(tg_),
95         rng(r),
96         walker_size(1),
97         walker_memory_usage(0),
98         bp_walker_size(0),
99         bp_walker_memory_usage(0),
100         bp_pos(-1),
101         history_pos(0),
102         walkerType(UNDEFINED_WALKER_TYPE),
103         tot_num_walkers(0),
104         walker_buffer({0, 1}, alloc_),
105         bp_buffer({0, 0}, bpalloc_),
106         load_balance(UNDEFINED_LOAD_BALANCE),
107         pop_control(UNDEFINED_BRANCHING),
108         min_weight(0.05),
109         max_weight(4.0)
110   {
111     parse(cur);
112     setup();
113   }
114 
115   /// destructor
~WalkerSetBase()116   ~WalkerSetBase() {}
117 
118   WalkerSetBase(WalkerSetBase const& other) = delete;
119   WalkerSetBase(WalkerSetBase&& other)      = default;
120   WalkerSetBase& operator=(WalkerSetBase const& other) = delete;
121   WalkerSetBase& operator=(WalkerSetBase&& other) = delete;
122 
123   /*
124    * Returns the current number of walkers in the set.
125    */
size()126   int size() const { return tot_num_walkers; }
127 
128   /*
129    * Returns the maximum number of walkers in the set that can be stored without reallocation.
130    */
capacity()131   int capacity() const { return int(walker_buffer.size(0)); }
132 
133   /*
134    * Returns the maximum number of fields in the set that can be stored without reallocation.
135    */
NumBackProp()136   int NumBackProp() const { return wlk_desc[3]; }
137   /*
138    * Returns the maximum number of cholesky vectors in the set that can be stored without reallocation.
139    */
NumCholVecs()140   int NumCholVecs() const { return wlk_desc[4]; }
141   /*
142    * Returns the length of the history buffers.
143    */
HistoryBufferLength()144   int HistoryBufferLength() const { return wlk_desc[6]; }
145 
146   /*
147    * Returns the position of the insertion point in the BP stack.
148    */
getBPPos()149   int getBPPos() const { return bp_pos; }
setBPPos(int p)150   void setBPPos(int p) { bp_pos = p; }
advanceBPPos()151   void advanceBPPos() { bp_pos++; }
152 
153   /*
154    * Returns, sets and advances the position of the insertion point in the History circular buffers.
155    */
getHistoryPos()156   int getHistoryPos() const { return history_pos; }
setHistoryPos(int p)157   void setHistoryPos(int p) { history_pos = p % wlk_desc[6]; }
advanceHistoryPos()158   void advanceHistoryPos() { history_pos = (history_pos + 1) % wlk_desc[6]; }
159 
160 
161   /*
162    * Returns iterator to the first walker in the set
163    */
begin()164   iterator begin()
165   {
166     assert(walker_buffer.size(1) == walker_size);
167     return iterator(0, boost::multi::static_array_cast<element, pointer>(walker_buffer), data_displ, wlk_desc);
168   }
169 
170   /*
171    * Returns iterator to the first walker in the set
172    */
begin()173   const_iterator begin() const
174   {
175     assert(walker_buffer.size(1) == walker_size);
176     return const_iterator(0, boost::multi::static_array_cast<element, pointer>(walker_buffer), data_displ, wlk_desc);
177   }
178 
179 
180   /*
181    * Returns iterator to the past-the-end walker in the set
182    */
end()183   iterator end()
184   {
185     assert(walker_buffer.size(1) == walker_size);
186     return iterator(tot_num_walkers, boost::multi::static_array_cast<element, pointer>(walker_buffer), data_displ,
187                     wlk_desc);
188   }
189 
190   /*
191    * Returns a reference to a walker
192    */
193   reference operator[](int i)
194   {
195     if (i < 0 || i > tot_num_walkers)
196       APP_ABORT("error: index out of bounds.\n");
197     assert(walker_buffer.size(1) == walker_size);
198     return reference(boost::multi::static_array_cast<element, pointer>(walker_buffer)[i], data_displ, wlk_desc);
199   }
200 
201   /*
202    * Returns a reference to a walker
203    */
204   const_reference operator[](int i) const
205   {
206     if (i < 0 || i > tot_num_walkers)
207       APP_ABORT("error: index out of bounds.\n");
208     assert(walker_buffer.size(1) == walker_size);
209     return const_reference(boost::multi::static_array_cast<element, pointer>(walker_buffer)[i], data_displ, wlk_desc);
210   }
211 
212   // cleans state of object.
213   //   -erases allocated memory
214   bool clean();
215 
216   /*
217    * Increases the capacity of the containers to n.
218    */
219   void reserve(int n);
220 
221   /*
222    * Adds/removes the number of walkers in the set to match the requested value.
223    * Walkers are removed from the end of the set
224    *     and buffer capacity remains unchanged in this case.
225    * New walkers are initialized from already existing walkers in a round-robin fashion.
226    * If the set is empty, calling this routine will abort.
227    * Capacity is increased if necessary.
228    * Target Populations are set to n.
229    */
230   void resize(int n);
231 
232   /*
233    * Adds/removes the number of walkers in the set to match the requested value.
234    * Walkers are removed from the end of the set
235    *     and buffer capacity remains unchanged in this case.
236    * New walkers are initialized from the supplied matrix.
237    * Capacity is increased if necessary.
238    * Target Populations are set to n.
239    */
240   template<class MatA, class MatB>
resize(int n,MatA && A,MatB && B)241   void resize(int n, MatA&& A, MatB&& B)
242   {
243     assert(A.size(0) == wlk_desc[0]);
244     assert(A.size(1) == wlk_desc[1]);
245     if (walkerType == COLLINEAR)
246     {
247       assert(B.size(0) == wlk_desc[0]);
248       assert(B.size(1) == wlk_desc[2]);
249     }
250     reserve(n);
251     if (n > tot_num_walkers)
252     {
253       if (TG.TG_local().root())
254       {
255         auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
256         auto pos = tot_num_walkers;
257         // careful here!!!
258         while (pos < n)
259         {
260           using std::fill_n;
261           fill_n(W[pos].origin(), W[pos].size(0), ComplexType(0, 0));
262           reference w0(W[pos], data_displ, wlk_desc);
263           //w0.SlaterMatrix(Alpha) = A;
264           auto&& SM_(*w0.SlaterMatrix(Alpha));
265           SM_ = A;
266           if (walkerType == COLLINEAR)
267           {
268             //w0.SlaterMatrix(Beta) = B;
269             auto&& SMB_(*w0.SlaterMatrix(Beta));
270             SMB_ = B;
271           }
272           pos++;
273         }
274         // use operator= or assign when ready!!!
275         boost::multi::array<ComplexType, 1> buff(iextensions<1u>{n - tot_num_walkers}, ComplexType(1.0));
276         ma::copy(buff, W({tot_num_walkers, n}, data_displ[WEIGHT]));
277         ma::copy(buff, W({tot_num_walkers, n}, data_displ[OVLP]));
278         ma::copy(buff, W({tot_num_walkers, n}, data_displ[PHASE]));
279       }
280     }
281     tot_num_walkers = n;
282     targetN_per_TG  = tot_num_walkers;
283     targetN         = GlobalPopulation();
284     if (targetN != targetN_per_TG * TG.getNumberOfTGs())
285     {
286       std::cerr << " targetN, targetN_per_TG, # of TGs: " << targetN << " " << targetN_per_TG << " "
287                 << TG.getNumberOfTGs() << std::endl;
288       std::cout << " targetN, targetN_per_TG, # of TGs: " << targetN << " " << targetN_per_TG << " "
289                 << TG.getNumberOfTGs() << std::endl;
290       APP_ABORT("Error in WalkerSetBase::resize(n,A,B).\n");
291     }
292   }
293 
resize_bp(int nbp,int nCV,int nref)294   void resize_bp(int nbp, int nCV, int nref)
295   {
296     assert(walker_buffer.size(1) == walker_size);
297     assert(bp_buffer.size(0) == bp_walker_size);
298     assert(walker_buffer.size(0) == bp_buffer.size(1));
299     // wlk_descriptor: {nmo, naea, naeb, nback_prop, nCV, nRefs, nHist}
300     wlk_desc[3] = nbp;
301     wlk_desc[4] = nCV;
302     wlk_desc[5] = nref;
303     wlk_desc[6] = 3 * nbp;
304     int ncol    = NAEA;
305     int nrow    = NMO;
306     if (walkerType != CLOSED)
307     {
308       if (walkerType == COLLINEAR)
309       {
310         ncol += NAEB;
311       }
312       else if (walkerType == NONCOLLINEAR)
313       {
314         nrow += NMO;
315         ncol += NAEB;
316       }
317       else
318       {
319         app_error() << " Error: Incorrect walker_type on WalkerSetBase::setup \n";
320         APP_ABORT("");
321       }
322     }
323     // store nbpx3 history of weights and factors in circular buffer
324     int cnt            = 0;
325     data_displ[FIELDS] = cnt;
326     cnt += nbp * nCV;
327     data_displ[WEIGHT_FAC] = cnt;
328     cnt += wlk_desc[6];
329     data_displ[WEIGHT_HISTORY] = cnt;
330     cnt += wlk_desc[6];
331     bp_walker_size = cnt;
332     if (bp_buffer.size(0) != bp_walker_size)
333     {
334       bp_buffer.reextent({bp_walker_size, walker_buffer.size(0)});
335       using std::fill_n;
336       fill_n(bp_buffer.origin() + data_displ[WEIGHT_FAC] * bp_buffer.size(1), wlk_desc[6] * bp_buffer.size(1),
337              bp_element(1.0));
338     }
339     if (nbp > 0 && (data_displ[SMN] < 0 || data_displ[SM_AUX] < 0))
340     {
341       auto sz(walker_size);
342       data_displ[SMN] = walker_size;
343       walker_size += nrow * ncol;
344       data_displ[SM_AUX] = walker_size;
345       walker_size += nrow * ncol;
346       CMatrix wb({walker_buffer.size(0), walker_size}, walker_buffer.get_allocator());
347       ma::copy(walker_buffer, wb(wb.extension(0), {0, sz}));
348       walker_buffer = std::move(wb);
349     }
350   }
351 
352   // perform and report tests/timings
353   void benchmark(std::string& blist, int maxnW, int delnW, int repeat);
354 
get_TG_target_population()355   int get_TG_target_population() const { return targetN_per_TG; }
get_global_target_population()356   int get_global_target_population() const { return targetN; }
357 
walker_dims()358   std::pair<int, int> walker_dims() const { return std::pair<int, int>{wlk_desc[0], wlk_desc[1]}; }
359 
GlobalPopulation()360   int GlobalPopulation() const
361   {
362     int res = 0;
363     assert(walker_buffer.size(1) == walker_size);
364     if (TG.TG_local().root())
365       res += tot_num_walkers;
366     return (TG.Global() += res);
367   }
368 
GlobalWeight()369   RealType GlobalWeight() const
370   {
371     RealType res = 0;
372     assert(walker_buffer.size(1) == walker_size);
373     if (TG.TG_local().root())
374     {
375       boost::multi::array<ComplexType, 1> buff(iextensions<1u>{tot_num_walkers});
376       getProperty(WEIGHT, buff);
377       for (int i = 0; i < tot_num_walkers; i++)
378         res += std::abs(buff[i]);
379     }
380     return (TG.Global() += res);
381   }
382 
383   // population control algorithm
384   void popControl(std::vector<ComplexType>& curData);
385 
386   template<class Mat>
push_walkers(Mat && M)387   void push_walkers(Mat&& M)
388   {
389     static_assert(std::decay<Mat>::type::dimensionality == 2, "Wrong dimensionality");
390     if (tot_num_walkers + M.size(0) > capacity())
391       APP_ABORT("Insufficient capacity");
392     if (single_walker_size() + single_walker_bp_size() != M.size(1))
393       APP_ABORT("Incorrect dimensions.");
394     if (M.stride(1) != 1)
395       APP_ABORT("Incorrect strides.");
396     if (!TG.TG_local().root())
397     {
398       tot_num_walkers += M.size(0);
399       return;
400     }
401     auto&& W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
402     auto&& BPW(boost::multi::static_array_cast<bp_element, bp_pointer>(bp_buffer));
403     for (int i = 0; i < M.size(0); i++)
404     {
405       W[tot_num_walkers] = M[i].sliced(0, walker_size);
406       if (wlk_desc[3] > 0)
407         BPW(BPW.extension(0), tot_num_walkers) = M[i].sliced(walker_size, walker_size + bp_walker_size);
408       tot_num_walkers++;
409     }
410   }
411 
412   template<class Mat>
pop_walkers(Mat && M)413   void pop_walkers(Mat&& M)
414   {
415     static_assert(std::decay<Mat>::type::dimensionality == 2, "Wrong dimensionality");
416     if (tot_num_walkers < int(M.size(0)))
417       APP_ABORT("Insufficient walkers");
418     if (wlk_desc[3] > 0)
419     {
420       if (walker_size + bp_walker_size != int(M.size(1)))
421         APP_ABORT("Incorrect dimensions.");
422     }
423     else
424     {
425       if (walker_size != int(M.size(1)))
426         APP_ABORT("Incorrect dimensions.");
427     }
428     if (M.stride(1) != 1)
429       APP_ABORT("Incorrect strides.");
430 
431     if (!TG.TG_local().root())
432     {
433       tot_num_walkers -= int(M.size(0));
434       return;
435     }
436     auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
437     auto BPW(boost::multi::static_array_cast<bp_element, bp_pointer>(bp_buffer));
438     for (int i = 0; i < M.size(0); i++)
439     {
440       M[i].sliced(0, walker_size) = W[tot_num_walkers - 1];
441       if (wlk_desc[3] > 0)
442         M[i].sliced(walker_size, walker_size + bp_walker_size) = BPW(BPW.extension(0), tot_num_walkers - 1);
443       tot_num_walkers--;
444     }
445   }
446 
447   // given a list of new weights and counts, add/remove walkers and reassign weight accordingly
448   template<class Mat>
branch(std::vector<std::pair<double,int>>::iterator itbegin,std::vector<std::pair<double,int>>::iterator itend,Mat & M)449   void branch(std::vector<std::pair<double, int>>::iterator itbegin,
450               std::vector<std::pair<double, int>>::iterator itend,
451               Mat& M)
452   {
453     if (std::distance(itbegin, itend) != tot_num_walkers)
454       APP_ABORT("Error in WalkerSetBase::branch(): ptr_range != # walkers. \n");
455 
456     // checking purposes
457     int nW = 0;
458     for (auto it = itbegin; it != itend; ++it)
459       nW += it->second;
460     if (int(M.size(0)) < std::max(0, nW - targetN_per_TG))
461     {
462       std::cout << " Error in WalkerSetBase::branch(): Not enough space in excess matrix. \n"
463                 << M.size(0) << " " << nW << " " << targetN_per_TG << std::endl;
464       APP_ABORT("Error in WalkerSetBase::branch(): Not enough space in excess matrix.\n");
465     }
466     if (int(M.size(1)) < walker_size + ((wlk_desc[3] > 0) ? bp_walker_size : 0))
467       APP_ABORT("Error in WalkerSetBase::branch(): Wrong dimensions in excess matrix.\n");
468 
469     // if all walkers are dead, don't bother with routine, reset tot_num_walkers and return
470     if (nW == 0)
471     {
472       tot_num_walkers = 0;
473       return;
474     }
475 
476     auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
477     auto BPW(boost::multi::static_array_cast<bp_element, bp_pointer>(bp_buffer));
478 
479     //1. push/swap all dead walkers to the end and adjust tot_num_walkers
480     {
481       auto kill = itbegin;
482       auto keep = itend - 1;
483 
484       while (keep > kill)
485       {
486         // 1. look for next keep
487         while (keep->second == 0 && keep > kill)
488         {
489           tot_num_walkers--;
490           --keep;
491         }
492         if (keep == kill)
493           break;
494 
495         // 2. look for next kill
496         while (kill->second != 0 && kill < keep)
497           ++kill;
498         if (keep == kill)
499           break;
500 
501         // 3. swap
502         std::swap(*kill, *keep);
503         W[std::distance(itbegin, kill)] = W[tot_num_walkers - 1];
504         if (wlk_desc[3] > 0)
505           BPW(BPW.extension(0), std::distance(itbegin, kill)) = BPW(BPW.extension(0), tot_num_walkers - 1);
506         --tot_num_walkers;
507         --keep;
508       }
509 
510       // check
511       int n = 0;
512       for (auto it = itbegin; it != itbegin + tot_num_walkers; ++it)
513         n += it->second;
514       if (n != nW)
515         APP_ABORT("Error in WalkerSetBase::branch(): Problems with walker counts after sort.\n");
516       for (auto it = itbegin + tot_num_walkers; it != itend; ++it)
517         if (it->second != 0)
518           APP_ABORT("Error in WalkerSetBase::branch(): Problems after sort.\n");
519       // you can also check the energy if things look incorrect
520     }
521 
522     //2. Adjust weights and replicate walkers. Those beyond targetN_per_TG go in M
523     itend   = itbegin + tot_num_walkers;
524     int pos = 0;
525     int cnt = 0;
526     // circular buffer
527     int his_pos = ((history_pos == 0) ? wlk_desc[6] - 1 : history_pos - 1);
528     for (; itbegin != itend; ++itbegin, ++pos)
529     {
530       if (itbegin->second <= 0)
531       { // just checking
532         APP_ABORT("Error in WalkerSetBase::branch(): Problems during branch.\n");
533       }
534       else if (itbegin->second == 1)
535       {
536         //walker_buffer[pos][data_displ[WEIGHT]] = ComplexType(itbegin->first,0.0);
537         // need synthetic references to make this easier!!!
538         using std::fill_n;
539         fill_n(W[pos].origin() + data_displ[WEIGHT], 1, ComplexType(itbegin->first, 0.0));
540         if (wlk_desc[6] > 0 && his_pos >= 0 && his_pos < wlk_desc[6])
541           fill_n(BPW[data_displ[WEIGHT_HISTORY] + his_pos].origin() + pos, 1, ComplexType(itbegin->first, 0.0));
542       }
543       else
544       {
545         // if there is space, branch within walker set
546         // otherwise send excess to M
547         int n = std::min(targetN_per_TG - tot_num_walkers, itbegin->second - 1);
548         //walker_buffer[pos][data_displ[WEIGHT]] = ComplexType(itbegin->first,0.0);
549         // need synthetic references to make this easier!!!
550         using std::fill_n;
551         fill_n(W[pos].origin() + data_displ[WEIGHT], 1, ComplexType(itbegin->first, 0.0));
552         if (wlk_desc[6] > 0 && his_pos >= 0 && his_pos < wlk_desc[6])
553           fill_n(BPW[data_displ[WEIGHT_HISTORY] + his_pos].origin() + pos, 1, ComplexType(itbegin->first, 0.0));
554         for (int i = 0; i < n; i++)
555         {
556           W[tot_num_walkers] = W[pos];
557           if (wlk_desc[3] > 0)
558             BPW(BPW.extension(0), tot_num_walkers) = BPW(BPW.extension(0), pos);
559           tot_num_walkers++;
560         }
561         for (int i = 0, in = itbegin->second - 1 - n; i < in; i++, cnt++)
562         {
563           M[cnt].sliced(0, walker_size) = W[pos];
564           if (wlk_desc[3] > 0)
565             M[cnt].sliced(walker_size, walker_size + bp_walker_size) = BPW(BPW.extension(0), pos);
566         }
567       }
568     }
569   }
570 
571   template<class T>
572   void scaleWeight(const T& w0, bool scale_last_history = false)
573   {
574     if (!TG.TG_local().root())
575       return;
576     assert(walker_buffer.size(1) == walker_size);
577     auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
578     ma::scal(ComplexType(w0), W({0, tot_num_walkers}, data_displ[WEIGHT]));
579     if (scale_last_history)
580     {
581       int his_pos = ((history_pos == 0) ? wlk_desc[6] - 1 : history_pos - 1);
582       if (wlk_desc[6] > 0 && his_pos >= 0 && his_pos < wlk_desc[6])
583       {
584         auto BPW(boost::multi::static_array_cast<bp_element, bp_pointer>(bp_buffer));
585         ma::scal(bp_element(w0), BPW[data_displ[WEIGHT_HISTORY] + his_pos]);
586       }
587     }
588   }
589 
scaleWeightsByOverlap()590   void scaleWeightsByOverlap()
591   {
592     if (!TG.TG_local().root())
593       return;
594     assert(walker_buffer.size(1) == walker_size);
595     auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
596     boost::multi::array<ComplexType, 1> ov(iextensions<1u>{tot_num_walkers});
597     boost::multi::array<ComplexType, 1> buff(iextensions<1u>{tot_num_walkers});
598     getProperty(OVLP, ov);
599     for (int i = 0; i < tot_num_walkers; i++)
600       buff[i] = ComplexType(1.0 / std::abs(ov[i]), 0.0);
601     ma::axty(ComplexType(1.0), buff, W({0, tot_num_walkers}, data_displ[WEIGHT]));
602     for (int i = 0; i < tot_num_walkers; i++)
603       buff[i] = std::exp(ComplexType(0.0, -std::arg(ov[i])));
604     ma::axty(ComplexType(1.0), buff, W({0, tot_num_walkers}, data_displ[PHASE]));
605   }
606 
getTG()607   afqmc::TaskGroup_& getTG() { return TG; }
608 
single_walker_memory_usage()609   int single_walker_memory_usage() const { return walker_memory_usage; }
single_walker_size()610   int single_walker_size() const { return walker_size; }
single_walker_bp_memory_usage()611   int single_walker_bp_memory_usage() const { return (wlk_desc[3] > 0) ? bp_walker_memory_usage : 0; }
single_walker_bp_size()612   int single_walker_bp_size() const { return (wlk_desc[3] > 0) ? bp_walker_size : 0; }
613 
getWalkerType()614   WALKER_TYPES getWalkerType() { return walkerType; }
615 
walkerSizeIO()616   int walkerSizeIO()
617   {
618     if (walkerType == COLLINEAR)
619       return wlk_desc[0] * (wlk_desc[1] + wlk_desc[2]) + 7;
620     else // since NAEB = 0 in both CLOSED and NONCOLLINEAR cases
621       return wlk_desc[0] * wlk_desc[1] + 7;
622     return 0;
623   }
624 
625   // I am going to assume that the relevant data to be copied is continuous,
626   // careful not to break this in the future
627   template<class Vec>
copyToIO(Vec && x,int n)628   void copyToIO(Vec&& x, int n)
629   {
630     assert(n < tot_num_walkers);
631     assert(x.size() >= walkerSizeIO());
632     assert(walker_buffer.size(1) == walker_size);
633     auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
634     using std::copy_n;
635     copy_n(W[n].origin(), walkerSizeIO(), x.origin());
636   }
637 
638   template<class Vec>
copyFromIO(Vec && x,int n)639   void copyFromIO(Vec&& x, int n)
640   {
641     assert(n < tot_num_walkers);
642     assert(x.size() >= walkerSizeIO());
643     assert(walker_buffer.size(1) == walker_size);
644     auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
645     using std::copy_n;
646     copy_n(x.origin(), walkerSizeIO(), W[n].origin());
647   }
648 
649   template<class TVec>
getProperty(walker_data id,TVec && v)650   void getProperty(walker_data id, TVec&& v) const
651   {
652     static_assert(std::decay<TVec>::type::dimensionality == 1, "Wrong dimensionality");
653     if (v.num_elements() < tot_num_walkers)
654       APP_ABORT("Error: getProperty(v):: v.size < tot_num_walkers.\n");
655     auto W_(boost::multi::static_array_cast<element, pointer>(walker_buffer));
656     ma::copy(W_({0, tot_num_walkers}, data_displ[id]), v.sliced(0, tot_num_walkers));
657   }
658 
659   template<class TVec>
setProperty(walker_data id,TVec && v)660   void setProperty(walker_data id, TVec&& v)
661   {
662     static_assert(std::decay<TVec>::type::dimensionality == 1, "Wrong dimensionality");
663     if (v.num_elements() < tot_num_walkers)
664       APP_ABORT("Error: setProperty(v):: v.size < tot_num_walkers.\n");
665     auto W_(boost::multi::static_array_cast<element, pointer>(walker_buffer));
666     ma::copy(v.sliced(0, tot_num_walkers), W_({0, tot_num_walkers}, data_displ[id]));
667   }
668 
resetWeights()669   void resetWeights()
670   {
671     TG.TG_local().barrier();
672     if (TG.TG_local().root())
673     {
674       boost::multi::array<element, 1> w_(iextensions<1u>{tot_num_walkers}, ComplexType(1.0));
675       setProperty(WEIGHT, w_);
676     }
677     TG.TG_local().barrier();
678   }
679 
680   // Careful!!! This matrix returns an array_ref, NOT a copy!!!
getFields(int ip)681   stdCMatrix_ptr getFields(int ip)
682   {
683     if (ip < 0 || ip > wlk_desc[3])
684       APP_ABORT(" Error: index out of bounds in getFields. \n");
685     int skip = (data_displ[FIELDS] + ip * wlk_desc[4]) * bp_buffer.size(1);
686     return stdCMatrix_ptr(to_address(bp_buffer.origin()) + skip, {wlk_desc[4], bp_buffer.size(1)});
687   }
688 
getFields()689   stdCTensor_ptr getFields()
690   {
691     return stdCTensor_ptr(to_address(bp_buffer.origin()) + data_displ[FIELDS] * bp_buffer.size(1),
692                           {wlk_desc[3], wlk_desc[4], bp_buffer.size(1)});
693   }
694 
695   template<class Mat>
storeFields(int ip,Mat && V)696   void storeFields(int ip, Mat&& V)
697   {
698     static_assert(std::decay<Mat>::type::dimensionality == 2, "Wrong dimensionality");
699     auto&& F(*getFields(ip));
700     if (V.stride(0) == V.size(1))
701     {
702       using std::copy_n;
703       copy_n(V.origin(), F.num_elements(), F.origin());
704     }
705     else
706       F = V;
707   }
708 
getWeightFactors()709   stdCMatrix_ptr getWeightFactors()
710   {
711     return stdCMatrix_ptr(to_address(bp_buffer.origin()) + data_displ[WEIGHT_FAC] * bp_buffer.size(1),
712                           {wlk_desc[6], bp_buffer.size(1)});
713   }
714 
getWeightHistory()715   stdCMatrix_ptr getWeightHistory()
716   {
717     return stdCMatrix_ptr(to_address(bp_buffer.origin()) + data_displ[WEIGHT_HISTORY] * bp_buffer.size(1),
718                           {wlk_desc[6], bp_buffer.size(1)});
719   }
720 
getLogOverlapFactor()721   double getLogOverlapFactor() const { return LogOverlapFactor; }
722   // nx= {2:CLOSED&&COLLINEAR, 1:NONCOLLINEAR }
723   // before: OV_full = exp( nx*LogOverlapFactor ) * OVold
724   // after: OV_full = exp( nx*LogOverlapFactor+f ) * OVnew
725   // OVnew = OVold * exp( -f )
726   // LogOverlapFactor_new = LogOverlapFactor + f/nx
adjustLogOverlapFactor(const double f)727   void adjustLogOverlapFactor(const double f)
728   {
729     assert(walker_buffer.size(1) == walker_size);
730     double nx = (walkerType == NONCOLLINEAR ? 1.0 : 2.0);
731     if (TG.TG_local().root())
732     {
733       auto W(boost::multi::static_array_cast<element, pointer>(walker_buffer));
734       ma::scal(ComplexType(std::exp(-f)), W({0, tot_num_walkers}, data_displ[OVLP]));
735     }
736     LogOverlapFactor += f / nx;
737     TG.TG_local().barrier();
738   }
739 
740 protected:
741   afqmc::TaskGroup_& TG;
742 
743   RandomGenerator_t* rng;
744 
745   int walker_size, walker_memory_usage;
746   int bp_walker_size, bp_walker_memory_usage;
747   int bp_pos;
748   int history_pos;
749 
750   // wlk_descriptor: {nmo, naea, naeb, nback_prop, nCV, nRefs, nHist}
751   wlk_descriptor wlk_desc;
752   wlk_indices data_displ;
753 
754   WALKER_TYPES walkerType;
755 
756   int targetN_per_TG;
757   int targetN;
758   int tot_num_walkers;
759 
760   // Stores an overall scaling factor for walker weights (assumed to be
761   // consistent over all walker groups).
762   // The actual overlap of a walker is exp(OverlapFactor)*wset[i].weight()
763   // Notice that overlap ratios (which are always what matters) are
764   // independent of this value.
765   // If this value is changed, the overlaps of the walkers must be adjusted
766   // This is needed for stability reasons in large systems
767   // Note that this is stored on a "per spin" capacity
768   double LogOverlapFactor = 0.0;
769 
770   TimerList_t Timers;
771 
772   // Contains main walker data needed for propagation
773   CMatrix walker_buffer;
774 
775   // Contains stack of fields and slater matrix references for back propagation
776   BPCMatrix bp_buffer;
777 
778   // reads xml and performs setup
779   void parse(xmlNodePtr cur);
780 
781   // performs setup
782   void setup();
783 
784   // load balance algorithm
785   LOAD_BALANCE_ALGORITHM load_balance;
786 
787   // load balancing algorithm
788   template<class Mat>
loadBalance(Mat && M)789   void loadBalance(Mat&& M)
790   {
791     if (load_balance == SIMPLE)
792     {
793       if (TG.TG_local().root())
794         afqmc::swapWalkersSimple(*this, std::forward<Mat>(M), nwalk_counts_old, nwalk_counts_new, TG.TG_heads());
795     }
796     else if (load_balance == ASYNC)
797     {
798       if (TG.TG_local().root())
799         afqmc::swapWalkersAsync(*this, std::forward<Mat>(M), nwalk_counts_old, nwalk_counts_new, TG.TG_heads());
800     }
801     TG.local_barrier();
802     // since tot_num_walkers is local, you need to sync it
803     if (TG.TG_local().size() > 1)
804       TG.TG_local().broadcast_n(&tot_num_walkers, 1, 0);
805   }
806 
807   // branching algorithm
808   BRANCHING_ALGORITHM pop_control;
809   double min_weight, max_weight;
810 
811   std::vector<int> nwalk_counts_new, nwalk_counts_old;
812 };
813 
814 } // namespace afqmc
815 
816 } // namespace qmcplusplus
817 
818 #include "AFQMC/Walkers/WalkerSetBase.icc"
819 
820 #endif
821