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) 2020 QMCPACK developers. 6 // 7 // File developed by: Peter Doak, doakpw@ornl.gov, Oak Ridge National Laboratory 8 // 9 // File refactored from VMC.h 10 ////////////////////////////////////////////////////////////////////////////////////// 11 12 #ifndef QMCPLUSPLUS_MCPOPULATION_H 13 #define QMCPLUSPLUS_MCPOPULATION_H 14 15 #include <iterator> 16 #include <vector> 17 #include <memory> 18 19 #include "Configuration.h" 20 #include "type_traits/TypeRequire.hpp" 21 #include "Particle/ParticleSet.h" 22 #include "ParticleBase/ParticleAttrib.h" 23 #include "Particle/MCWalkerConfiguration.h" 24 #include "Particle/Walker.h" 25 #include "QMCWaveFunctions/TrialWaveFunction.h" 26 #include "QMCDrivers/WalkerElementsRef.h" 27 #include "OhmmsPETE/OhmmsVector.h" 28 #include "Utilities/FairDivide.h" 29 30 // forward declaration 31 namespace optimize 32 { 33 struct VariableSet; 34 } 35 36 namespace qmcplusplus 37 { 38 // forward declaration 39 class QMCHamiltonian; 40 class MCPopulation 41 { 42 public: 43 using MCPWalker = Walker<QMCTraits, PtclOnLatticeTraits>; 44 using WFBuffer = MCPWalker::WFBuffer_t; 45 using RealType = QMCTraits::RealType; 46 using Properties = MCPWalker::PropertyContainer_t; 47 using IndexType = QMCTraits::IndexType; 48 using FullPrecRealType = QMCTraits::FullPrecRealType; 49 using opt_variables_type = optimize::VariableSet; 50 51 private: 52 // Potential thread safety issue 53 MCDataType<QMCTraits::FullPrecRealType> ensemble_property_; 54 55 IndexType num_global_walkers_ = 0; 56 IndexType num_local_walkers_ = 0; 57 IndexType num_particles_ = 0; 58 IndexType num_groups_ = 0; 59 IndexType max_samples_ = 0; 60 IndexType target_population_ = 0; 61 IndexType target_samples_ = 0; 62 //Properties properties_; 63 ParticleSet ions_; 64 65 // By making this a linked list and creating the crowds at the same time we could get first touch. 66 UPtrVector<MCPWalker> walkers_; 67 UPtrVector<MCPWalker> dead_walkers_; 68 std::vector<std::pair<int, int>> particle_group_indexes_; 69 SpeciesSet species_set_; 70 std::vector<RealType> ptclgrp_mass_; 71 ///1/Mass per species 72 std::vector<RealType> ptclgrp_inv_mass_; 73 ///1/Mass per particle 74 std::vector<RealType> ptcl_inv_mass_; 75 76 // This is necessary MCPopulation is constructed in a simple call scope in QMCDriverFactory from the legacy MCWalkerConfiguration 77 // MCPopulation should have QMCMain scope eventually and the driver will just have a reference to it. 78 TrialWaveFunction* trial_wf_; 79 ParticleSet* elec_particle_set_; 80 QMCHamiltonian* hamiltonian_; 81 // At the moment these are "clones" but I think this design pattern smells. 82 UPtrVector<ParticleSet> walker_elec_particle_sets_; 83 UPtrVector<TrialWaveFunction> walker_trial_wavefunctions_; 84 UPtrVector<QMCHamiltonian> walker_hamiltonians_; 85 86 // We still haven't cleaned up the dependence between different walker elements so they all need to be tracked 87 // as in the legacy implementation. 88 UPtrVector<ParticleSet> dead_walker_elec_particle_sets_; 89 UPtrVector<TrialWaveFunction> dead_walker_trial_wavefunctions_; 90 UPtrVector<QMCHamiltonian> dead_walker_hamiltonians_; 91 92 // MCPopulation immutables 93 // would be nice if they were const but we'd lose the default move assignment 94 int num_ranks_; 95 int rank_; 96 97 // reference to the captured WalkerConfigurations 98 WalkerConfigurations& walker_configs_ref_; 99 100 public: 101 /** Temporary constructor to deal with MCWalkerConfiguration be the only source of some information 102 * in QMCDriverFactory. 103 */ 104 MCPopulation(int num_ranks, 105 int this_rank, 106 WalkerConfigurations& mcwc, 107 ParticleSet* elecs, 108 TrialWaveFunction* trial_wf, 109 QMCHamiltonian* hamiltonian_); 110 111 ~MCPopulation(); 112 MCPopulation(MCPopulation&) = delete; 113 MCPopulation& operator=(MCPopulation&) = delete; 114 MCPopulation(MCPopulation&&) = default; 115 116 /** @ingroup PopulationControl 117 * 118 * State Requirement: 119 * * createWalkers must have been called 120 * @{ 121 */ 122 WalkerElementsRef spawnWalker(); 123 void killWalker(MCPWalker&); 124 void killLastWalker(); 125 /** }@ */ 126 127 /** Creates walkers with a clone of the golden electron particle set and golden trial wavefunction 128 * 129 * \param[in] num_walkers number of living walkers in initial population 130 * \param[in] reserve multiple above that to reserve >=1.0 131 */ 132 void createWalkers(IndexType num_walkers, RealType reserve = 1.0); 133 134 /** distributes walkers and their "cloned" elements to the elements of a vector 135 * of unique_ptr to "walker_consumers". 136 * 137 * a valid "walker_consumer" has a member function of 138 * void addWalker(MCPWalker& walker, ParticleSet& elecs, TrialWaveFunction& twf, QMCHamiltonian& hamiltonian); 139 */ 140 template<typename WTTV> redistributeWalkers(WTTV & walker_consumers)141 void redistributeWalkers(WTTV& walker_consumers) 142 { 143 // The type returned here is dependent on the integral type that the walker_consumers 144 // use to return there size. 145 auto walkers_per_crowd = fairDivide(walkers_.size(), walker_consumers.size()); 146 147 auto walker_index = 0; 148 for (int i = 0; i < walker_consumers.size(); ++i) 149 { 150 walker_consumers[i]->clearWalkers(); 151 for (int j = 0; j < walkers_per_crowd[i]; ++j) 152 { 153 walker_consumers[i]->addWalker(*walkers_[walker_index], *walker_elec_particle_sets_[walker_index], 154 *walker_trial_wavefunctions_[walker_index], *walker_hamiltonians_[walker_index]); 155 ++walker_index; 156 } 157 } 158 } 159 160 void syncWalkersPerRank(Communicate* comm); 161 void measureGlobalEnergyVariance(Communicate& comm, FullPrecRealType& ener, FullPrecRealType& variance) const; 162 163 /**@ingroup Accessors 164 * @{ 165 */ 166 167 /** The number of cases in which this and get_num_local_walkers is so few that 168 * I strongly suspect it is a design issue. 169 * 170 * get_active_walkers is onlyh useful between the setting of num_local_walkers_ and 171 * creation of walkers. I would reason this is actually a time over which the MCPopulation object 172 * is invalid. Ideally MCPopulation not process any calls in this state, next best would be to only 173 * process calls to become valid. 174 */ 175 //IndexType get_active_walkers() const { return walkers_.size(); } get_num_ranks()176 int get_num_ranks() const { return num_ranks_; } get_rank()177 int get_rank() const { return rank_; } get_num_global_walkers()178 IndexType get_num_global_walkers() const { return num_global_walkers_; } get_num_local_walkers()179 IndexType get_num_local_walkers() const { return num_local_walkers_; } get_num_particles()180 IndexType get_num_particles() const { return num_particles_; } get_max_samples()181 IndexType get_max_samples() const { return max_samples_; } get_target_population()182 IndexType get_target_population() const { return target_population_; } get_target_samples()183 IndexType get_target_samples() const { return target_samples_; } 184 //const Properties& get_properties() const { return properties_; } get_species_set()185 const SpeciesSet& get_species_set() const { return species_set_; } get_ions()186 const ParticleSet& get_ions() const { return ions_; } 187 188 // accessor to the gold copy get_golden_electrons()189 const ParticleSet* get_golden_electrons() const { return elec_particle_set_; } get_golden_electrons()190 ParticleSet* get_golden_electrons() { return elec_particle_set_; } get_golden_twf()191 const TrialWaveFunction& get_golden_twf() const { return *trial_wf_; } get_golden_twf()192 TrialWaveFunction& get_golden_twf() { return *trial_wf_; } 193 // TODO: the fact this is needed is sad remove need for its existence. get_golden_hamiltonian()194 QMCHamiltonian& get_golden_hamiltonian() { return *hamiltonian_; } 195 set_num_global_walkers(IndexType num_global_walkers)196 void set_num_global_walkers(IndexType num_global_walkers) { num_global_walkers_ = num_global_walkers; } set_num_local_walkers(IndexType num_local_walkers)197 void set_num_local_walkers(IndexType num_local_walkers) { num_local_walkers_ = num_local_walkers; } 198 set_target(IndexType pop)199 void set_target(IndexType pop) { target_population_ = pop; } set_target_samples(IndexType samples)200 void set_target_samples(IndexType samples) { target_samples_ = samples; } 201 set_ensemble_property(const MCDataType<QMCTraits::FullPrecRealType> & ensemble_property)202 void set_ensemble_property(const MCDataType<QMCTraits::FullPrecRealType>& ensemble_property) 203 { 204 ensemble_property_ = ensemble_property; 205 } 206 get_walkers()207 UPtrVector<MCPWalker>& get_walkers() { return walkers_; } get_walkers()208 const UPtrVector<MCPWalker>& get_walkers() const { return walkers_; } get_dead_walkers()209 const UPtrVector<MCPWalker>& get_dead_walkers() const { return dead_walkers_; } 210 get_elec_particle_sets()211 UPtrVector<ParticleSet>& get_elec_particle_sets() { return walker_elec_particle_sets_; } 212 get_twfs()213 UPtrVector<TrialWaveFunction>& get_twfs() { return walker_trial_wavefunctions_; } get_dead_twfs()214 UPtrVector<TrialWaveFunction>& get_dead_twfs() { return dead_walker_trial_wavefunctions_; } 215 get_hamiltonians()216 UPtrVector<QMCHamiltonian>& get_hamiltonians() { return walker_hamiltonians_; } get_dead_hamiltonians()217 UPtrVector<QMCHamiltonian>& get_dead_hamiltonians() { return dead_walker_hamiltonians_; } 218 219 /** Non threadsafe access to walkers and their elements 220 * 221 * Prefer to distribute the walker elements and access 222 * through a crowd to support the concurrency design. 223 * 224 * You should not use this unless absolutely necessary. 225 * That doesn't include that you would rather just use 226 * omp parallel and ignore concurrency. 227 */ 228 WalkerElementsRef getWalkerElementsRef(const size_t walker_index); 229 230 /** As long as walker WalkerElements is used we need this for unit tests 231 * 232 * As operator[] don't use it to ignore the concurrency design. 233 */ 234 std::vector<WalkerElementsRef> get_walker_elements(); 235 get_particle_group_indexes()236 const std::vector<std::pair<int, int>>& get_particle_group_indexes() const { return particle_group_indexes_; } get_ptclgrp_mass()237 const std::vector<RealType>& get_ptclgrp_mass() const { return ptclgrp_mass_; } get_ptclgrp_inv_mass()238 const std::vector<RealType>& get_ptclgrp_inv_mass() const { return ptclgrp_inv_mass_; } get_ptcl_inv_mass()239 const std::vector<RealType>& get_ptcl_inv_mass() const { return ptcl_inv_mass_; } 240 241 /** }@ */ 242 243 244 /// Set variational parameters for the per-walker copies of the wavefunction. 245 void set_variational_parameters(const opt_variables_type& active); 246 247 /// check if all the internal vector contain consistent sizes; 248 void checkIntegrity() const; 249 getWalkerConfigsRef()250 WalkerConfigurations& getWalkerConfigsRef() { return walker_configs_ref_; } 251 252 // save walker configurations to walker_configs_ref_ 253 void saveWalkerConfigurations(); 254 }; 255 256 } // namespace qmcplusplus 257 258 #endif 259