1
/* ----------------------------------------------------------------------
2
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
3
http://lammps.sandia.gov, Sandia National Laboratories
4
Steve Plimpton, sjplimp@sandia.gov
6
Copyright (2003) Sandia Corporation. Under the terms of Contract
7
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
8
certain rights in this software. This software is distributed under
9
the GNU General Public License.
11
See the README file in the top-level LAMMPS directory.
12
------------------------------------------------------------------------- */
14
/* ----------------------------------------------------------------------
16
Purpose Quantum Path Integral Algorithm for Quantum Chemistry
17
Copyright Voth Group @ University of Chicago
18
Authors Chris Knight & Yuxing Peng (yuxing at uchicago.edu)
22
------------------------------------------------------------------------- */
37
using namespace LAMMPS_NS;
38
using namespace FixConst;
40
enum{PIMD,NMPIMD,CMD};
42
/* ---------------------------------------------------------------------- */
44
FixPIMD::FixPIMD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
52
for(int i=3; i<narg-1; i+=2)
54
if(strcmp(arg[i],"method")==0)
56
if(strcmp(arg[i+1],"pimd")==0) method=PIMD;
57
else if(strcmp(arg[i+1],"nmpimd")==0) method=NMPIMD;
58
else if(strcmp(arg[i+1],"cmd")==0) method=CMD;
59
else error->universe_all(FLERR,"Unkown method parameter for fix pimd");
61
else if(strcmp(arg[i],"fmass")==0)
63
fmass = atof(arg[i+1]);
64
if(fmass<0.0 || fmass>1.0) error->universe_all(FLERR,"Invalid fmass value for fix pimd");
66
else if(strcmp(arg[i],"sp")==0)
69
if(fmass<0.0) error->universe_all(FLERR,"Invalid sp value for fix pimd");
71
else if(strcmp(arg[i],"temp")==0)
73
nhc_temp = atof(arg[i+1]);
74
if(nhc_temp<0.0) error->universe_all(FLERR,"Invalid temp value for fix pimd");
76
else if(strcmp(arg[i],"nhc")==0)
78
nhc_nchain = atoi(arg[i+1]);
79
if(nhc_nchain<2) error->universe_all(FLERR,"Invalid nhc value for fix pimd");
81
else error->universe_all(arg[i],i+1,"Unkown keyword for fix pimd");
95
plan_send = plan_recv = NULL;
97
M_x2xp = M_xp2x = M_f2fp = M_fp2f = NULL;
106
nhc_eta_dotdot = NULL;
109
size_peratom_cols = 12 * nhc_nchain + 3;
111
nhc_offset_one_1 = 3 * nhc_nchain;
112
nhc_offset_one_2 = 3 * nhc_nchain +3;
113
nhc_size_one_1 = sizeof(double) * nhc_offset_one_1;
114
nhc_size_one_2 = sizeof(double) * nhc_offset_one_2;
127
atom->add_callback(0); // Call LAMMPS to allocate memory for per-atom array
128
atom->add_callback(1); // Call LAMMPS to re-assign restart-data for per-atom array
130
grow_arrays(atom->nmax);
132
// some initilizations
137
/* ---------------------------------------------------------------------- */
139
int FixPIMD::setmask()
143
mask |= INITIAL_INTEGRATE;
144
mask |= FINAL_INTEGRATE;
148
/* ---------------------------------------------------------------------- */
152
if(universe->me==0 && screen) fprintf(screen,"Fix pimd initializing Path-Integral ...\n");
154
// prepare the constants
156
np = universe->nworlds;
157
inverse_np = 1.0 / np;
159
/* The first solution for the force constant, using SI units
161
const double Boltzmann = 1.3806488E-23; // SI unit: J/K
162
const double Plank = 6.6260755E-34; // SI unit: m^2 kg / s
164
double hbar = Plank / ( 2.0 * M_PI ) * sp;
165
double beta = 1.0 / ( Boltzmann * input.nh_temp);
167
// - P / ( beta^2 * hbar^2) SI unit: s^-2
168
double _fbond = -1.0 / (beta*beta*hbar*hbar) * input.nbeads;
170
// convert the units: s^-2 -> (kcal/mol) / (g/mol) / (A^2)
171
fbond = _fbond * 4.184E+26;
175
/* The current solution, using LAMMPS internal real units */
177
const double Boltzmann = force->boltz;
178
const double Plank = force->hplanck;
180
double hbar = Plank / ( 2.0 * M_PI );
181
double beta = 1.0 / (Boltzmann * nhc_temp);
182
double _fbond = 1.0 * np / (beta*beta*hbar*hbar) ;
184
omega_np = sqrt(np) / (hbar * beta) * sqrt(force->mvv2e);
185
fbond = - _fbond * force->mvv2e;
188
printf("Fix pimd -P/(beta^2 * hbar^2) = %20.7lE (kcal/mol/A^2)\n\n", fbond);
191
dtf = 0.5 * update->dt * force->ftm2v;
195
mass = new double [atom->ntypes+1];
197
if(method==CMD || method==NMPIMD) nmpimd_init();
198
else for(int i=1; i<=atom->ntypes; i++) mass[i] = atom->mass[i] / np * fmass;
200
if(!nhc_ready) nhc_init();
203
/* ---------------------------------------------------------------------- */
205
void FixPIMD::setup(int vflag)
207
if(universe->me==0 && screen) fprintf(screen,"Setting up Path-Integral ...\n");
212
/* ---------------------------------------------------------------------- */
214
void FixPIMD::initial_integrate(int vflag)
220
/* ---------------------------------------------------------------------- */
222
void FixPIMD::final_integrate()
227
/* ---------------------------------------------------------------------- */
229
void FixPIMD::post_force(int flag)
231
for(int i=0; i<atom->nlocal; i++) for(int j=0; j<3; j++) atom->f[i][j] /= np;
236
if(method==CMD || method==NMPIMD)
238
/* forward comm for the force on ghost atoms */
240
nmpimd_fill(atom->f);
242
/* inter-partition comm */
246
/* normal-mode transform */
248
nmpimd_transform(buf_beads, atom->f, M_f2fp[universe->iworld]);
252
/* ----------------------------------------------------------------------
254
------------------------------------------------------------------------- */
256
void FixPIMD::nhc_init()
258
double tau = 1.0 / omega_np;
259
double KT = force->boltz * nhc_temp;
261
double mass0 = KT * tau * tau;
262
int max = 3 * atom->nlocal;
264
for(int i=0; i<max; i++)
266
for(int ichain=0; ichain<nhc_nchain; ichain++)
268
nhc_eta[i][ichain] = 0.0;
269
nhc_eta_dot[i][ichain] = 0.0;
270
nhc_eta_dot[i][ichain] = 0.0;
271
nhc_eta_dotdot[i][ichain] = 0.0;
272
nhc_eta_mass[i][ichain] = mass0;
273
nhc_eta_mass[i][ichain] *= fmass;
276
nhc_eta_dot[i][nhc_nchain] = 0.0;
278
for(int ichain=1; ichain<nhc_nchain; ichain++)
279
nhc_eta_dotdot[i][ichain] = (nhc_eta_mass[i][ichain-1] * nhc_eta_dot[i][ichain-1]
280
* nhc_eta_dot[i][ichain-1] * force->mvv2e - KT) / nhc_eta_mass[i][ichain];
283
// Zero NH acceleration for CMD
285
if(method==CMD && universe->iworld==0) for(int i=0; i<max; i++)
286
for(int ichain=0; ichain<nhc_nchain; ichain++) nhc_eta_dotdot[i][ichain] = 0.0;
291
/* ---------------------------------------------------------------------- */
293
void FixPIMD::nhc_update_x()
295
int n = atom->nlocal;
296
double **x = atom->x;
297
double **v = atom->v;
299
if(method==CMD || method==NMPIMD)
301
nmpimd_fill(atom->v);
304
/* borrow the space of atom->f to store v in cartisian */
307
nmpimd_transform(buf_beads, v, M_xp2x[universe->iworld]);
310
for(int i=0; i<n; i++)
312
x[i][0] += dtv * v[i][0];
313
x[i][1] += dtv * v[i][1];
314
x[i][2] += dtv * v[i][2];
318
/* ---------------------------------------------------------------------- */
320
void FixPIMD::nhc_update_v()
322
int n = atom->nlocal;
323
int *type = atom->type;
324
double **v = atom->v;
325
double **f = atom->f;
327
for(int i=0; i<n; i++)
329
double dtfm = dtf / mass[type[i]];
330
v[i][0] += dtfm * f[i][0];
331
v[i][1] += dtfm * f[i][1];
332
v[i][2] += dtfm * f[i][2];
336
if(method==CMD && universe->iworld==0) return;
339
int nmax = 3 * atom->nlocal;
340
double KT = force->boltz * nhc_temp;
341
double kecurrent, t_current;
343
double dthalf = 0.5 * update->dt;
344
double dt4 = 0.25 * update->dt;
345
double dt8 = 0.125 * update->dt;
347
for(int i=0; i<nmax; i++)
352
double *vv = v[iatm];
354
kecurrent = mass[type[iatm]] * vv[idim]* vv[idim] * force->mvv2e;
355
t_current = kecurrent / force->boltz;
357
double *eta = nhc_eta[i];
358
double *eta_dot = nhc_eta_dot[i];
359
double *eta_dotdot = nhc_eta_dotdot[i];
361
eta_dotdot[0] = (kecurrent - KT) / nhc_eta_mass[i][0];
363
for(int ichain=nhc_nchain-1; ichain>0; ichain--)
365
expfac = exp(-dt8 * eta_dot[ichain+1]);
366
eta_dot[ichain] *= expfac;
367
eta_dot[ichain] += eta_dotdot[ichain] * dt4;
368
eta_dot[ichain] *= expfac;
371
expfac = exp(-dt8 * eta_dot[1]);
372
eta_dot[0] *= expfac;
373
eta_dot[0] += eta_dotdot[0] * dt4;
374
eta_dot[0] *= expfac;
376
// Update particle velocities half-step
378
double factor_eta = exp(-dthalf * eta_dot[0]);
379
vv[idim] *= factor_eta;
381
t_current *= (factor_eta * factor_eta);
382
kecurrent = force->boltz * t_current;
383
eta_dotdot[0] = (kecurrent - KT) / nhc_eta_mass[i][0];
385
for(int ichain=0; ichain<nhc_nchain; ichain++)
386
eta[ichain] += dthalf * eta_dot[ichain];
388
eta_dot[0] *= expfac;
389
eta_dot[0] += eta_dotdot[0] * dt4;
390
eta_dot[0] *= expfac;
392
for(int ichain=1; ichain<nhc_nchain; ichain++)
394
expfac = exp(-dt8 * eta_dot[ichain+1]);
395
eta_dot[ichain] *= expfac;
396
eta_dotdot[ichain] = (nhc_eta_mass[i][ichain-1] * eta_dot[ichain-1] * eta_dot[ichain-1]
397
- KT) / nhc_eta_mass[i][ichain];
398
eta_dot[ichain] += eta_dotdot[ichain] * dt4;
399
eta_dot[ichain] *= expfac;
408
/* ----------------------------------------------------------------------
410
------------------------------------------------------------------------- */
412
void FixPIMD::nmpimd_init()
414
memory->create(M_x2xp, np, np, "fix_feynman:M_x2xp");
415
memory->create(M_xp2x, np, np, "fix_feynman:M_xp2x");
416
memory->create(M_f2fp, np, np, "fix_feynman:M_f2fp");
417
memory->create(M_fp2f, np, np, "fix_feynman:M_fp2f");
419
lam = (double*) memory->smalloc(sizeof(double)*np, "FixPIMD::lam");
421
// Set up eigenvalues
424
if(np%2==0) lam[np-1] = 4.0 * np;
426
for(int i=2; i<=np/2; i++)
428
lam[2*i-3] = lam[2*i-2] = 2.0 * np * (1.0 - 1.0 *cos(2.0*M_PI*(i-1)/np));
431
// Set up eigenvectors for non-degenerated modes
433
for(int i=0; i<np; i++)
435
M_x2xp[0][i] = 1.0 / np;
436
if(np%2==0) M_x2xp[np-1][i] = 1.0 / np * pow(-1.0, i);
439
// Set up eigenvectors for degenerated modes
441
for(int i=0; i<(np-1)/2; i++) for(int j=0; j<np; j++)
443
M_x2xp[2*i+1][j] = sqrt(2.0) * cos ( 2.0 * M_PI * (i+1) * j / np) / np;
444
M_x2xp[2*i+2][j] = - sqrt(2.0) * sin ( 2.0 * M_PI * (i+1) * j / np) / np;
449
for(int i=0; i<np; i++)
450
for(int j=0; j<np; j++)
452
M_xp2x[i][j] = M_x2xp[j][i] * np;
453
M_f2fp[i][j] = M_x2xp[i][j] * np;
454
M_fp2f[i][j] = M_xp2x[i][j];
459
int iworld = universe->iworld;
461
for(int i=1; i<=atom->ntypes; i++)
463
mass[i] = atom->mass[i];
467
mass[i] *= lam[iworld];
473
/* ---------------------------------------------------------------------- */
475
void FixPIMD::nmpimd_fill(double **ptr)
478
comm->forward_comm_fix(this);
481
/* ---------------------------------------------------------------------- */
483
void FixPIMD::nmpimd_transform(double** src, double** des, double *vector)
485
int n = atom->nlocal;
488
for(int i=0; i<n; i++) for(int d=0; d<3; d++)
491
for(int j=0; j<np; j++) { des[i][d] += (src[j][m] * vector[j]); }
496
/* ---------------------------------------------------------------------- */
498
void FixPIMD::spring_force()
502
double **x = atom->x;
503
double **f = atom->f;
504
double* _mass = atom->mass;
505
int* type = atom->type;
506
int nlocal = atom->nlocal;
508
double* xlast = buf_beads[x_last];
509
double* xnext = buf_beads[x_next];
511
for(int i=0; i<nlocal; i++)
513
double delx1 = xlast[0] - x[i][0];
514
double dely1 = xlast[1] - x[i][1];
515
double delz1 = xlast[2] - x[i][2];
517
domain->minimum_image(delx1, dely1, delz1);
519
double delx2 = xnext[0] - x[i][0];
520
double dely2 = xnext[1] - x[i][1];
521
double delz2 = xnext[2] - x[i][2];
523
domain->minimum_image(delx2, dely2, delz2);
525
double ff = fbond * _mass[type[i]];
527
double dx = delx1+delx2;
528
double dy = dely1+dely2;
529
double dz = delz1+delz2;
531
f[i][0] -= (dx) * ff;
532
f[i][1] -= (dy) * ff;
533
f[i][2] -= (dz) * ff;
535
spring_energy += (dx*dx+dy*dy+dz*dz);
539
/* ----------------------------------------------------------------------
541
------------------------------------------------------------------------- */
543
void FixPIMD::comm_init()
554
plan_send = new int [2];
555
plan_recv = new int [2];
556
mode_index = new int [2];
558
int rank_last = universe->me - comm->nprocs;
559
int rank_next = universe->me + comm->nprocs;
560
if(rank_last<0) rank_last += universe->nprocs;
561
if(rank_next>=universe->nprocs) rank_next -= universe->nprocs;
563
plan_send[0] = rank_next; plan_send[1] = rank_last;
564
plan_recv[0] = rank_last; plan_recv[1] = rank_next;
566
mode_index[0] = 0; mode_index[1] = 1;
567
x_last = 1; x_next = 0;
572
plan_send = new int [size_plan];
573
plan_recv = new int [size_plan];
574
mode_index = new int [size_plan];
576
for(int i=0; i<size_plan; i++)
578
plan_send[i] = universe->me + comm->nprocs * (i+1);
579
if(plan_send[i]>=universe->nprocs) plan_send[i] -= universe->nprocs;
581
plan_recv[i] = universe->me - comm->nprocs * (i+1);
582
if(plan_recv[i]<0) plan_recv[i] += universe->nprocs;
584
mode_index[i]=(universe->iworld+i+1)%(universe->nworlds);
587
x_next = (universe->iworld+1+universe->nworlds)%(universe->nworlds);
588
x_last = (universe->iworld-1+universe->nworlds)%(universe->nworlds);
593
for(int i=0; i<np; i++) if(buf_beads[i]) delete [] buf_beads[i];
597
buf_beads = new double* [np];
598
for(int i=0; i<np; i++) buf_beads[i] = NULL;
601
/* ---------------------------------------------------------------------- */
603
void FixPIMD::comm_exec(double **ptr)
605
int nlocal = atom->nlocal;
607
if(nlocal > max_nlocal)
609
max_nlocal = nlocal+200;
610
int size = sizeof(double) * max_nlocal * 3;
611
buf_recv = (double*) memory->srealloc(buf_recv, size, "FixPIMD:x_recv");
613
for(int i=0; i<np; i++)
614
buf_beads[i] = (double*) memory->srealloc(buf_beads[i], size, "FixPIMD:x_beads[i]");
617
// copy local positions
619
memcpy(buf_beads[universe->iworld], &(ptr[0][0]), sizeof(double)*nlocal*3);
621
// go over comm plans
623
for(int iplan = 0; iplan<size_plan; iplan++)
629
MPI_Sendrecv( &(nlocal), 1, MPI_INT, plan_send[iplan], 0,
630
&(nsend), 1, MPI_INT, plan_recv[iplan], 0, universe->uworld, MPI_STATUS_IGNORE);
634
if(nsend > max_nsend)
636
max_nsend = nsend+200;
637
tag_send = (int*) memory->srealloc(tag_send, sizeof(int)*max_nsend, "FixPIMD:tag_send");
638
buf_send = (double*) memory->srealloc(buf_send, sizeof(double)*max_nsend*3, "FixPIMD:x_send");
643
MPI_Sendrecv( atom->tag, nlocal, MPI_INT, plan_send[iplan], 0,
644
tag_send, nsend, MPI_INT, plan_recv[iplan], 0, universe->uworld, MPI_STATUS_IGNORE);
648
double *wrap_ptr = buf_send;
649
int ncpy = sizeof(double)*3;
651
for(int i=0; i<nsend; i++)
653
int index = atom->map(tag_send[i]);
657
char error_line[256];
659
sprintf(error_line, "Atom %d is missing at world [%d] rank [%d] required by rank [%d].\n",
660
tag_send[i], universe->iworld, comm->me, plan_recv[iplan]);
662
error->universe_one(FLERR,error_line);
665
memcpy(wrap_ptr, ptr[index], ncpy);
671
MPI_Sendrecv( buf_send, nsend*3, MPI_DOUBLE, plan_recv[iplan], 0,
672
buf_recv, nlocal*3, MPI_DOUBLE, plan_send[iplan], 0, universe->uworld, MPI_STATUS_IGNORE);
676
memcpy(buf_beads[mode_index[iplan]], buf_recv, sizeof(double)*nlocal*3);
680
/* ---------------------------------------------------------------------- */
682
int FixPIMD::pack_comm(int n, int *list, double *buf,
683
int pbc_flag, int *pbc)
689
for (i = 0; i < n; i++) {
691
buf[m++] = comm_ptr[j][0];
692
buf[m++] = comm_ptr[j][1];
693
buf[m++] = comm_ptr[j][2];
699
/* ---------------------------------------------------------------------- */
701
void FixPIMD::unpack_comm(int n, int first, double *buf)
707
for (i = first; i < last; i++) {
708
comm_ptr[i][0] = buf[m++];
709
comm_ptr[i][1] = buf[m++];
710
comm_ptr[i][2] = buf[m++];
714
/* ----------------------------------------------------------------------
716
------------------------------------------------------------------------- */
718
double FixPIMD::memory_usage()
721
bytes = atom->nmax * size_peratom_cols * sizeof(double);
725
/* ---------------------------------------------------------------------- */
727
void FixPIMD::grow_arrays(int nmax)
732
memory->grow(array_atom, nmax, size_peratom_cols, "FixPIMD::array_atom");
733
memory->grow(nhc_eta, count, nhc_nchain, "FixPIMD::nh_eta");
734
memory->grow(nhc_eta_dot, count, nhc_nchain+1, "FixPIMD::nh_eta_dot");
735
memory->grow(nhc_eta_dotdot, count, nhc_nchain, "FixPIMD::nh_eta_dotdot");
736
memory->grow(nhc_eta_mass, count, nhc_nchain, "FixPIMD::nh_eta_mass");
739
/* ---------------------------------------------------------------------- */
741
void FixPIMD::copy_arrays(int i, int j, int delflag)
746
memcpy(nhc_eta [j_pos], nhc_eta [i_pos], nhc_size_one_1);
747
memcpy(nhc_eta_dot [j_pos], nhc_eta_dot [i_pos], nhc_size_one_2);
748
memcpy(nhc_eta_dotdot[j_pos], nhc_eta_dotdot[i_pos], nhc_size_one_1);
749
memcpy(nhc_eta_mass [j_pos], nhc_eta_mass [i_pos], nhc_size_one_1);
752
/* ---------------------------------------------------------------------- */
754
int FixPIMD::pack_exchange(int i, double *buf)
759
memcpy(buf+offset, nhc_eta[pos], nhc_size_one_1); offset += nhc_offset_one_1;
760
memcpy(buf+offset, nhc_eta_dot[pos], nhc_size_one_2); offset += nhc_offset_one_2;
761
memcpy(buf+offset, nhc_eta_dotdot[pos], nhc_size_one_1); offset += nhc_offset_one_1;
762
memcpy(buf+offset, nhc_eta_mass[pos], nhc_size_one_1); offset += nhc_offset_one_1;
764
return size_peratom_cols;
767
/* ---------------------------------------------------------------------- */
769
int FixPIMD::unpack_exchange(int nlocal, double *buf)
774
memcpy(nhc_eta[pos], buf+offset, nhc_size_one_1); offset += nhc_offset_one_1;
775
memcpy(nhc_eta_dot[pos], buf+offset, nhc_size_one_2); offset += nhc_offset_one_2;
776
memcpy(nhc_eta_dotdot[pos], buf+offset, nhc_size_one_1); offset += nhc_offset_one_1;
777
memcpy(nhc_eta_mass[pos], buf+offset, nhc_size_one_1); offset += nhc_offset_one_1;
779
return size_peratom_cols;
782
/* ---------------------------------------------------------------------- */
784
int FixPIMD::pack_restart(int i, double *buf)
788
buf[offset++] = size_peratom_cols+1;
790
memcpy(buf+offset, nhc_eta[pos], nhc_size_one_1); offset += nhc_offset_one_1;
791
memcpy(buf+offset, nhc_eta_dot[pos], nhc_size_one_2); offset += nhc_offset_one_2;
792
memcpy(buf+offset, nhc_eta_dotdot[pos], nhc_size_one_1); offset += nhc_offset_one_1;
793
memcpy(buf+offset, nhc_eta_mass[pos], nhc_size_one_1); offset += nhc_offset_one_1;
795
return size_peratom_cols+1;
798
/* ---------------------------------------------------------------------- */
800
void FixPIMD::unpack_restart(int nlocal, int nth)
802
double **extra = atom->extra;
804
// skip to Nth set of extra values
807
for (int i=0; i<nth; i++) m += static_cast<int> (extra[nlocal][m]);
810
int pos = nlocal * 3;
812
memcpy(nhc_eta[pos], extra[nlocal]+m, nhc_size_one_1); m += nhc_offset_one_1;
813
memcpy(nhc_eta_dot[pos], extra[nlocal]+m, nhc_size_one_2); m += nhc_offset_one_2;
814
memcpy(nhc_eta_dotdot[pos], extra[nlocal]+m, nhc_size_one_1); m += nhc_offset_one_1;
815
memcpy(nhc_eta_mass[pos], extra[nlocal]+m, nhc_size_one_1); m += nhc_offset_one_1;
820
/* ---------------------------------------------------------------------- */
822
int FixPIMD::maxsize_restart()
824
return size_peratom_cols+1;
827
/* ---------------------------------------------------------------------- */
829
int FixPIMD::size_restart(int nlocal)
831
return size_peratom_cols+1;
834
/* ---------------------------------------------------------------------- */
836
double FixPIMD::compute_vector(int n)
838
if(n==0) { return spring_energy; }
839
if(n==1) { return t_sys; }