CoMD
A Mini-app for Co-Design of Classical Molecular Dynamics.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
initAtoms.c
Go to the documentation of this file.
1 /// \file
2 /// Initialize the atom configuration.
3 
4 #include "initAtoms.h"
5 
6 #include <math.h>
7 #include <assert.h>
8 
9 #include "constants.h"
10 #include "decomposition.h"
11 #include "parallel.h"
12 #include "random.h"
13 #include "linkCells.h"
14 #include "timestep.h"
15 #include "memUtils.h"
16 #include "performanceTimers.h"
17 
18 static void computeVcm(SimFlat* s, real_t vcm[3]);
19 
20 /// \details
21 /// Call functions such as createFccLattice and setTemperature to set up
22 /// initial atom positions and momenta.
24 {
25  Atoms* atoms = comdMalloc(sizeof(Atoms));
26 
27  int maxTotalAtoms = MAXATOMS*boxes->nTotalBoxes;
28 
29  atoms->gid = (int*) comdMalloc(maxTotalAtoms*sizeof(int));
30  atoms->iSpecies = (int*) comdMalloc(maxTotalAtoms*sizeof(int));
31  atoms->r = (real3*) comdMalloc(maxTotalAtoms*sizeof(real3));
32  atoms->p = (real3*) comdMalloc(maxTotalAtoms*sizeof(real3));
33  atoms->f = (real3*) comdMalloc(maxTotalAtoms*sizeof(real3));
34  atoms->U = (real_t*)comdMalloc(maxTotalAtoms*sizeof(real_t));
35 
36  atoms->nLocal = 0;
37  atoms->nGlobal = 0;
38 
39  for (int iOff = 0; iOff < maxTotalAtoms; iOff++)
40  {
41  atoms->gid[iOff] = 0;
42  atoms->iSpecies[iOff] = 0;
43  zeroReal3(atoms->r[iOff]);
44  zeroReal3(atoms->p[iOff]);
45  zeroReal3(atoms->f[iOff]);
46  atoms->U[iOff] = 0.;
47  }
48 
49  return atoms;
50 }
51 
52 void destroyAtoms(Atoms *atoms)
53 {
54  freeMe(atoms,gid);
55  freeMe(atoms,iSpecies);
56  freeMe(atoms,r);
57  freeMe(atoms,p);
58  freeMe(atoms,f);
59 }
60 
61 /// Creates atom positions on a face centered cubic (FCC) lattice with
62 /// nx * ny * nz unit cells and lattice constant lat.
63 /// Set momenta to zero.
64 void createFccLattice(int nx, int ny, int nz, real_t lat, SimFlat* s)
65 {
66  const real_t* localMin = s->domain->localMin; // alias
67  const real_t* localMax = s->domain->localMax; // alias
68 
69  int nb = 4; // number of atoms in the basis
70  real3 basis[4] = { {0.25, 0.25, 0.25},
71  {0.25, 0.75, 0.75},
72  {0.75, 0.25, 0.75},
73  {0.75, 0.75, 0.25} };
74 
75  // create and place atoms
76  int begin[3];
77  int end[3];
78  for (int ii=0; ii<3; ++ii)
79  {
80  begin[ii] = floor(localMin[ii]/lat);
81  end[ii] = ceil (localMax[ii]/lat);
82  }
83 
84  real_t px,py,pz;
85  px=py=pz=0.0;
86  for (int ix=begin[0]; ix<end[0]; ++ix)
87  for (int iy=begin[1]; iy<end[1]; ++iy)
88  for (int iz=begin[2]; iz<end[2]; ++iz)
89  for (int ib=0; ib<nb; ++ib)
90  {
91  real_t rx = (ix+basis[ib][0]) * lat;
92  real_t ry = (iy+basis[ib][1]) * lat;
93  real_t rz = (iz+basis[ib][2]) * lat;
94  if (rx < localMin[0] || rx >= localMax[0]) continue;
95  if (ry < localMin[1] || ry >= localMax[1]) continue;
96  if (rz < localMin[2] || rz >= localMax[2]) continue;
97  int id = ib+nb*(iz+nz*(iy+ny*(ix)));
98  putAtomInBox(s->boxes, s->atoms, id, 0, rx, ry, rz, px, py, pz);
99  }
100 
101  // set total atoms in simulation
103  addIntParallel(&s->atoms->nLocal, &s->atoms->nGlobal, 1);
105 
106  assert(s->atoms->nGlobal == nb*nx*ny*nz);
107 }
108 
109 /// Sets the center of mass velocity of the system.
110 /// \param [in] newVcm The desired center of mass velocity.
111 void setVcm(SimFlat* s, real_t newVcm[3])
112 {
113  real_t oldVcm[3];
114  computeVcm(s, oldVcm);
115 
116  real_t vShift[3];
117  vShift[0] = (newVcm[0] - oldVcm[0]);
118  vShift[1] = (newVcm[1] - oldVcm[1]);
119  vShift[2] = (newVcm[2] - oldVcm[2]);
120 
121  for (int iBox=0; iBox<s->boxes->nLocalBoxes; ++iBox)
122  {
123  for (int iOff=MAXATOMS*iBox, ii=0; ii<s->boxes->nAtoms[iBox]; ++ii, ++iOff)
124  {
125  int iSpecies = s->atoms->iSpecies[iOff];
126  real_t mass = s->species[iSpecies].mass;
127 
128  s->atoms->p[iOff][0] += mass * vShift[0];
129  s->atoms->p[iOff][1] += mass * vShift[1];
130  s->atoms->p[iOff][2] += mass * vShift[2];
131  }
132  }
133 }
134 
135 /// Sets the temperature of system.
136 ///
137 /// Selects atom velocities randomly from a boltzmann (equilibrium)
138 /// distribution that corresponds to the specified temperature. This
139 /// random process will typically result in a small, but non zero center
140 /// of mass velocity and a small difference from the specified
141 /// temperature. For typical MD runs these small differences are
142 /// unimportant, However, to avoid possible confusion, we set the center
143 /// of mass velocity to zero and scale the velocities to exactly match
144 /// the input temperature.
145 void setTemperature(SimFlat* s, real_t temperature)
146 {
147  // set initial velocities for the distribution
148  for (int iBox=0; iBox<s->boxes->nLocalBoxes; ++iBox)
149  {
150  for (int iOff=MAXATOMS*iBox, ii=0; ii<s->boxes->nAtoms[iBox]; ++ii, ++iOff)
151  {
152  int iType = s->atoms->iSpecies[iOff];
153  real_t mass = s->species[iType].mass;
154  real_t sigma = sqrt(kB_eV * temperature/mass);
155  uint64_t seed = mkSeed(s->atoms->gid[iOff], 123);
156  s->atoms->p[iOff][0] = mass * sigma * gasdev(&seed);
157  s->atoms->p[iOff][1] = mass * sigma * gasdev(&seed);
158  s->atoms->p[iOff][2] = mass * sigma * gasdev(&seed);
159  }
160  }
161  // compute the resulting temperature
162  // kinetic energy = 3/2 kB * Temperature
163  if (temperature == 0.0) return;
164  real_t vZero[3] = {0., 0., 0.};
165  setVcm(s, vZero);
166  kineticEnergy(s);
167  real_t temp = (s->eKinetic/s->atoms->nGlobal)/kB_eV/1.5;
168  // scale the velocities to achieve the target temperature
169  real_t scaleFactor = sqrt(temperature/temp);
170  for (int iBox=0; iBox<s->boxes->nLocalBoxes; ++iBox)
171  {
172  for (int iOff=MAXATOMS*iBox, ii=0; ii<s->boxes->nAtoms[iBox]; ++ii, ++iOff)
173  {
174  s->atoms->p[iOff][0] *= scaleFactor;
175  s->atoms->p[iOff][1] *= scaleFactor;
176  s->atoms->p[iOff][2] *= scaleFactor;
177  }
178  }
179  kineticEnergy(s);
180  temp = s->eKinetic/s->atoms->nGlobal/kB_eV/1.5;
181 }
182 
183 /// Add a random displacement to the atom positions.
184 /// Atoms are displaced by a random distance in the range
185 /// [-delta, +delta] along each axis.
186 /// \param [in] delta The maximum displacement (along each axis).
188 {
189  for (int iBox=0; iBox<s->boxes->nLocalBoxes; ++iBox)
190  {
191  for (int iOff=MAXATOMS*iBox, ii=0; ii<s->boxes->nAtoms[iBox]; ++ii, ++iOff)
192  {
193  uint64_t seed = mkSeed(s->atoms->gid[iOff], 457);
194  s->atoms->r[iOff][0] += (2.0*lcg61(&seed)-1.0) * delta;
195  s->atoms->r[iOff][1] += (2.0*lcg61(&seed)-1.0) * delta;
196  s->atoms->r[iOff][2] += (2.0*lcg61(&seed)-1.0) * delta;
197  }
198  }
199 }
200 
201 /// Computes the center of mass velocity of the system.
202 void computeVcm(SimFlat* s, real_t vcm[3])
203 {
204  real_t vcmLocal[4] = {0., 0., 0., 0.};
205  real_t vcmSum[4] = {0., 0., 0., 0.};
206 
207  // sum the momenta and particle masses
208  for (int iBox=0; iBox<s->boxes->nLocalBoxes; ++iBox)
209  {
210  for (int iOff=MAXATOMS*iBox, ii=0; ii<s->boxes->nAtoms[iBox]; ++ii, ++iOff)
211  {
212  vcmLocal[0] += s->atoms->p[iOff][0];
213  vcmLocal[1] += s->atoms->p[iOff][1];
214  vcmLocal[2] += s->atoms->p[iOff][2];
215 
216  int iSpecies = s->atoms->iSpecies[iOff];
217  vcmLocal[3] += s->species[iSpecies].mass;
218  }
219  }
220 
222  addRealParallel(vcmLocal, vcmSum, 4);
224 
225  real_t totalMass = vcmSum[3];
226  vcm[0] = vcmSum[0]/totalMass;
227  vcm[1] = vcmSum[1]/totalMass;
228  vcm[2] = vcmSum[2]/totalMass;
229 }
230