336 lines
9.6 KiB
C
336 lines
9.6 KiB
C
/*
|
|
* This function opens the .car file and extracts coordinate information
|
|
* into the atoms Atom structure
|
|
*/
|
|
|
|
#include "msi2lmp.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
set global box params
|
|
assumes boxlo/hi and triclinic tilts are already set
|
|
------------------------------------------------------------------------- */
|
|
|
|
void set_box(double box[3][3], double *h, double *h_inv)
|
|
{
|
|
h[0] = box[1][0] - box[0][0];
|
|
h[1] = box[1][1] - box[0][1];
|
|
h[2] = box[1][2] - box[0][2];
|
|
|
|
h_inv[0] = 1.0/h[0];
|
|
h_inv[1] = 1.0/h[1];
|
|
h_inv[2] = 1.0/h[2];
|
|
|
|
h[3] = box[2][2];
|
|
h[4] = box[2][1];
|
|
h[5] = box[2][0];
|
|
h_inv[3] = -h[3] / (h[1]*h[2]);
|
|
h_inv[4] = (h[3]*h[5] - h[1]*h[4]) / (h[0]*h[1]*h[2]);
|
|
h_inv[5] = -h[5] / (h[0]*h[1]);
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
convert triclinic 0-1 lamda coords to box coords for one atom
|
|
x = H lamda + x0;
|
|
lamda and x can point to same 3-vector
|
|
------------------------------------------------------------------------- */
|
|
|
|
void lamda2x(double *lamda, double *x, double *h, double *boxlo)
|
|
{
|
|
x[0] = h[0]*lamda[0] + h[5]*lamda[1] + h[4]*lamda[2] + boxlo[0];
|
|
x[1] = h[1]*lamda[1] + h[3]*lamda[2] + boxlo[1];
|
|
x[2] = h[2]*lamda[2] + boxlo[2];
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
convert box coords to triclinic 0-1 lamda coords for one atom
|
|
lamda = H^-1 (x - x0)
|
|
x and lamda can point to same 3-vector
|
|
------------------------------------------------------------------------- */
|
|
|
|
void x2lamda(double *x, double *lamda, double *h_inv, double *boxlo)
|
|
{
|
|
double delta[3];
|
|
delta[0] = x[0] - boxlo[0];
|
|
delta[1] = x[1] - boxlo[1];
|
|
delta[2] = x[2] - boxlo[2];
|
|
|
|
lamda[0] = h_inv[0]*delta[0] + h_inv[5]*delta[1] + h_inv[4]*delta[2];
|
|
lamda[1] = h_inv[1]*delta[1] + h_inv[3]*delta[2];
|
|
lamda[2] = h_inv[2]*delta[2];
|
|
}
|
|
|
|
|
|
void ReadCarFile(void)
|
|
{
|
|
char line[MAX_LINE_LENGTH]; /* Stores lines as they are read in */
|
|
int k,m,n; /* counters */
|
|
int skip; /* lines to skip at beginning of file */
|
|
double lowest, highest; /* temp coordinate finding variables */
|
|
double total_q;
|
|
double cos_alpha; /* Added by SLTM Sept 13, 2010 */
|
|
double cos_gamma;
|
|
double sin_gamma;
|
|
double cos_beta;
|
|
double A, B, C;
|
|
double center[3];
|
|
double hmat[6];
|
|
double hinv[6];
|
|
double lamda[3];
|
|
|
|
/* Open .car file for reading */
|
|
|
|
sprintf(line,"%s.car",rootname);
|
|
if (pflag > 0) printf(" Reading car file: %s\n",line);
|
|
if( (CarF = fopen(line,"r")) == NULL ) {
|
|
printf("Cannot open %s\n",line);
|
|
exit(33);
|
|
}
|
|
|
|
/* Determine Number of molecules & atoms */
|
|
|
|
rewind(CarF);
|
|
no_molecules = -1; /* Set to -1 because counter will be incremented an
|
|
extra time at the end of the file */
|
|
|
|
fgets(line,MAX_LINE_LENGTH,CarF); /* Read header line */
|
|
|
|
/* Check for periodicity, if present, read cell constants */
|
|
|
|
if( strncmp(fgets(line,MAX_LINE_LENGTH,CarF),"PBC=ON",6) == 0) {
|
|
periodic = 1;
|
|
skip = 5; /* Data starts 5 lines from beginning of file */
|
|
fgets(line,MAX_LINE_LENGTH,CarF); /* Comment line */
|
|
fgets(line,MAX_LINE_LENGTH,CarF); /* Date stamp */
|
|
fscanf(CarF,"%*s %lf %lf %lf %lf %lf %lf %*s",
|
|
&pbc[0],&pbc[1],&pbc[2],&pbc[3],&pbc[4],&pbc[5]);
|
|
|
|
/* Added triclinic flag for non-orthogonal boxes Oct 5, 2010 SLTM */
|
|
if(pbc[3] != 90.0 || pbc[4] != 90.0 || pbc[5] != 90.0) {
|
|
TriclinicFlag = 1;
|
|
} else TriclinicFlag = 0;
|
|
} else {
|
|
periodic = 0;
|
|
skip = 4;
|
|
if (pflag > 1) {
|
|
printf(" %s is not a periodic system\n", rootname);
|
|
printf(" Assigning cell parameters based on coordinates\n");
|
|
}
|
|
fgets(line,MAX_LINE_LENGTH, CarF); /* Comment line */
|
|
fgets(line,MAX_LINE_LENGTH, CarF); /* Date Stamp */
|
|
}
|
|
|
|
/* First pass through file -- Count molecules */
|
|
|
|
while(fgets(line,MAX_LINE_LENGTH,CarF) != NULL )
|
|
if( strncmp(line,"end",3) == 0 )
|
|
no_molecules++;
|
|
|
|
/* Allocate space to keep track of the number of atoms within a molecule */
|
|
|
|
no_atoms = (int *) calloc(no_molecules,sizeof(int));
|
|
if ( no_atoms == NULL ) {
|
|
printf("Could not allocate memory for no_atoms\n");
|
|
exit(32);
|
|
}
|
|
|
|
/* Second pass through file -- Count atoms */
|
|
|
|
rewind(CarF);
|
|
for(n=0; n < skip; n++) /* Skip beginning lines */
|
|
fgets(line,MAX_LINE_LENGTH,CarF);
|
|
|
|
for(n=0; n < no_molecules; n++)
|
|
while( strncmp(fgets(line,MAX_LINE_LENGTH,CarF),"end",3) )
|
|
no_atoms[n]++;
|
|
|
|
for( total_no_atoms=0, n=0; n < no_molecules; n++ )
|
|
total_no_atoms += no_atoms[n];
|
|
|
|
molecule = (struct MoleculeList *) calloc(no_molecules,
|
|
sizeof(struct MoleculeList));
|
|
if (molecule == NULL) {
|
|
printf("Unable to allocate memory for molecule structure\n");
|
|
exit(32);
|
|
}
|
|
molecule[0].start = 0;
|
|
molecule[0].end = no_atoms[0];
|
|
for (n=1; n < no_molecules; n++) {
|
|
molecule[n].start = molecule[n-1].end;
|
|
molecule[n].end = molecule[n].start + no_atoms[n];
|
|
}
|
|
|
|
/* Allocate space for atoms Atom structures */
|
|
|
|
atoms = (struct Atom *) calloc(total_no_atoms,sizeof(struct Atom));
|
|
if( atoms == NULL ) {
|
|
printf("Could not allocate memory for AtomList\n");
|
|
exit(32);
|
|
}
|
|
|
|
/* Third pass through file -- Read+Parse Car File */
|
|
center[0] = center[1] = center[2] = 0.0;
|
|
rewind(CarF);
|
|
for(n=0; n < skip; n++)
|
|
fgets(line,MAX_LINE_LENGTH,CarF);
|
|
|
|
for(m=0; m < no_molecules; m++) {
|
|
for(k=molecule[m].start; k <
|
|
molecule[m].end; k++) {
|
|
|
|
atoms[k].molecule = m;
|
|
atoms[k].no = k;
|
|
|
|
fscanf(CarF,"%s %lf %lf %lf %*s %d %s %s %lf",
|
|
atoms[k].name,
|
|
&(atoms[k].x[0]),
|
|
&(atoms[k].x[1]),
|
|
&(atoms[k].x[2]),
|
|
&(atoms[k].molecule),
|
|
atoms[k].potential,
|
|
atoms[k].element,
|
|
&(atoms[k].q));
|
|
|
|
atoms[k].x[0] += shift[0];
|
|
atoms[k].x[1] += shift[1];
|
|
atoms[k].x[2] += shift[2];
|
|
|
|
if (centerflag) {
|
|
center[0] += atoms[k].x[0];
|
|
center[1] += atoms[k].x[1];
|
|
center[2] += atoms[k].x[2];
|
|
}
|
|
}
|
|
fgets(line,MAX_LINE_LENGTH,CarF);
|
|
fgets(line,MAX_LINE_LENGTH,CarF);
|
|
|
|
} /* End m (molecule) loop */
|
|
|
|
center[0] /= (double) total_no_atoms;
|
|
center[1] /= (double) total_no_atoms;
|
|
center[2] /= (double) total_no_atoms;
|
|
|
|
for (total_q=0.0,k=0; k < total_no_atoms; k++)
|
|
total_q += atoms[k].q;
|
|
|
|
if (pflag > 1) {
|
|
printf(" There are %d atoms in %d molecules in this file\n",
|
|
total_no_atoms,no_molecules);
|
|
printf(" The total charge in the system is %7.3f.\n",total_q);
|
|
}
|
|
|
|
/* Search coordinates to find lowest and highest for x, y, and z */
|
|
|
|
if (periodic == 0) {
|
|
/* Added if/else statement STLM Oct 5 2010 */
|
|
if (TriclinicFlag == 0) {
|
|
/* no need to re-center the box, if we use min/max values */
|
|
center[0] = center[1] = center[2] = 0.0;
|
|
for ( k = 0; k < 3; k++) {
|
|
lowest = atoms[0].x[k];
|
|
highest = atoms[0].x[k];
|
|
|
|
for ( m = 1; m < total_no_atoms; m++) {
|
|
if (atoms[m].x[k] < lowest) lowest = atoms[m].x[k];
|
|
if (atoms[m].x[k] > highest) highest = atoms[m].x[k];
|
|
}
|
|
box[0][k] = lowest - 0.5;
|
|
box[1][k] = highest + 0.5;
|
|
box[2][k] = 0.0;
|
|
}
|
|
} else {
|
|
printf("This tool only works for periodic systems with triclinic boxes");
|
|
exit(32);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (pflag > 2)
|
|
printf(" pbc[0] %f pbc[1] %f pbc[2] %f\n", pbc[0] ,pbc[1] ,pbc[2]);
|
|
if (TriclinicFlag == 0) {
|
|
for (k=0; k < 3; k++) {
|
|
box[0][k] = -0.5*pbc[k] + center[k] + shift[k];
|
|
box[1][k] = 0.5*pbc[k] + center[k] + shift[k];
|
|
box[2][k] = 0.0;
|
|
}
|
|
} else {
|
|
double ly,lz;
|
|
cos_alpha = cos(pbc[3]*PI_180);
|
|
cos_gamma = cos(pbc[5]*PI_180);
|
|
sin_gamma = sin(pbc[5]*PI_180);
|
|
cos_beta = cos(pbc[4]*PI_180);
|
|
if (pflag > 2) {
|
|
printf(" pbc[3] %f pbc[4] %f pbc[5] %f\n", pbc[3] ,pbc[4] ,pbc[5]);
|
|
printf(" cos_alpha %f cos_beta %f cos_gamma %f\n", cos_alpha ,cos_beta ,cos_gamma);
|
|
}
|
|
A = pbc[0];
|
|
B = pbc[1];
|
|
C = pbc[2];
|
|
|
|
/* compute xy, xz, and yz */
|
|
box[2][0] = B * cos_gamma;
|
|
box[2][1] = C * cos_beta;
|
|
if (fabs(sin_gamma) > 0.0001)
|
|
box[2][2] = C*(cos_alpha-cos_gamma*cos_beta)/sin_gamma;
|
|
else box[2][2] = 0.0;
|
|
|
|
box[0][0] = -0.5*A + center[0] + shift[0];
|
|
box[1][0] = 0.5*A + center[0] + shift[0];
|
|
|
|
/* compute adjusted box length for y and z and apply */
|
|
ly = sqrt(B*B - box[2][0]*box[2][0]);
|
|
lz = sqrt(C*C - box[2][1]*box[2][1] - box[2][2]*box[2][2]);
|
|
box[0][1] = -0.5*ly + center[1] + shift[1];
|
|
box[1][1] = 0.5*ly + center[1] + shift[1];
|
|
box[0][2] = -0.5*lz + center[2] + shift[2];
|
|
box[1][2] = 0.5*lz + center[2] + shift[2];
|
|
}
|
|
}
|
|
|
|
/* compute image flags */
|
|
|
|
set_box(box,hmat,hinv);
|
|
|
|
n = 0;
|
|
for (m = 0; m < total_no_atoms; m++) {
|
|
double tmp;
|
|
int w=0;
|
|
|
|
x2lamda(atoms[m].x,lamda,hinv,box[0]);
|
|
for (k = 0; k < 3; ++k) {
|
|
tmp = floor(lamda[k]);
|
|
atoms[m].image[k] = tmp;
|
|
lamda[k] -= tmp;
|
|
if (tmp != 0.0) ++w;
|
|
}
|
|
lamda2x(lamda, atoms[m].x,hmat,box[0]);
|
|
if (w > 0) ++n;
|
|
}
|
|
|
|
/* warn if atoms are outside the box */
|
|
if (n > 0) {
|
|
if (periodic) {
|
|
if (pflag > 1)
|
|
printf(" %d of %d atoms with nonzero image flags\n\n",n,total_no_atoms);
|
|
} else {
|
|
if (iflag == 0 || (pflag > 1))
|
|
printf(" %d of %d atoms outside the box\n\n",n,total_no_atoms);
|
|
|
|
condexit(32);
|
|
}
|
|
}
|
|
|
|
/* Close .car file */
|
|
|
|
if (fclose(CarF) !=0) {
|
|
printf("Error closing %s.car\n", rootname);
|
|
exit(31);
|
|
}
|
|
}
|
|
/* End ReadCarFile() */
|