forked from lijiext/lammps
363 lines
12 KiB
C
363 lines
12 KiB
C
/* Copyright (C) 2013 Quantum ESPRESSO group
|
|
* This file is distributed under the terms of the
|
|
* GNU General Public License. See the file `License'
|
|
* in the root directory of the present distribution,
|
|
* or http://www.gnu.org/copyleft/gpl.txt . */
|
|
|
|
/* Toplevel wrapper code to launch QM/MM calculations via MPI */
|
|
|
|
#include <mpi.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#include "libqecouple.h"
|
|
#include "libqmmm.h"
|
|
|
|
#ifndef QE_LIBCOUPLE_API_VERSION
|
|
#define QE_LIBCOUPLE_API_VERSION 1
|
|
#endif
|
|
|
|
#if QE_LIBCOUPLE_API_VERSION != 1
|
|
#error "Unsupported QE coupling API. Want API version 1."
|
|
#endif
|
|
|
|
#include "library.h"
|
|
|
|
static const char delim[] = " \t\n\r";
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
MPI_Comm intra_comm, qm_comm, mm_comm;
|
|
int me, ncpu, nqm, key, retval;
|
|
|
|
MPI_Init(&argc, &argv);
|
|
MPI_Comm_size(MPI_COMM_WORLD,&ncpu);
|
|
MPI_Comm_rank(MPI_COMM_WORLD,&me);
|
|
|
|
/* we accept just the qm/mm file as the one argument */
|
|
if ((argc < 2) || (argc > 3)) {
|
|
if (me == 0) fprintf(stderr,"\n usage: %s <qmmm input file> "
|
|
"[<number of mm procs>]\n\n",argv[0]);
|
|
MPI_Finalize();
|
|
return -1;
|
|
}
|
|
|
|
/* parse the qm/mm file */
|
|
if (read_qmmm_config(argv[1],&qmmmcfg)) {
|
|
if (me == 0) fputs("\n Error parsing QM/MM config file\n\n",stderr);
|
|
MPI_Finalize();
|
|
return -2;
|
|
}
|
|
|
|
key = 2;
|
|
if (argc == 3) {
|
|
key = atoi(argv[2]);
|
|
}
|
|
qmmmcfg.nmm = key;
|
|
|
|
/* sanity checks */
|
|
qmmmcfg.comm_mode = QMMM_COMM_MPI;
|
|
nqm = ncpu - qmmmcfg.nmm;
|
|
retval = 0;
|
|
#if 1 // AK: temporary hack
|
|
if ( qmmmcfg.nmm != 2 ) {
|
|
if (me == 0) {
|
|
fprintf( stderr, "\n Error in the number of processors for MM code"
|
|
"\n for the time being only two processor are allowed\n");
|
|
}
|
|
MPI_Finalize();
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if (me == 0) {
|
|
const char *msg;
|
|
|
|
msg = check_qmmm_config(&qmmmcfg);
|
|
|
|
if ((nqm < 1) || (qmmmcfg.nmm < 2)) {
|
|
msg = "Need at least 2 MM and 1 QM processes";
|
|
}
|
|
if (msg != NULL) {
|
|
retval = 1;
|
|
fprintf(stderr,"\n%s\n\n",msg);
|
|
}
|
|
}
|
|
MPI_Bcast(&retval,1,MPI_INT,0,MPI_COMM_WORLD);
|
|
if (retval != 0) {
|
|
MPI_Finalize();
|
|
return -3;
|
|
}
|
|
|
|
if (me == 0) {
|
|
write_qmmm_config(NULL,&qmmmcfg);
|
|
|
|
printf("\nRunning QM/MM calculation for %d steps on %d procs\n\n",
|
|
qmmmcfg.steps, ncpu);
|
|
printf("QM system: procs: % 4d | directory: %-16s | input: %-16s|\n",
|
|
nqm,qmmmcfg.qmdir,qmmmcfg.qminp);
|
|
printf("MM master: procs: % 4d | directory: %-16s | input: %-16s|\n",
|
|
qmmmcfg.nmm-1,qmmmcfg.madir,qmmmcfg.mainp);
|
|
printf("MM slave: procs: % 4d | directory: %-16s | input: %-16s|\n\n",
|
|
1,qmmmcfg.sldir,qmmmcfg.slinp);
|
|
}
|
|
|
|
/* set up MPI communication */
|
|
|
|
/* process partitioning: QM | MM master | MM slave */
|
|
qmmmcfg.role = QMMM_ROLE_QM;
|
|
if (me >= nqm) qmmmcfg.role = QMMM_ROLE_MASTER;
|
|
if (me == (ncpu-1)) qmmmcfg.role = QMMM_ROLE_SLAVE;
|
|
|
|
MPI_Comm_split(MPI_COMM_WORLD, qmmmcfg.role, me, &intra_comm);
|
|
qmmmcfg.my_comm = MPI_Comm_c2f(intra_comm);
|
|
|
|
/* qm to mm-master inter communicator */
|
|
key = MPI_UNDEFINED;
|
|
if ((me == 0) || (me == nqm)) key = 1;
|
|
|
|
MPI_Comm_split(MPI_COMM_WORLD, key, ncpu-me, &qm_comm);
|
|
qmmmcfg.qm_comm = MPI_Comm_c2f(qm_comm);
|
|
|
|
/* mm-slave to mm-master inter communicator */
|
|
key = MPI_UNDEFINED;
|
|
if ((me == (ncpu-1)) || (me == nqm)) key = 1;
|
|
|
|
MPI_Comm_split(MPI_COMM_WORLD, key, me, &mm_comm);
|
|
qmmmcfg.mm_comm = MPI_Comm_c2f(mm_comm);
|
|
|
|
if (qmmmcfg.role == QMMM_ROLE_QM) {
|
|
FILE *fp;
|
|
int nimage,npots,npool,ntg,nband,ndiag;
|
|
|
|
MPI_Comm_rank(intra_comm,&me);
|
|
|
|
if (chdir(qmmmcfg.qmdir)) {
|
|
if (me == 0) fputs("failure to change into QM directory\n",stderr);
|
|
MPI_Abort(MPI_COMM_WORLD, 10);
|
|
}
|
|
|
|
/* check if input file is available and readable */
|
|
fp = fopen(qmmmcfg.qminp,"r");
|
|
if (fp == NULL) {
|
|
if (me == 0) fprintf(stderr,"failure to open QM input for "
|
|
"reading: %s\n", strerror(errno));
|
|
MPI_Abort(MPI_COMM_WORLD, 20);
|
|
} else fclose(fp);
|
|
|
|
/* redirect output to file, if requested */
|
|
if (strcmp(qmmmcfg.qmout,"NULL") != 0) {
|
|
fp = freopen(qmmmcfg.qmout,"w",stdout);
|
|
if (fp == NULL) {
|
|
if (me == 0) fprintf(stderr,"failure to open QM output for "
|
|
"writing: %s\n", strerror(errno));
|
|
MPI_Abort(MPI_COMM_WORLD, 30);
|
|
}
|
|
}
|
|
|
|
/* parse additional command line flags for pw.x */
|
|
nimage=npots=npool=ntg=nband=ndiag=1;
|
|
|
|
if (qmmmcfg.qmarg != NULL) {
|
|
char *ptr = strtok(qmmmcfg.qmarg,delim);
|
|
do {
|
|
/* -nimage parallelization is not supported with QM/MM
|
|
* -npot parallelization has been removed from QE */
|
|
if ((strncmp("-nk",ptr,3) == 0)
|
|
|| (strncmp("-npoo",ptr,5) == 0)) {
|
|
ptr=strtok(NULL,delim);
|
|
npool=atoi(ptr);
|
|
} else if (strncmp("-nt",ptr,3) == 0) {
|
|
ptr=strtok(NULL,delim);
|
|
ntg=atoi(ptr);
|
|
} else if (strncmp("-nb",ptr,3) == 0) {
|
|
ptr=strtok(NULL,delim);
|
|
nband=atoi(ptr);
|
|
} else if ((strncmp("-nd",ptr,3) == 0)
|
|
|| (strncmp("-no",ptr,3) == 0)
|
|
|| (strcmp("-nproc_diag",ptr) == 0)
|
|
|| (strcmp("-nproc_ortho",ptr) == 0)) {
|
|
ptr=strtok(NULL,delim);
|
|
ndiag=atoi(ptr);
|
|
} else {
|
|
if (me == 0) {
|
|
fprintf(stderr,"QM: ignoring flag '%s", ptr);
|
|
ptr=strtok(NULL,delim);
|
|
fprintf(stderr," %s'\n",ptr);
|
|
} else strtok(NULL,delim);
|
|
}
|
|
} while ((ptr=strtok(NULL,delim)));
|
|
}
|
|
|
|
retval = 0;
|
|
|
|
/* setup and call Q-E. */
|
|
c2qmmm_mpi_config(qmmmcfg.qmmm_mode, qmmmcfg.qm_comm,
|
|
qmmmcfg.verbose, qmmmcfg.steps);
|
|
c2libpwscf(qmmmcfg.my_comm, nimage, npots, npool, ntg, nband, ndiag,
|
|
&retval, qmmmcfg.qminp);
|
|
|
|
if (strcmp(qmmmcfg.qmout,"NULL") != 0)
|
|
fclose(fp);
|
|
|
|
} else if (qmmmcfg.role == QMMM_ROLE_MASTER) {
|
|
FILE *fp;
|
|
char *suffix;
|
|
void *lmp;
|
|
|
|
MPI_Comm_rank(intra_comm,&me);
|
|
|
|
if (chdir(qmmmcfg.madir)) {
|
|
if (me == 0)
|
|
fputs("failure to change into MM master directory\n",stderr);
|
|
MPI_Abort(MPI_COMM_WORLD, 10);
|
|
}
|
|
|
|
/* check if input file is available and readable */
|
|
fp = fopen(qmmmcfg.mainp,"r");
|
|
if (fp == NULL) {
|
|
if (me == 0) fprintf(stderr,"failure to open MM master input "
|
|
"for reading: %s\n", strerror(errno));
|
|
MPI_Abort(MPI_COMM_WORLD, 20);
|
|
} else fclose(fp);
|
|
|
|
/* redirect output to file, if requested */
|
|
if (strcmp(qmmmcfg.maout,"NULL") != 0) {
|
|
fp = freopen(qmmmcfg.maout,"w",stdout);
|
|
if (fp == NULL) {
|
|
if (me == 0) fprintf(stderr,"failure to open MM master output "
|
|
"for writing: %s\n", strerror(errno));
|
|
MPI_Abort(MPI_COMM_WORLD, 30);
|
|
}
|
|
}
|
|
|
|
/* parse additional support command line flags for LAMMPS */
|
|
|
|
if (qmmmcfg.maarg != NULL) {
|
|
char *ptr = strtok(qmmmcfg.maarg,delim);
|
|
do {
|
|
if ((strncmp("-sf",ptr,3) == 0)
|
|
|| (strncmp("-suffix",ptr,7) == 0)) {
|
|
ptr=strtok(NULL,delim);
|
|
suffix=strdup(ptr);
|
|
} else {
|
|
if (me == 0)
|
|
fprintf(stderr,"unsupported LAMMPS flag: %s\n",ptr);
|
|
MPI_Abort(MPI_COMM_WORLD, 40);
|
|
}
|
|
} while ((ptr=strtok(NULL,delim)));
|
|
}
|
|
char *lmpargs[5];
|
|
lmpargs[0] = strdup("MM Master");
|
|
lmpargs[1] = strdup("-log");
|
|
lmpargs[2] = strdup("none");
|
|
lmpargs[3] = strdup("-echo");
|
|
lmpargs[4] = strdup("screen");
|
|
|
|
lammps_open(5, lmpargs, intra_comm, &lmp);
|
|
lammps_file(lmp,qmmmcfg.mainp);
|
|
|
|
char runcmd[1024];
|
|
sprintf(runcmd,"run %d\n",qmmmcfg.steps);
|
|
lammps_command(lmp,runcmd);
|
|
if (qmmmcfg.restart != NULL) {
|
|
sprintf(runcmd,"write_restart %s\n",qmmmcfg.restart);
|
|
lammps_command(lmp,runcmd);
|
|
}
|
|
lammps_close(lmp);
|
|
|
|
fputs("MM: master done\n",stderr);
|
|
if (strcmp(qmmmcfg.maout,"NULL") != 0)
|
|
fclose(fp);
|
|
|
|
retval = 0;
|
|
|
|
} else if (qmmmcfg.role == QMMM_ROLE_SLAVE) {
|
|
FILE *fp;
|
|
char *suffix;
|
|
void *lmp;
|
|
|
|
MPI_Comm_rank(intra_comm,&me);
|
|
|
|
if (chdir(qmmmcfg.sldir)) {
|
|
if (me == 0)
|
|
fputs("failure to change into MM slave directory\n",stderr);
|
|
MPI_Abort(MPI_COMM_WORLD, 10);
|
|
}
|
|
|
|
/* check if input file is available and readable */
|
|
fp = fopen(qmmmcfg.slinp,"r");
|
|
if (fp == NULL) {
|
|
if (me == 0) fprintf(stderr,"failure to open MM slave input "
|
|
"for reading: %s\n", strerror(errno));
|
|
MPI_Abort(MPI_COMM_WORLD, 20);
|
|
} else fclose(fp);
|
|
|
|
/* redirect output to file, if requested */
|
|
if (strcmp(qmmmcfg.slout,"NULL") != 0) {
|
|
fp = freopen(qmmmcfg.slout,"w",stdout);
|
|
if (fp == NULL) {
|
|
if (me == 0) fprintf(stderr,"failure to open MM slave output "
|
|
"for writing: %s\n", strerror(errno));
|
|
MPI_Abort(MPI_COMM_WORLD, 30);
|
|
}
|
|
}
|
|
|
|
/* parse additional support command line flags for LAMMPS */
|
|
|
|
if (qmmmcfg.slarg != NULL) {
|
|
char *ptr = strtok(qmmmcfg.maarg,delim);
|
|
do {
|
|
if ((strncmp("-sf",ptr,3) == 0)
|
|
|| (strncmp("-suffix",ptr,7) == 0)) {
|
|
ptr=strtok(NULL,delim);
|
|
suffix=strdup(ptr);
|
|
} else {
|
|
if (me == 0)
|
|
fprintf(stderr,"unsupported LAMMPS flag: %s\n",ptr);
|
|
MPI_Abort(MPI_COMM_WORLD, 40);
|
|
}
|
|
} while ((ptr=strtok(NULL,delim)));
|
|
}
|
|
|
|
char *lmpargs[5];
|
|
lmpargs[0] = strdup("MM slave");
|
|
lmpargs[1] = strdup("-log");
|
|
lmpargs[2] = strdup("none");
|
|
lmpargs[3] = strdup("-echo");
|
|
lmpargs[4] = strdup("screen");
|
|
|
|
lammps_open(5, lmpargs, intra_comm, &lmp);
|
|
lammps_file(lmp,qmmmcfg.slinp);
|
|
|
|
char runcmd[64];
|
|
sprintf(runcmd,"run %d\n",qmmmcfg.steps);
|
|
lammps_command(lmp,runcmd);
|
|
lammps_close(lmp);
|
|
|
|
fputs("MM: slave done\n",stderr);
|
|
if (strcmp(qmmmcfg.slout,"NULL") != 0)
|
|
fclose(fp);
|
|
retval = 0;
|
|
|
|
} else {
|
|
fputs("\n how on earth did you end up here?\n\n",stderr);
|
|
retval = 0;
|
|
}
|
|
|
|
MPI_Barrier(MPI_COMM_WORLD);
|
|
MPI_Comm_rank(MPI_COMM_WORLD,&me);
|
|
|
|
if (me == 0) fputs("\nQM/MM run complete.\n",stderr);
|
|
MPI_Finalize();
|
|
free_qmmm_config(&qmmmcfg);
|
|
|
|
return retval;
|
|
}
|
|
|