QMCPACK
InitMolecularSystem.cpp
Go to the documentation of this file.
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: Jordan E. Vincent, University of Illinois at Urbana-Champaign
8 // Luke Shulenburger, lshulen@sandia.gov, Sandia National Laboratories
9 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
10 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
11 // Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
12 // Mark Dewing, markdewing@gmail.com, University of Illinois at Urbana-Champaign
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 /**@file InitMolecularSystem.cpp
20  * @brief Implements InitMolecuarSystem operators.
21  */
22 #include "InitMolecularSystem.h"
24 #include "OhmmsData/AttributeSet.h"
25 #include "Particle/DistanceTable.h"
27 
28 namespace qmcplusplus
29 {
31 
33  : OhmmsElementBase(aname), ptclPool(pset)
34 {}
35 
36 bool InitMolecularSystem::put(xmlNodePtr cur)
37 {
38  std::string target("e"), source("i"), volume("no");
39  OhmmsAttributeSet hAttrib;
40  hAttrib.add(target, "target");
41  hAttrib.add(source, "source");
42  hAttrib.add(volume, "use_volume");
43  hAttrib.put(cur);
44  ParticleSet* els = ptclPool.getParticleSet(target);
45  if (els == 0)
46  {
47  ERRORMSG("No target particle " << target << " exists.")
48  return false;
49  }
50  ParticleSet* ions = ptclPool.getParticleSet(source);
51  if (ions == 0)
52  {
53  ERRORMSG("No source particle " << source << " exists.")
54  return false;
55  }
56 
57  app_log() << "<init source=\"" << source << "\" target=\"" << target << "\">" << std::endl;
58 
59  if (volume == "yes")
60  initWithVolume(ions, els);
61  else
62  initMolecule(ions, els);
63 
65  els->spins *= 2 * M_PI;
66 
67  app_log() << "</init>" << std::endl;
68  app_log().flush();
69 
70  return true;
71 }
72 
74 {
75  //3N-dimensional Gaussian
77  makeGaussRandom(chi);
78  RealType q = std::sqrt(static_cast<RealType>(els->getTotalNum())) * 0.5;
79  int nel(els->getTotalNum()), items(0);
80  while (nel)
81  {
82  els->R[items] = ions->R[0] + q * chi[items];
83  --nel;
84  ++items;
85  }
86 }
87 
89 {
90  int ID;
92  inline LoneElectron(int id, RealType bl) : ID(id), BondLength(bl) {}
93 };
94 
96 {
97  if (ions->getTotalNum() == 1)
98  return initAtom(ions, els);
99 
100  const int d_ii_ID = ions->addTable(*ions);
101  ions->update();
102  const ParticleSet::ParticleIndex& grID(ions->GroupID);
103  SpeciesSet& Species(ions->getSpeciesSet());
104  int Centers = ions->getTotalNum();
105  std::vector<int> Qtot(Centers), Qcore(Centers), Qval(Centers, 0);
106  //use charge as the core electrons first
107  int icharge = Species.addAttribute("charge");
108  //Assign default core charge
109  for (int iat = 0; iat < Centers; iat++)
110  Qtot[iat] = static_cast<int>(Species(icharge, grID[iat]));
111  //cutoff radius (Bohr) this a random choice
112  RealType cutoff = 4.0;
114  //makeGaussRandom(chi);
115  makeSphereRandom(chi);
116  // the upper limit of the electron index with spin up
117  const int numUp = els->last(0);
118  // the upper limit of the electron index with spin down. Pay attention to the no spin down electron case.
119  const int numDown = els->last(els->groups() > 1 ? 1 : 0) - els->first(0);
120  // consumer counter of random numbers chi
121  int random_number_counter = 0;
122  int nup_tot = 0, ndown_tot = numUp;
123  std::vector<LoneElectron> loneQ;
124  RealType rmin = cutoff;
126 
127  const auto& dist = ions->getDistTableAA(d_ii_ID).getDistances();
128  // Step 1. Distribute even Q[iat] of atomic center iat. If Q[iat] is odd, put Q[iat]-1 and save the lone electron.
129  for (size_t iat = 0; iat < Centers; iat++)
130  {
131  cm += ions->R[iat];
132  for (size_t jat = iat + 1; jat < Centers; ++jat)
133  {
134  rmin = std::min(rmin, dist[jat][iat]);
135  }
136  //use 40% of the minimum bond
137  RealType sep = rmin * 0.4;
138  int v2 = Qtot[iat] / 2;
139  if (Qtot[iat] > v2 * 2)
140  {
141  loneQ.push_back(LoneElectron(iat, sep));
142  }
143  for (int k = 0; k < v2; k++)
144  {
145  // initialize electron positions in pairs
146  if (nup_tot < numUp)
147  els->R[nup_tot++] = ions->R[iat] + sep * chi[random_number_counter++];
148  if (ndown_tot < numDown)
149  els->R[ndown_tot++] = ions->R[iat] + sep * chi[random_number_counter++];
150  }
151  }
152 
153  // Step 2. Distribute the electrons left alone
154  // mmorales: changed order of spin assignment to help with spin
155  // imbalances in molecules at large distances.
156  // Not guaranteed to work, but should help in most cases
157  // as long as atoms in molecules are defined sequencially
158  std::vector<LoneElectron>::iterator it(loneQ.begin());
159  std::vector<LoneElectron>::iterator it_end(loneQ.end());
160  while (it != it_end && nup_tot != numUp && ndown_tot != numDown)
161  {
162  if (nup_tot < numUp)
163  {
164  els->R[nup_tot++] = ions->R[(*it).ID] + (*it).BondLength * chi[random_number_counter++];
165  ++it;
166  }
167  if (ndown_tot < numDown && it != it_end)
168  {
169  els->R[ndown_tot++] = ions->R[(*it).ID] + (*it).BondLength * chi[random_number_counter++];
170  ++it;
171  }
172  }
173 
174  // Step 3. Handle more than neutral electrons
175  //extra electrons around the geometric center
176  RealType cnorm = 1.0 / static_cast<RealType>(Centers);
177  RealType sep = rmin * 2;
178  cm = cnorm * cm;
179  if (nup_tot < numUp)
180  while (nup_tot < numUp)
181  els->R[nup_tot++] = cm + sep * chi[random_number_counter++];
182  if (ndown_tot < numDown)
183  while (ndown_tot < numDown)
184  els->R[ndown_tot++] = cm + sep * chi[random_number_counter++];
185 
186  // safety check. all the random numbers should have been consumed once and only once.
187  if (random_number_counter != chi.size())
188  throw std::runtime_error("initMolecule unexpected random number consumption. Please report a bug!");
189 
190  //put all the electrons in a unit box
191  if (els->getLattice().SuperCellEnum != SUPERCELL_OPEN)
192  {
193  els->R.setUnit(PosUnit::Cartesian);
194  els->applyBC(els->R);
195  els->update(false);
196  }
197 }
198 
199 ///helper function to determine the lower bound of a domain (need to move up)
200 template<typename T>
202 {
203  return TinyVector<T, 3>(std::min(a[0], b[0]), std::min(a[1], b[1]), std::min(a[2], b[2]));
204 }
205 
206 ///helper function to determine the upper bound of a domain (need to move up)
207 template<typename T>
209 {
210  return TinyVector<T, 3>(std::max(a[0], b[0]), std::max(a[1], b[1]), std::max(a[2], b[2]));
211 }
212 
214 {
217 
220  ions->applyBC(ions->R, Ru);
221 
222  for (int iat = 0; iat < Ru.size(); iat++)
223  {
224  start = lower_bound(Ru[iat], start);
225  end = upper_bound(Ru[iat], end);
226  }
227 
229  Tensor<RealType, OHMMS_DIM> newbox(ions->getLattice().R);
230 
231  RealType buffer = 2.0; //buffer 2 bohr
232  for (int idim = 0; idim < OHMMS_DIM; ++idim)
233  {
234  //if(ions->getLattice().BoxBConds[idim])
235  //{
236  // start[idim]=0.0;
237  // end[idim]=1.0;
238  // shift[idim]=0.0;
239  //}
240  //else
241  {
242  RealType buffer_r = buffer * ions->getLattice().OneOverLength[idim];
243  start[idim] = std::max((RealType)0.0, (start[idim] - buffer_r));
244  end[idim] = std::min((RealType)1.0, (end[idim] + buffer_r));
245  shift[idim] = start[idim] * ions->getLattice().Length[idim];
246  if (std::abs(end[idim] = start[idim]) < buffer)
247  { //handle singular case
248  start[idim] = std::max(0.0, start[idim] - buffer_r / 2.0);
249  end[idim] = std::min(1.0, end[idim] + buffer_r / 2.0);
250  }
251 
252  newbox(idim, idim) = (end[idim] - start[idim]) * ions->getLattice().Length[idim];
253  }
254  }
255 
256  ParticleSet::ParticleLayout slattice(ions->getLattice());
257  slattice.set(newbox);
258 
259  app_log() << " InitMolecularSystem::initWithVolume " << std::endl;
260  app_log() << " Effective Lattice shifted by " << shift << std::endl;
261  app_log() << newbox << std::endl;
262 
263  Ru.resize(els->getTotalNum());
264  makeUniformRandom(Ru);
265  for (int iat = 0; iat < Ru.size(); ++iat)
266  els->R[iat] = slattice.toCart(Ru[iat]) + shift;
267  els->R.setUnit(PosUnit::Cartesian);
268 }
269 
270 bool InitMolecularSystem::put(std::istream& is) { return true; }
271 
272 bool InitMolecularSystem::get(std::ostream& os) const { return true; }
273 
275 } // namespace qmcplusplus
void set(const Tensor< TT, D > &lat)
set the lattice vector from the command-line options
a class that defines a supercell in D-dimensional Euclean space.
void makeUniformRandom(ParticleAttrib< TinyVector< T, D >> &a)
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
#define ERRORMSG(msg)
Definition: OutputManager.h:86
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
const DistanceTableAA & getDistTableAA(int table_ID) const
get a distance table by table_ID and dyanmic_cast to DistanceTableAA
ParticleScalar spins
internal spin variables for dynamical spin calculations
Definition: ParticleSet.h:81
QTBase::RealType RealType
Definition: Configuration.h:58
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
size_t getTotalNum() const
Definition: ParticleSet.h:493
std::ostream & app_log()
Definition: OutputManager.h:65
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
void applyBC(const ParticlePos &pin, ParticlePos &pout)
int first(int igroup) const
return the first index of a group i
Definition: ParticleSet.h:514
void update(bool skipSK=false)
update the internal data
Attaches a unit to a Vector for IO.
#define OHMMS_DIM
Definition: config.h:64
T min(T a, T b)
TinyVector< T, 3 > lower_bound(const TinyVector< T, 3 > &a, const TinyVector< T, 3 > &b)
helper function to determine the lower bound of a domain (need to move up)
ParticleIndex GroupID
Species ID.
Definition: ParticleSet.h:77
LoneElectron(int id, RealType bl)
int groups() const
return the number of groups
Definition: ParticleSet.h:511
int addTable(const ParticleSet &psrc, DTModes modes=DTModes::ALL_OFF)
add a distance table
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
void makeSphereRandom(ParticleAttrib< TinyVector< T, 3 >> &a)
Tensor<T,D> class for D by D tensor.
Definition: OhmmsTinyMeta.h:32
Declaration of InitMolecularSystem.
Abstract class to provide xml-compatible I/O interfaces for the derived classes.
ParticleSet * getParticleSet(const std::string &pname)
get a named ParticleSet
void makeGaussRandom(std::vector< TinyVector< T, D >> &a)
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
void initWithVolume(ParticleSet *ions, ParticleSet *els)
initialize els for the systems with a mixed boundary
Manage a collection of ParticleSet objects.
ParticlePos R
Position.
Definition: ParticleSet.h:79
int last(int igroup) const
return the last index of a group i
Definition: ParticleSet.h:517
TinyVector< T, 3 > upper_bound(const TinyVector< T, 3 > &a, const TinyVector< T, 3 > &b)
helper function to determine the upper bound of a domain (need to move up)
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
QMCTraits::RealType RealType
void initAtom(ParticleSet *ions, ParticleSet *els)
initialize els for an atom
void reset() override
reset member data
void initMolecule(ParticleSet *ions, ParticleSet *els)
initialize els position for a molecule
const std::vector< DistRow > & getDistances() const
return full table distances
InitMolecularSystem(ParticleSetPool &pset, const char *aname="mosystem")
bool get(std::ostream &os) const override
write to a std::ostream
const auto & getLattice() const
Definition: ParticleSet.h:251
Custom container for set of attributes for a set of species.
Definition: SpeciesSet.h:33
void add(PDT &aparam, const std::string &aname, std::vector< PDT > candidate_values={}, TagStatus status=TagStatus::OPTIONAL)
add a new attribute
Definition: AttributeSet.h:42
ParticleSetPool & ptclPool
pointer to ParticleSetPool
bool put(std::istream &is) override
read from std::istream
Declaration of ParticleSetPool.