blob: d7ca06764f09575204ce121261b74d785d0239a9 [file] [log] [blame]
/*************************************************************************/
/* */
/* Copyright (c) 1994 Stanford University */
/* */
/* All rights reserved. */
/* */
/* Permission is given to use, copy, and modify this software for any */
/* non-commercial purpose as long as this copyright notice is not */
/* removed. All other uses, including redistribution in whole or in */
/* part, are forbidden without prior written permission. */
/* */
/* This software is provided with absolutely no warranty and no */
/* support. */
/* */
/*************************************************************************/
EXTERN_ENV
#include <math.h>
#include <stdio.h>
#include "mdvar.h"
#include "water.h"
#include "cnst.h"
#include "fileio.h"
#include "parameters.h"
#include "mddata.h"
#include "split.h"
INITIA()
{
/* this routine initializes the positions of the molecules along
a regular cubical lattice, and randomizes the initial velocities of
the atoms. The random numbers used in the initialization of velocities
are read from the file random.in, which must be in the current working
directory in which the program is run */
static double XMIN = 0;
static double YMIN = 0;
static double ZMIN = 0;
FILE *random_numbers; /* points to input file containing
pseudo-random numbers for initializing
velocities */
double XMAS[4], XS, ZERO, WCOS, WSIN, XT[4], YT[4], Z;
double SUX, SUY, SUZ, SUMX, SUMY, SUMZ, FAC;
int X_INDEX, Y_INDEX, Z_INDEX;
int mol=0;
int atom=0;
int i, j, k, ii, kk;
struct link *link_ptr, *curr_ptr, *last_ptr;
double xrand();
//int srandom();
int Part_per_box, Unassigned, m, pid;
random_numbers = fopen("random.in","r");
if (random_numbers == NULL) {
fprintf(stderr,"Error in opening file random.in\n");
fflush(stderr);
exit(-1);
}
XMAS[1]=sqrt(OMAS*HMAS);
XMAS[0]=HMAS;
XMAS[2]=HMAS;
/* .....assign positions */
{
int deriv;
double NS = pow((double) NMOL, 1.0/3.0) - 0.00000000000001;
double XS = BOXL/NS;
double ZERO = XS * 0.50;
double WCOS = ROH * cos(ANGLE * 0.5);
double WSIN = ROH * sin(ANGLE * 0.5);
printf("\nNS = %.16f\n",NS);
printf("BOXL = %10f\n",BOXL);
printf("CUTOFF = %10f\n",CUTOFF);
printf("BOX_LENGTH = %10f\n",BOX_LENGTH);
printf("BOX_PER_SIDE = %d\n",BOX_PER_SIDE);
printf("XS = %10f\n",XS);
printf("ZERO = %g\n",ZERO);
printf("WCOS = %f\n",WCOS);
printf("WSIN = %f\n",WSIN);
fflush(stdout);
#ifdef RANDOM
/* if we want to initialize to a random distribution of displacements
for the molecules, rather than a distribution along a regular lattice
spaced according to intermolecular distances in water */
srandom(1023);
fscanf(random_numbers,"%lf",&SUX);
SUMX=0.0;
SUMY=0.0;
SUMZ=0.0;
Part_per_box = NMOL / (BOX_PER_SIDE * BOX_PER_SIDE * BOX_PER_SIDE);
Unassigned = NMOL - (Part_per_box * BOX_PER_SIDE * BOX_PER_SIDE * BOX_PER_SIDE);
printf("Part_per_box = %d, BOX_PER_SIDE = %d, Unassigned = %d\n",Part_per_box, BOX_PER_SIDE, Unassigned);
for (i = 0; i < BOX_PER_SIDE; i++)
for (j = 0; j < BOX_PER_SIDE; j++)
for (k = 0; k < BOX_PER_SIDE; k++)
for (m = 0; m < Part_per_box; m++) {
link_ptr = (struct link *) G_MALLOC(sizeof(link_type));
link_ptr->mol.F[DISP][XDIR][O] = xrand(BOX_LENGTH * i, BOX_LENGTH * (i+1));
link_ptr->mol.F[DISP][XDIR][H1] = link_ptr->mol.F[DISP][XDIR][O] + WCOS;
link_ptr->mol.F[DISP][XDIR][H2] = link_ptr->mol.F[DISP][XDIR][H1];
link_ptr->mol.F[DISP][YDIR][O] = xrand(BOX_LENGTH * j, BOX_LENGTH * (j+1));
link_ptr->mol.F[DISP][YDIR][H1] = link_ptr->mol.F[DISP][YDIR][O] + WSIN;
link_ptr->mol.F[DISP][YDIR][H2] = link_ptr->mol.F[DISP][YDIR][O] - WSIN;
link_ptr->mol.F[DISP][ZDIR][O] = xrand(BOX_LENGTH * k, BOX_LENGTH * (k+1));
link_ptr->mol.F[DISP][ZDIR][H1] = link_ptr->mol.F[DISP][ZDIR][O];
link_ptr->mol.F[DISP][ZDIR][H2] = link_ptr->mol.F[DISP][ZDIR][O];
for (atom = 0; atom < NATOMS; atom++) {
/* read random velocities from file random.in */
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][XDIR][atom]);
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][YDIR][atom]);
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][ZDIR][atom]);
SUMX = SUMX + link_ptr->mol.F[VEL][XDIR][atom];
SUMY = SUMY + link_ptr->mol.F[VEL][YDIR][atom];
SUMZ = SUMZ + link_ptr->mol.F[VEL][ZDIR][atom];
/* set acceleration and all higher-order derivatives to zero */
for (deriv = ACC; deriv < MAXODR; deriv++) {
link_ptr->mol.F[deriv][XDIR][atom] = 0.0;
link_ptr->mol.F[deriv][YDIR][atom] = 0.0;
link_ptr->mol.F[deriv][ZDIR][atom] = 0.0;
}
}
link_ptr->next_mol = NULL; /* Terminating link */
/* update box indices in all three dimensions */
X_INDEX = (int) (link_ptr->mol.F[DISP][XDIR][O]/BOX_LENGTH);
Y_INDEX = (int) (link_ptr->mol.F[DISP][YDIR][O]/BOX_LENGTH);
Z_INDEX = (int) (link_ptr->mol.F[DISP][ZDIR][O]/BOX_LENGTH);
/* Put X_, Y_, and Z_INDEX back in box */
if (X_INDEX >=BOX_PER_SIDE) X_INDEX -= 1;
if (Y_INDEX >=BOX_PER_SIDE) Y_INDEX -= 1;
if (Z_INDEX >=BOX_PER_SIDE) Z_INDEX -= 1;
/* get list ptr */
curr_ptr = BOX[X_INDEX][Y_INDEX][Z_INDEX].list;
if (curr_ptr == NULL) { /* No links in box yet */
BOX[X_INDEX][Y_INDEX][Z_INDEX].list = link_ptr;
} else {
while (curr_ptr) { /* Scan to end of list */
last_ptr = curr_ptr;
curr_ptr = curr_ptr->next_mol;
} /* while curr_ptr */
last_ptr->next_mol = link_ptr; /* Add to end of list */
} /* if curr_ptr */
}
/* distribute the unassigned molecules evenly among processors */
pid = 0;
for (i = 0; i < Unassigned; i++) {
link_ptr = (struct link *) G_MALLOC(sizeof(link_type));
link_ptr->mol.F[DISP][XDIR][O] = xrand(BOX_LENGTH * start_end[pid]->box[XDIR][FIRST], BOX_LENGTH * (start_end[pid]->box[XDIR][LAST] + 1));
link_ptr->mol.F[DISP][XDIR][H1] = link_ptr->mol.F[DISP][XDIR][O] + WCOS;
link_ptr->mol.F[DISP][XDIR][H2] = link_ptr->mol.F[DISP][XDIR][H1];
link_ptr->mol.F[DISP][YDIR][O] = xrand(BOX_LENGTH * start_end[pid]->box[YDIR][FIRST], BOX_LENGTH * (start_end[pid]->box[YDIR][LAST] + 1));
link_ptr->mol.F[DISP][YDIR][H1] = link_ptr->mol.F[DISP][YDIR][O] + WSIN;
link_ptr->mol.F[DISP][YDIR][H2] = link_ptr->mol.F[DISP][YDIR][O] - WSIN;
link_ptr->mol.F[DISP][ZDIR][O] = xrand(BOX_LENGTH * start_end[pid]->box[ZDIR][FIRST], BOX_LENGTH * (start_end[pid]->box[ZDIR][LAST] + 1));
link_ptr->mol.F[DISP][ZDIR][H1] = link_ptr->mol.F[DISP][ZDIR][O];
link_ptr->mol.F[DISP][ZDIR][H2] = link_ptr->mol.F[DISP][ZDIR][O];
pid = (pid + 1) % NumProcs;
/* read random velocities from file random.in */
for (atom = 0; atom < NATOMS; atom++) {
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][XDIR][atom]);
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][YDIR][atom]);
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][ZDIR][atom]);
SUMX = SUMX + link_ptr->mol.F[VEL][XDIR][atom];
SUMY = SUMY + link_ptr->mol.F[VEL][YDIR][atom];
SUMZ = SUMZ + link_ptr->mol.F[VEL][ZDIR][atom];
/* set acceleration and all higher derivatives to zero */
for (deriv = ACC; deriv < MAXODR; deriv++) {
link_ptr->mol.F[deriv][XDIR][atom] = 0.0;
link_ptr->mol.F[deriv][YDIR][atom] = 0.0;
link_ptr->mol.F[deriv][ZDIR][atom] = 0.0;
}
}
link_ptr->next_mol = NULL; /* Terminating link */
/* updated box indices in all dimensions */
X_INDEX = (int) (link_ptr->mol.F[DISP][XDIR][O]/BOX_LENGTH);
Y_INDEX = (int) (link_ptr->mol.F[DISP][YDIR][O]/BOX_LENGTH);
Z_INDEX = (int) (link_ptr->mol.F[DISP][ZDIR][O]/BOX_LENGTH);
/* Put X_, Y_, and Z_INDEX back in box */
if (X_INDEX >=BOX_PER_SIDE) X_INDEX -= 1;
if (Y_INDEX >=BOX_PER_SIDE) Y_INDEX -= 1;
if (Z_INDEX >=BOX_PER_SIDE) Z_INDEX -= 1;
/* get list ptr */
curr_ptr = BOX[X_INDEX][Y_INDEX][Z_INDEX].list;
if (curr_ptr == NULL) { /* No links in box yet */
BOX[X_INDEX][Y_INDEX][Z_INDEX].list = link_ptr;
} else {
while (curr_ptr) { /* Scan to end of list */
last_ptr = curr_ptr;
curr_ptr = curr_ptr->next_mol;
} /* while curr_ptr */
last_ptr->next_mol = link_ptr; /* Add to end of list */
} /* if curr_ptr */
}
#else
/* not random initial placement, but rather along a regular
lattice. This is the default and the prefered initialization
since random does not necessarily make sense from the viewpoint
of preserving bond distances */
fprintf(six, "***** NEW RUN STARTING FROM REGULAR LATTICE *****\n");
fflush(six);
XT[2] = ZERO;
mol = 0;
fscanf(random_numbers,"%lf",&SUX);
SUMX=0.0;
SUMY=0.0;
SUMZ=0.0;
/* Generate displacements along a regular lattice */
for (i=0; i < NS; i++) {
XT[1]=XT[2]+WCOS;
XT[3]=XT[1];
YT[2]=ZERO;
for (j=0; j < NS; j+=1) {
YT[1]=YT[2]+WSIN;
YT[3]=YT[2]-WSIN;
Z=ZERO;
for (k = 0; k < NS; k++) {
link_ptr = (struct link *) G_MALLOC(sizeof(link_type));
for (atom = 0; atom < NATOMS; atom++) {
/* displacements for atom */
link_ptr->mol.F[DISP][XDIR][atom] = XT[atom+1];
link_ptr->mol.F[DISP][YDIR][atom] = YT[atom+1];
link_ptr->mol.F[DISP][ZDIR][atom] = Z;
/* read random velocities from file random.in */
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][XDIR][atom]);
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][YDIR][atom]);
fscanf(random_numbers,"%lf",&link_ptr->mol.F[VEL][ZDIR][atom]);
SUMX = SUMX + link_ptr->mol.F[VEL][XDIR][atom];
SUMY = SUMY + link_ptr->mol.F[VEL][YDIR][atom];
SUMZ = SUMZ + link_ptr->mol.F[VEL][ZDIR][atom];
for (deriv = ACC; deriv < MAXODR; deriv++) {
link_ptr->mol.F[deriv][XDIR][atom] = 0.0;
link_ptr->mol.F[deriv][YDIR][atom] = 0.0;
link_ptr->mol.F[deriv][ZDIR][atom] = 0.0;
}
}
link_ptr->next_mol = NULL; /* Terminating link */
mol++;
Z += XS;
/* update box numbers in all dimensions */
X_INDEX = (int) (link_ptr->mol.F[DISP][XDIR][O]/BOX_LENGTH);
Y_INDEX = (int) (link_ptr->mol.F[DISP][YDIR][O]/BOX_LENGTH);
Z_INDEX = (int) (link_ptr->mol.F[DISP][ZDIR][O]/BOX_LENGTH);
/* Put X_, Y_, and Z_INDEX back in box */
if (X_INDEX >=BOX_PER_SIDE) X_INDEX -= 1;
if (Y_INDEX >=BOX_PER_SIDE) Y_INDEX -= 1;
if (Z_INDEX >=BOX_PER_SIDE) Z_INDEX -= 1;
/* get list ptr */
curr_ptr = BOX[X_INDEX][Y_INDEX][Z_INDEX].list;
if (curr_ptr == NULL) { /* No links in box yet */
BOX[X_INDEX][Y_INDEX][Z_INDEX].list = link_ptr;
} else {
while (curr_ptr) { /* Scan to end of list */
last_ptr = curr_ptr;
curr_ptr = curr_ptr->next_mol;
} /* while curr_ptr */
last_ptr->next_mol = link_ptr; /* Add to end of list */
} /* if curr_ptr */
} /* for k */
YT[2] += XS;
} /* for j */
XT[2] += XS;
} /* for i */
if (NMOL != mol) {
printf("Lattice init error: total mol %d != NMOL %d\n", mol, NMOL);
exit(-1);
}
#endif
}
/* assign random momenta */
/* find average momenta per atom */
SUMX=SUMX/(NATOMS*NMOL);
SUMY=SUMY/(NATOMS*NMOL);
SUMZ=SUMZ/(NATOMS*NMOL);
/* find normalization factor so that <k.e.>=KT/2 */
SUX=0.0;
SUY=0.0;
SUZ=0.0;
for (i=0; i<BOX_PER_SIDE; i++) {
for (j=0; j<BOX_PER_SIDE; j++) {
for (k=0; k<BOX_PER_SIDE; k++) {
curr_ptr = BOX[i][j][k].list;
while (curr_ptr) {
SUX = SUX +
(pow( (curr_ptr->mol.F[VEL][XDIR][H1] - SUMX),2.0)
+pow( (curr_ptr->mol.F[VEL][XDIR][H2] - SUMX),2.0))/HMAS
+pow( (curr_ptr->mol.F[VEL][XDIR][O] - SUMX),2.0)/OMAS;
SUY = SUY +
(pow( (curr_ptr->mol.F[VEL][YDIR][H1] - SUMY),2.0)
+pow( (curr_ptr->mol.F[VEL][YDIR][H2] - SUMY),2.0))/HMAS
+pow( (curr_ptr->mol.F[VEL][YDIR][O] - SUMY),2.0)/OMAS;
SUZ = SUZ +
(pow( (curr_ptr->mol.F[VEL][ZDIR][H1] - SUMZ),2.0)
+ pow( (curr_ptr->mol.F[VEL][ZDIR][H2] - SUMZ),2.0))/HMAS
+pow( (curr_ptr->mol.F[VEL][ZDIR][O] - SUMZ),2.0)/OMAS;
curr_ptr = curr_ptr->next_mol;
} /* while curr_ptr */
}
}
} /* for boxes */
FAC=BOLTZ*TEMP*NATMO/UNITM * pow((UNITT*TSTEP/UNITL),2.0);
SUX=sqrt(FAC/SUX);
SUY=sqrt(FAC/SUY);
SUZ=sqrt(FAC/SUZ);
/* normalize individual velocities so that there are no bulk momenta */
XMAS[1]=OMAS;
for (i=0; i<BOX_PER_SIDE; i++) {
for (j=0; j<BOX_PER_SIDE; j++) {
for (k=0; k<BOX_PER_SIDE; k++) {
curr_ptr = BOX[i][j][k].list;
while (curr_ptr) {
for (atom = 0; atom < NATOMS; atom++) {
curr_ptr->mol.F[VEL][XDIR][atom] =
( curr_ptr->mol.F[VEL][XDIR][atom] -
SUMX) * SUX/XMAS[atom];
curr_ptr->mol.F[VEL][YDIR][atom] =
( curr_ptr->mol.F[VEL][YDIR][atom] -
SUMY) * SUY/XMAS[atom];
curr_ptr->mol.F[VEL][ZDIR][atom] =
( curr_ptr->mol.F[VEL][ZDIR][atom] -
SUMZ) * SUZ/XMAS[atom];
} /* for atom */
curr_ptr = curr_ptr->next_mol;
} /* while curr_ptr */
}
}
} /* for box */
fclose(random_numbers);
} /* end of subroutine INITIA */
/*
* XRAND: generate floating-point random number.
*/
double xrand(xl, xh)
double xl, xh; /* lower, upper bounds on number */
{
long random ();
double x;
x=(xl + (xh - xl) * ((double) random()) / 2147483647.0);
return (x);
}