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: D. Das, University of Illinois at Urbana-Champaign
8 //                    Bryan Clark, bclark@Princeton.edu, Princeton University
9 //                    Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
10 //                    Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
11 //                    Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
12 //                    Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
13 //                    Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
14 //
15 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
16 //////////////////////////////////////////////////////////////////////////////////////
17 
18 
19 #ifndef QMCPLUSPLUS_PARTICLESET_H
20 #define QMCPLUSPLUS_PARTICLESET_H
21 
22 #include <Configuration.h>
23 #include "ParticleTags.h"
24 #include "DynamicCoordinates.h"
25 #include "Walker.h"
26 #include "Utilities/SpeciesSet.h"
27 #include "Utilities/PooledData.h"
28 #include "OhmmsPETE/OhmmsArray.h"
29 #include "Utilities/TimerManager.h"
30 #include "OhmmsSoA/VectorSoaContainer.h"
31 #include "type_traits/template_types.hpp"
32 
33 namespace qmcplusplus
34 {
35 ///forward declaration of DistanceTableData
36 class DistanceTableData;
37 class ResourceCollection;
38 class StructFact;
39 
40 /** Specialized paritlce class for atomistic simulations
41  *
42  * Derived from QMCTraits, ParticleBase<PtclOnLatticeTraits> and OhmmsElementBase.
43  * The ParticleLayout class represents a supercell with/without periodic boundary
44  * conditions. The ParticleLayout class also takes care of spatial decompositions
45  * for efficient evaluations for the interactions with a finite cutoff.
46  */
47 class ParticleSet : public QMCTraits, public OhmmsElementBase, public PtclOnLatticeTraits
48 {
49 public:
50   /// walker type
51   typedef Walker<QMCTraits, PtclOnLatticeTraits> Walker_t;
52   /// container type to store the property
53   typedef Walker_t::PropertyContainer_t PropertyContainer_t;
54   /// buffer type for a serialized buffer
55   typedef PooledData<RealType> Buffer_t;
56 
57   enum quantum_domains
58   {
59     no_quantum_domain = 0,
60     classical,
61     quantum
62   };
63 
64   ///quantum_domain of the particles, default = classical
65   quantum_domains quantum_domain;
66 
67   //@{ public data members
68   ///ParticleLayout
69   ParticleLayout_t Lattice, PrimitiveLattice;
70   ///Long-range box
71   ParticleLayout_t LRBox;
72 
73   ///unique, persistent ID for each particle
74   ParticleIndex_t ID;
75   ///index to the primitice cell with tiling
76   ParticleIndex_t PCID;
77   /** ID map that reflects species group
78    *
79    * IsGrouped=true, if ID==IndirectID
80    */
81   ParticleIndex_t IndirectID;
82   ///Species ID
83   ParticleIndex_t GroupID;
84   ///Position
85   ParticlePos_t R;
86   ///internal spin variables for dynamical spin calculations
87   ParticleScalar_t spins;
88   ///gradients of the particles
89   ParticleGradient_t G;
90   ///laplacians of the particles
91   ParticleLaplacian_t L;
92   ///differential gradients of the particles
93   ParticleGradient_t dG;
94   ///differential laplacians of the particles
95   ParticleLaplacian_t dL;
96   ///mass of each particle
97   ParticleScalar_t Mass;
98   ///charge of each particle
99   ParticleScalar_t Z;
100 
101   ///true if the particles are grouped
102   bool IsGrouped;
103   ///true if the particles have the same mass
104   bool SameMass;
105   ///threa id
106   Index_t ThreadID;
107   /** the index of the active particle during particle-by-particle moves
108    *
109    * when a single particle move is proposed, the particle id is assigned to activePtcl
110    * No matter the move is accepted or rejected, activePtcl is marked back to -1.
111    * This state flag is used for picking coordinates and distances for SPO evaluation.
112    */
113   Index_t activePtcl;
114   ///the group of the active particle during particle-by-particle moves
115   Index_t activeGroup;
116   ///the index of the active bead for particle-by-particle moves
117   Index_t activeBead;
118   ///the direction reptile traveling
119   Index_t direction;
120 
121   ///the proposed position of activePtcl during particle-by-particle moves
122   SingleParticlePos_t activePos;
123 
124   ///the proposed spin of activePtcl during particle-by-particle moves
125   Scalar_t activeSpinVal;
126 
127   ///the proposed position in the Lattice unit
128   SingleParticlePos_t newRedPos;
129 
130   ///SpeciesSet of particles
131   SpeciesSet mySpecies;
132 
133   ///Structure factor
134   std::unique_ptr<StructFact> SK;
135 
136   ///Particle density in G-space for MPC interaction
137   std::vector<TinyVector<int, OHMMS_DIM>> DensityReducedGvecs;
138   std::vector<ComplexType> Density_G;
139   Array<RealType, OHMMS_DIM> Density_r;
140 
141   /// DFT potential
142   std::vector<TinyVector<int, OHMMS_DIM>> VHXCReducedGvecs;
143   std::vector<ComplexType> VHXC_G[2];
144   Array<RealType, OHMMS_DIM> VHXC_r[2];
145 
146   /** name-value map of Walker Properties
147    *
148    * PropertyMap is used to keep the name-value mapping of
149    * Walker_t::Properties.  PropertyList::Values are not
150    * necessarily updated during the simulations.
151    */
152   PropertySetType PropertyList;
153 
154   /** properties of the current walker
155    *
156    * The internal order is identical to PropertyList, which holds
157    * the matching names.
158    */
159   PropertyContainer_t Properties;
160 
161   /** observables in addition to those registered in Properties/PropertyList
162    *
163    * Such observables as density, gofr, sk are not stored per walker but
164    * collected during QMC iterations.
165    */
166   Buffer_t Collectables;
167 
168   ///clones of this object: used by the thread pool
169   std::vector<ParticleSet*> myClones;
170 
171   ///Property history vector
172   std::vector<std::vector<FullPrecRealType>> PropertyHistory;
173   std::vector<int> PHindex;
174   ///@}
175 
176   ///current MC step
177   int current_step;
178 
179   ///default constructor
180   ParticleSet(const DynamicCoordinateKind kind = DynamicCoordinateKind::DC_POS);
181 
182   ///copy constructor
183   ParticleSet(const ParticleSet& p);
184 
185   ///default destructor
186   virtual ~ParticleSet();
187 
188   /** create  particles
189    * @param n number of particles
190    */
191   void create(int n);
192   /** create grouped particles
193    * @param agroup number of particles per group
194    */
195   void create(const std::vector<int>& agroup);
196 
197   ///write to a std::ostream
198   bool get(std::ostream&) const;
199 
200   ///read from std::istream
201   bool put(std::istream&);
202 
203   ///reset member data
204   void reset();
205 
206   ///initialize ParticleSet from xmlNode
207   bool put(xmlNodePtr cur);
208 
209   ///specify quantum_domain of particles
210   void set_quantum_domain(quantum_domains qdomain);
211 
set_quantum()212   void set_quantum() { quantum_domain = quantum; }
213 
is_classical()214   inline bool is_classical() const { return quantum_domain == classical; }
215 
is_quantum()216   inline bool is_quantum() const { return quantum_domain == quantum; }
217 
218   ///check whether quantum domain is valid for particles
quantum_domain_valid(quantum_domains qdomain)219   inline bool quantum_domain_valid(quantum_domains qdomain) const { return qdomain != no_quantum_domain; }
220 
221   ///check whether quantum domain is valid for particles
quantum_domain_valid()222   inline bool quantum_domain_valid() const { return quantum_domain_valid(quantum_domain); }
223 
224   /** add a distance table
225    * @param psrc source particle set
226    * @param need_full_table if true, DT is fully computed in loadWalker() and maintained up-to-date during p-by-p moving
227    *
228    * if this->myName == psrc.getName(), AA type. Otherwise, AB type.
229    */
230   int addTable(const ParticleSet& psrc, bool need_full_table = false);
231 
232   /** get a distance table by table_ID
233    */
getDistTable(int table_ID)234   inline const DistanceTableData& getDistTable(int table_ID) const { return *DistTables[table_ID]; }
235 
236   /** reset all the collectable quantities during a MC iteration
237    */
resetCollectables()238   inline void resetCollectables() { std::fill(Collectables.begin(), Collectables.end(), 0.0); }
239 
240   /** update the internal data
241    *@param skip SK update if skipSK is true
242    */
243   void update(bool skipSK = false);
244 
245   /// batched version of update
246   static void mw_update(const RefVectorWithLeader<ParticleSet>& p_list, bool skipSK = false);
247 
248   /** create Structure Factor with PBCs
249    */
250   void createSK();
251 
252   /** Turn on per particle storage in Structure Factor
253    */
254   void turnOnPerParticleSK();
255 
256   ///retrun the SpeciesSet of this particle set
getSpeciesSet()257   inline SpeciesSet& getSpeciesSet() { return mySpecies; }
258   ///retrun the const SpeciesSet of this particle set
getSpeciesSet()259   inline const SpeciesSet& getSpeciesSet() const { return mySpecies; }
260 
261   ///return parent's name
parentName()262   inline const std::string& parentName() const { return ParentName; }
setName(const std::string & aname)263   inline void setName(const std::string& aname)
264   {
265     myName = aname;
266     if (ParentName == "0")
267     {
268       ParentName = aname;
269     }
270   }
271 
getCoordinates()272   inline const DynamicCoordinates& getCoordinates() const { return *coordinates_; }
setCoordinates(const ParticlePos_t & R)273   inline void setCoordinates(const ParticlePos_t& R) { return coordinates_->setAllParticlePos(R); }
274 
275   //inline RealType getTotalWeight() const { return EnsembleProperty.Weight; }
276 
277   void resetGroups();
278 
279   /** return the position of the active particle
280    *
281    * activePtcl=-1 is used to flag non-physical moves
282    */
activeR(int iat)283   inline const PosType& activeR(int iat) const { return (activePtcl == iat) ? activePos : R[iat]; }
activeSpin(int iat)284   inline const Scalar_t& activeSpin(int iat) const { return (activePtcl == iat) ? activeSpinVal : spins[iat]; }
285   /** move the iat-th particle to activePos
286    * @param iat the index of the particle to be moved
287    * @param displ the displacement of the iat-th particle position
288    * @param maybe_accept if false, the caller guarantees that the proposed move will not be accepted.
289    *
290    * Update activePtcl index and activePos position (R[iat]+displ) for a proposed move.
291    * Evaluate the related distance table data DistanceTableData::Temp.
292    * If maybe_accept = false, certain operations for accepting moves will be skipped for optimal performance.
293    */
294   void makeMove(Index_t iat, const SingleParticlePos_t& displ, bool maybe_accept = true);
295   /// makeMove, but now includes an update to the spin variable
296   void makeMoveWithSpin(Index_t iat, const SingleParticlePos_t& displ, const Scalar_t& sdispl);
297 
298   /// batched version of makeMove
299   static void mw_makeMove(const RefVectorWithLeader<ParticleSet>& p_list,
300                           int iat,
301                           const std::vector<SingleParticlePos_t>& displs);
302 
303   /** move the iat-th particle to activePos
304    * @param iat the index of the particle to be moved
305    * @param displ random displacement of the iat-th particle
306    * @return true, if the move is valid
307    *
308    * Update activePtcl index and activePos position (R[iat]+displ) for a proposed move.
309    * Evaluate the related distance table data DistanceTableData::Temp.
310    *
311    * When a Lattice is defined, passing two checks makes a move valid.
312    * outOfBound(displ): invalid move, if displ is larger than half, currently, of the box in any direction
313    * isValid(Lattice.toUnit(activePos)): invalid move, if activePos goes out of the Lattice in any direction marked with open BC.
314    * Note: activePos and distances tables are always evaluated no matter the move is valid or not.
315    */
316   bool makeMoveAndCheck(Index_t iat, const SingleParticlePos_t& displ);
317   /// makeMoveAndCheck, but now includes an update to the spin variable
318   bool makeMoveAndCheckWithSpin(Index_t iat, const SingleParticlePos_t& displ, const Scalar_t& sdispl);
319 
320   /** Handles virtual moves for all the particles to a single newpos.
321    *
322    * The state activePtcl remains -1 and rejectMove is not needed.
323    * acceptMove can not be used.
324    * See QMCHamiltonians::MomentumEstimator as an example
325    */
326   void makeVirtualMoves(const SingleParticlePos_t& newpos);
327 
328   /** move all the particles of a walker
329    * @param awalker the walker to operate
330    * @param deltaR proposed displacement
331    * @param dt  factor of deltaR
332    * @return true if all the moves are legal.
333    *
334    * If big displacements or illegal positions are detected, return false.
335    * If all good, R = awalker.R + dt* deltaR
336    */
337   bool makeMoveAllParticles(const Walker_t& awalker, const ParticlePos_t& deltaR, RealType dt);
338 
339   bool makeMoveAllParticles(const Walker_t& awalker, const ParticlePos_t& deltaR, const std::vector<RealType>& dt);
340   /** move all the particles including the drift
341    *
342    * Otherwise, everything is the same as makeMove for a walker
343    */
344   bool makeMoveAllParticlesWithDrift(const Walker_t& awalker,
345                                      const ParticlePos_t& drift,
346                                      const ParticlePos_t& deltaR,
347                                      RealType dt);
348 
349   bool makeMoveAllParticlesWithDrift(const Walker_t& awalker,
350                                      const ParticlePos_t& drift,
351                                      const ParticlePos_t& deltaR,
352                                      const std::vector<RealType>& dt);
353 
354   /** accept or reject a proposed move
355    *  Two operation modes:
356    *  The using and updating distance tables via `ParticleSet` operate in two modes, regular and forward modes.
357    *
358    *  Regular mode
359    *  The regular mode can only be used when the distance tables for particle pairs are fully up-to-date.
360    *  This is the case after calling `ParticleSet::update()` in a unit test or after p-by-p moves in a QMC driver.
361    *  In this mode, the distance tables remain up-to-date after calling `ParticleSet::acceptMove`
362    *  and calling `ParticleSet::rejectMove` is not mandatory.
363    *
364    *  Forward mode
365    *  The forward mode assumes that distance table is not fully up-to-date until every particle is accepted
366    *  or rejected to move once in order. This is the mode used in the p-by-p part of drivers.
367    *  In this mode, calling `ParticleSet::accept_rejectMove` is required to handle accept/reject rather than
368    *  calling individual `ParticleSet::acceptMove` and `ParticleSet::reject`.
369    *  `ParticleSet::accept_rejectMove(iel)` ensures the distance tables (jel < iel) part is fully up-to-date
370    *  regardless a move is accepted or rejected. For this reason, the rejecting operation inside
371    *  `ParticleSet::accept_rejectMove` involves writing the distances with respect to the old particle position.
372    */
373   void accept_rejectMove(Index_t iat, bool accepted, bool forward_mode = true);
374 
375   /** accept the move and update the particle attribute by the proposed move in regular mode
376    *@param iat the index of the particle whose position and other attributes to be updated
377    */
378   void acceptMove(Index_t iat);
379 
380   /** reject a proposed move in regular mode
381    * @param iat the electron whose proposed move gets rejected.
382    */
383   void rejectMove(Index_t iat);
384   /// batched version of acceptMove and rejectMove fused
385   static void mw_accept_rejectMove(const RefVectorWithLeader<ParticleSet>& p_list,
386                                    Index_t iat,
387                                    const std::vector<bool>& isAccepted,
388                                    bool forward_mode = true);
389 
390   void initPropertyList();
addProperty(const std::string & pname)391   inline int addProperty(const std::string& pname) { return PropertyList.add(pname.c_str()); }
392 
393   int addPropertyHistory(int leng);
394   //        void rejectedMove();
395   //        void resetPropertyHistory( );
396   //        void addPropertyHistoryPoint(int index, RealType data);
397 
398   void clearDistanceTables();
399 
400   void convert(const ParticlePos_t& pin, ParticlePos_t& pout);
401   void convert2Unit(const ParticlePos_t& pin, ParticlePos_t& pout);
402   void convert2Cart(const ParticlePos_t& pin, ParticlePos_t& pout);
403   void convert2Unit(ParticlePos_t& pout);
404   void convert2Cart(ParticlePos_t& pout);
405   void convert2UnitInBox(const ParticlePos_t& pint, ParticlePos_t& pout);
406   void convert2CartInBox(const ParticlePos_t& pint, ParticlePos_t& pout);
407 
408   void applyBC(const ParticlePos_t& pin, ParticlePos_t& pout);
409   void applyBC(ParticlePos_t& pos);
410   void applyBC(const ParticlePos_t& pin, ParticlePos_t& pout, int first, int last);
411   void applyMinimumImage(ParticlePos_t& pinout);
412 
413   /** load a Walker_t to the current ParticleSet
414    * @param awalker the reference to the walker to be loaded
415    * @param pbyp true if it is used by PbyP update
416    *
417    * PbyP requires the distance tables and Sk with awalker.R
418    */
419   void loadWalker(Walker_t& awalker, bool pbyp);
420   /** batched version of loadWalker */
421   static void mw_loadWalker(const RefVectorWithLeader<ParticleSet>& p_list,
422                             const RefVector<Walker_t>& walkers,
423                             const std::vector<bool>& recompute,
424                             bool pbyp);
425 
426   /** save this to awalker
427    *
428    *  just the R, G, and L
429    *  More duplicate data that makes code difficult to reason about should be removed.
430    */
431   void saveWalker(Walker_t& awalker);
432 
433   /** batched version of saveWalker
434    *
435    *  just the R, G, and L
436    */
437   static void mw_saveWalker(const RefVectorWithLeader<ParticleSet>& psets, const RefVector<Walker_t>& walkers);
438 
439   /** update structure factor and unmark activePtcl
440    *
441    * The Coulomb interaction evaluation needs the structure factor.
442    * For these reason, call donePbyP after the loop of single
443    * electron moves before evaluating the Hamiltonian. Unmark
444    * activePtcl is more of a safety measure probably not needed.
445    */
446   void donePbyP();
447   /// batched version of donePbyP
448   static void mw_donePbyP(const RefVectorWithLeader<ParticleSet>& p_list);
449 
450   ///return the address of the values of Hamiltonian terms
getPropertyBase()451   inline FullPrecRealType* restrict getPropertyBase() { return Properties.data(); }
452 
453   ///return the address of the values of Hamiltonian terms
getPropertyBase()454   inline const FullPrecRealType* restrict getPropertyBase() const { return Properties.data(); }
455 
456   ///return the address of the i-th properties
getPropertyBase(int i)457   inline FullPrecRealType* restrict getPropertyBase(int i) { return Properties[i]; }
458 
459   ///return the address of the i-th properties
getPropertyBase(int i)460   inline const FullPrecRealType* restrict getPropertyBase(int i) const { return Properties[i]; }
461 
setTwist(SingleParticlePos_t & t)462   inline void setTwist(SingleParticlePos_t& t) { myTwist = t; }
getTwist()463   inline SingleParticlePos_t getTwist() const { return myTwist; }
464 
465   /** Initialize particles around another ParticleSet
466    * Used to initialize an electron ParticleSet by an ion ParticleSet
467    */
468   void randomizeFromSource(ParticleSet& src);
469 
470   /** return the ip-th clone
471    * @param ip thread number
472    *
473    * Return itself if ip==0
474    */
get_clone(int ip)475   inline ParticleSet* get_clone(int ip)
476   {
477     if (ip >= myClones.size())
478       return 0;
479     return (ip) ? myClones[ip] : this;
480   }
481 
get_clone(int ip)482   inline const ParticleSet* get_clone(int ip) const
483   {
484     if (ip >= myClones.size())
485       return 0;
486     return (ip) ? myClones[ip] : this;
487   }
488 
clones_size()489   inline int clones_size() const { return myClones.size(); }
490 
491   /** update R of its own and its clones
492    * @param rnew new position array of N
493    */
494   template<typename PAT>
update_clones(const PAT & rnew)495   inline void update_clones(const PAT& rnew)
496   {
497     if (R.size() != rnew.size())
498       APP_ABORT("ParticleSet::updateR failed due to different sizes");
499     R = rnew;
500     for (int ip = 1; ip < myClones.size(); ++ip)
501       myClones[ip]->R = rnew;
502   }
503 
504   /** reset internal data of clones including itself
505    */
506   void reset_clones();
507 
508   /** get species name of particle i
509    */
species_from_index(int i)510   inline const std::string& species_from_index(int i) { return mySpecies.speciesName[GroupID[i]]; }
511 
getTotalNum()512   inline size_t getTotalNum() const { return TotalNum; }
513 
resize(size_t numPtcl)514   inline void resize(size_t numPtcl)
515   {
516     TotalNum = numPtcl;
517 
518     R.resize(numPtcl);
519     spins.resize(numPtcl);
520     ID.resize(numPtcl);
521     PCID.resize(numPtcl);
522     GroupID.resize(numPtcl);
523     G.resize(numPtcl);
524     dG.resize(numPtcl);
525     L.resize(numPtcl);
526     dL.resize(numPtcl);
527     Mass.resize(numPtcl);
528     Z.resize(numPtcl);
529     IndirectID.resize(numPtcl);
530 
531     coordinates_->resize(numPtcl);
532   }
533 
clear()534   inline void clear()
535   {
536     TotalNum = 0;
537 
538     R.clear();
539     spins.clear();
540     ID.clear();
541     PCID.clear();
542     GroupID.clear();
543     G.clear();
544     dG.clear();
545     L.clear();
546     dL.clear();
547     Mass.clear();
548     Z.clear();
549     IndirectID.clear();
550 
551     coordinates_->resize(0);
552   }
553 
assign(const ParticleSet & ptclin)554   inline void assign(const ParticleSet& ptclin)
555   {
556     resize(ptclin.getTotalNum());
557     Lattice          = ptclin.Lattice;
558     PrimitiveLattice = ptclin.PrimitiveLattice;
559     R.InUnit         = ptclin.R.InUnit;
560     R                = ptclin.R;
561     spins            = ptclin.spins;
562     ID               = ptclin.ID;
563     GroupID          = ptclin.GroupID;
564     if (ptclin.SubPtcl.size())
565     {
566       SubPtcl.resize(ptclin.SubPtcl.size());
567       SubPtcl = ptclin.SubPtcl;
568     }
569   }
570 
571   ///return the number of groups
groups()572   inline int groups() const { return SubPtcl.size() - 1; }
573 
574   ///return the first index of a group i
first(int igroup)575   inline int first(int igroup) const { return SubPtcl[igroup]; }
576 
577   ///return the last index of a group i
last(int igroup)578   inline int last(int igroup) const { return SubPtcl[igroup + 1]; }
579 
580   ///return the group id of a given particle in the particle set.
getGroupID(int iat)581   inline int getGroupID(int iat) const
582   {
583     assert(iat >= 0 && iat < TotalNum);
584     return GroupID[iat];
585   }
586 
587   ///return the size of a group
groupsize(int igroup)588   inline int groupsize(int igroup) const { return SubPtcl[igroup + 1] - SubPtcl[igroup]; }
589 
590   ///add attributes to list for IO
591   template<typename ATList>
createAttributeList(ATList & AttribList)592   inline void createAttributeList(ATList& AttribList)
593   {
594     R.setTypeName(ParticleTags::postype_tag);
595     R.setObjName(ParticleTags::position_tag);
596     spins.setTypeName(ParticleTags::scalartype_tag);
597     spins.setObjName(ParticleTags::spins_tag);
598     ID.setTypeName(ParticleTags::indextype_tag);
599     ID.setObjName(ParticleTags::id_tag);
600     GroupID.setTypeName(ParticleTags::indextype_tag);
601     GroupID.setObjName(ParticleTags::ionid_tag);
602     //add basic attributes
603     AttribList.add(R);
604     AttribList.add(spins);
605     AttribList.add(ID);
606     AttribList.add(GroupID);
607 
608     G.setTypeName(ParticleTags::gradtype_tag);
609     L.setTypeName(ParticleTags::laptype_tag);
610     dG.setTypeName(ParticleTags::gradtype_tag);
611     dL.setTypeName(ParticleTags::laptype_tag);
612 
613     G.setObjName("grad");
614     L.setObjName("lap");
615     dG.setObjName("dgrad");
616     dL.setObjName("dlap");
617 
618     AttribList.add(G);
619     AttribList.add(L);
620     AttribList.add(dG);
621     AttribList.add(dL);
622 
623     //more particle attributes
624     Mass.setTypeName(ParticleTags::scalartype_tag);
625     Mass.setObjName("mass");
626     AttribList.add(Mass);
627 
628     Z.setTypeName(ParticleTags::scalartype_tag);
629     Z.setObjName("charge");
630     AttribList.add(Z);
631 
632     PCID.setTypeName(ParticleTags::indextype_tag); //add PCID tags
633     PCID.setObjName("pcid");
634     AttribList.add(PCID);
635 
636     IndirectID.setTypeName(ParticleTags::indextype_tag); //add IndirectID tags
637     IndirectID.setObjName("id1");
638     AttribList.add(IndirectID);
639   }
640 
getNumDistTables()641   inline int getNumDistTables() const { return DistTables.size(); }
642 
643   /// initialize a shared resource and hand it to a collection
644   void createResource(ResourceCollection& collection) const;
645   /** acquire external resource and assocaite it with the list of ParticleSet
646    * Note: use RAII ResourceCollectionTeamLock whenever possible
647    */
648   static void acquireResource(ResourceCollection& collection, const RefVectorWithLeader<ParticleSet>& p_list);
649   /** release external resource
650    * Note: use RAII ResourceCollectionTeamLock whenever possible
651    */
652   static void releaseResource(ResourceCollection& collection, const RefVectorWithLeader<ParticleSet>& p_list);
653 
654   static RefVectorWithLeader<DistanceTableData> extractDTRefList(const RefVectorWithLeader<ParticleSet>& p_list,
655                                                                  int id);
656   static RefVectorWithLeader<DynamicCoordinates> extractCoordsRefList(const RefVectorWithLeader<ParticleSet>& p_list);
657 
658 protected:
659   /** map to handle distance tables
660    *
661    * myDistTableMap[source-particle-tag]= locator in the distance table
662    * myDistTableMap[ObjectTag] === 0
663    */
664   std::map<std::string, int> myDistTableMap;
665 
666   /// distance tables that need to be updated by moving this ParticleSet
667   std::vector<DistanceTableData*> DistTables;
668 
669   /// Descriptions from distance table creation.  Same order as DistTables.
670   std::vector<std::string> distTableDescriptions;
671 
672   TimerList_t myTimers;
673 
674   SingleParticlePos_t myTwist;
675 
676   std::string ParentName;
677 
678   ///total number of particles
679   size_t TotalNum;
680 
681   ///array to handle a group of distinct particles per species
682   ParticleIndex_t SubPtcl;
683   ///internal representation of R. It can be an SoA copy of R
684   std::unique_ptr<DynamicCoordinates> coordinates_;
685 
686   /** compute temporal DistTables and SK for a new particle position
687    *
688    * @param iat the particle that is moved on a sphere
689    * @param newpos a new particle position
690    * @param maybe_accept if false, the caller guarantees that the proposed move will not be accepted.
691    */
692   void computeNewPosDistTablesAndSK(Index_t iat, const SingleParticlePos_t& newpos, bool maybe_accept = true);
693 
694 
695   /** compute temporal DistTables and SK for a new particle position for each walker in a batch
696    *
697    * @param p_list the list of wrapped ParticleSet references in a walker batch
698    * @param iat the particle that is moved on a sphere
699    * @param new_positions new particle positions
700    * @param maybe_accept if false, the caller guarantees that the proposed move will not be accepted.
701    */
702   static void mw_computeNewPosDistTablesAndSK(const RefVectorWithLeader<ParticleSet>& p_list,
703                                               Index_t iat,
704                                               const std::vector<SingleParticlePos_t>& new_positions,
705                                               bool maybe_accept = true);
706 
707   /** actual implemenation for accepting a proposed move, support both regular and forward modes
708    *
709    * @param iat the index of the particle whose position and other attributes to be updated
710    * @param forward_mode if ture, in forward mode.
711    */
712   void acceptMove_impl(Index_t iat, bool forward_mode);
713 
714   /** reject a proposed move in forward mode
715    * @param iat the electron whose proposed move gets rejected.
716    */
717   void rejectMoveForwardMode(Index_t iat);
718 };
719 
720 } // namespace qmcplusplus
721 #endif
722