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