git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@11711 f3b2605a-c512-4ea7-a41b-209d697bcdaa

This commit is contained in:
sjplimp 2014-04-04 20:08:01 +00:00
parent 3eac8574a6
commit d94e1e1ac5
15 changed files with 6103 additions and 0 deletions

View File

@ -25,5 +25,7 @@ poems POEMS rigid-body integration package, POEMS package
from Rudranarayan Mukherjee (RPI)
meam modified embedded atom method (MEAM) potential, MEAM package
from Greg Wagner (Sandia)
qmmm quantum mechanics/molecular mechanics coupling interface
from Axel Kohlmeyer (Temple U)
reax ReaxFF potential, REAX package
from Adri van Duin (Penn State) and Aidan Thompson (Sandia)

View File

@ -0,0 +1,67 @@
# -*- Makefile -*- for coupling LAMMPS to PWscf for QM/MM molecular dynamics
# this file will be copied to Makefile.lammps
EXTRAMAKE = Makefile.lammps.empty
# top level directory of Quantum ESPRESSO 5.1 or later
QETOPDIR=$(HOME)/compile/espresso
# import compiler settings from Quantum ESPRESSO
sinclude $(QETOPDIR)/make.sys
# FLAGS for c++ OpenMPI when QE was compiled with GNU Fortran 4.x
MPICXX=mpicxx
MPICXXFLAGS=-DOMPI_SKIP_MPICXX=1 -O2 -Wall -g \
-I../../src -I$(QETOPDIR)/COUPLE/include
MPILIBS=-fopenmp -lgfortran -ldl -ljpeg -lmpi_f77 -lmpi
# location of required libraries
# part 1: hi-level libraries for building pw.x
PWOBJS = \
$(QETOPDIR)/COUPLE/src/libqecouple.a \
$(QETOPDIR)/PW/src/libpw.a \
$(QETOPDIR)/Modules/libqemod.a
# part 2: lo-level libraries for all of Q-E
LIBOBJS = \
$(QETOPDIR)/flib/ptools.a \
$(QETOPDIR)/flib/flib.a \
$(QETOPDIR)/clib/clib.a \
$(QETOPDIR)/iotk/src/libiotk.a
# part 3: add-on libraries and main library for LAMMPS
sinclude ../../src/Makefile.package
LAMMPSCFG = openmpi-omp
LAMMPSLIB = ../../src/liblammps_$(LAMMPSCFG).a
# part 4: local QM/MM library and progams
SRC=pwqmmm.c libqmmm.c
OBJ=$(SRC:%.c=%.o)
default: libqmmm.a
all : tldeps libqmmm.a pwqmmm.x
pwqmmm.x : pwqmmm.o $(OBJ) $(PWOBJS) $(LIBOBJS) $(LAMMPSLIB)
$(MPICXX) $(LDFLAGS) -o $@ $^ $(PKG_PATH) $(PKG_LIB) $(MPILIBS) $(LIBS)
libqmmm.a: libqmmm.o
$(AR) $(ARFLAGS) $@ $^
@cp $(EXTRAMAKE) Makefile.lammps
%.o: %.c
$(MPICXX) -c $(LAMMPSFLAGS) $(MPICXXFLAGS) $< -o $@
tldeps:
( cd $(QETOPDIR) ; $(MAKE) $(MFLAGS) couple || exit 1)
$(MAKE) -C ../../src $(MFLAGS) makelib
$(MAKE) -C ../../src $(MFLAGS) $(LAMMPSCFG)
$(MAKE) -C ../../src $(MFLAGS) -f Makefile.lib $(LAMMPSCFG)
clean :
- /bin/rm -f *.x *.o *.a *~ *.F90 *.d *.mod *.i *.L
# explicit dependencies
pwqmmm.o: pwqmmm.c libqmmm.h
libqmmm.o: libqmmm.c libqmmm.h

View File

@ -0,0 +1,5 @@
# Settings that the LAMMPS build will import when this package library is used
qmmm_SYSINC =
qmmm_SYSLIB =
qmmm_SYSPATH =

108
lib/qmmm/README Normal file
View File

@ -0,0 +1,108 @@
QM/MM support toplevel library
Axel Kohlmeyer, akohlmey@gmail.com
Temple University, Philadelphia and ICTP, Trieste
This library provides the basic glue code to combine LAMMPS with the
Quantum ESPRESSO package plane wave density functional theory code for
performing QM/MM molecular dynamics simulations. More information on
Quantum ESPRESSO can be found at: http://www.quantum-espresso.org
The interface code itself is designed so it can also be combined with
other QM codes, however only support for Quantum ESPRESSO is currently
the only option. Adding support for a different QM code will require
to write a new version of the top-level wrapper code, pwqmmm.c, and
also an interface layer into the QM code similar to the one in QE.
-------------------------------------------------
This directory has the source files to build a library and an
executable for combining the pw.x program from Quantum ESPRESSO and
LAMMPS into a single executable that can be used for QM/MM molecular
dynamics simulations. LAMMPS will act as the MD "driver" and will
delegate computation of forces for the QM subset of the system to
Quantum ESPRESSO.
The toplevel code provided here will split the total number of cpus
into three partitions: the first for running a DFT calculation, the
second for running the "master" classical MD calculation, and the
third for a "slave" classical MD calculation. Each calculation will
have to be run in its own subdirectory with its own specific input
data and will write its output there as well. This and other settings
are provided in the QM/MM input file that is mandatory argument to the
QM/MM executable. The number of MM cpus is provided as the optional
second argument. The MM "slave" partition is always run with only 1
cpu thus the minimum number is 2, which is also the default. Therefore
a QM/MM calculation with this code requires at least 3 processes.
Thus the overall calling sequence is like this:
mpirun -np <total #cpus> ./pwqmmm.x <QM/MM input> [<#cpus for MM>]
A commented example is given below.
-------------------------------------------------
Build the library using one of the provided Makefile.* files or create
your own, specific to your compiler and system. For example:
make -f Makefile.gfortran
When you are done building this library, two new files should
exist in this directory:
libqmmm.a the library LAMMPS will link against
Makefile.lammps settings the LAMMPS Makefile will import
Makefile.lammps is created by the make command by simply copying the
Makefile.lammps.empty file. Currently no additional dependencies for
this library exist.
-------------------------------------------------
To compile and link the final QM/MM executable, you have to build
quantum espresso with the "pw" and "couple" targets. You also have
to to install the USER-QMMM package for LAMMPS. You have to specify
the path to the toplevel Quantum ESPRESSO directory, so that the
compiler and linker settings can be imported.
The makefile variable MPILIBS needs to be set to include all linker
flags that will need to be used in addition to the various libraries
from the two packages. Please see the provided example(s).
"make -f Makefile.gfortran" all by itself will only compile the
library (so that LAMMPS can be compiled into a standalone executable
as well, when the USER-QMMM package is installed).
"make -f Makefile.gfortran pwqmmm.x" will compile and link the QM/MM
executable; "make -f Makefile.gfortran all" will recurse through the
Quantum ESPRESSO and LAMMPS directories to compile all files that
require recompilation and then link the executable.
Please refer to the specific LAMMPS and Quantum ESPRESSO documentation
for details on how to set up compilation for each package and make
sure you have a set of settings and flags that allow you to build
each package successfully, so that it can run on its own.
-------------------------------------------------
# configuration file for QMMM wrapper
mode mech # coupling choices: o(ff), m(echanical), e(lectrostatic)
steps 20 # number of QM/MM (MD) steps
verbose 1 # verbosity level (0=no QM/MM output during run)
restart water.restart # checkpoint/restart file to write out at end
# QM system config
qmdir qm-pw # directory to run QM system in
qminp water.in # input file for QM code
qmout NULL # output file for QM code (or NULL to print to screen)
# MM master config
madir mm-master # directory to run MM master in
mainp water.in # input file for MM master
maout water.out # output file for MM master (or NULL to print to screen)
# MM slave config
sldir mm-slave # directory to run MM slave in
slinp water_single.in # input file for MM slave
slout water_single.out # output file for MM slave (or NULL to print to screen)

View File

@ -0,0 +1,236 @@
LAMMPS data file for water
96 atoms
64 bonds
32 angles
0 dihedrals
0 impropers
2 atom types
1 bond types
1 angle types
0 dihedral types
0 improper types
0.0 9.865 xlo xhi
0.0 9.865 ylo yhi
0.0 9.865 zlo zhi
Masses
1 15.9994
2 1.008
Pair Coeffs
1 0.102 3.188
2 0.000 0.000
Bond Coeffs
1 450 0.9572
Angle Coeffs
1 55.0 104.52
Atoms
1 0 1 -0.83400 -4.943157 4.999555 1.106073
2 0 2 0.41700 -3.989383 5.319684 0.882671
3 0 2 0.41700 -4.970859 4.118886 0.645414
4 0 1 -0.83400 0.087651 3.997966 0.245184
5 0 2 0.41700 -0.189448 3.238564 0.737637
6 0 2 0.41700 0.340165 3.716546 -0.646859
7 0 1 -0.83400 -1.476825 2.573003 3.969964
8 0 2 0.41700 -2.476262 2.342909 3.971242
9 0 2 0.41700 -1.177059 2.137822 4.797386
10 0 1 -0.83400 -2.866718 -2.698567 -5.842805
11 0 2 0.41700 -2.116039 -2.563955 -6.460863
12 0 2 0.41700 -2.633035 -3.566300 -5.365619
13 0 1 -0.83400 4.305354 0.916065 2.310797
14 0 2 0.41700 4.681590 1.456886 1.564890
15 0 2 0.41700 4.477897 -0.001266 2.162118
16 0 1 -0.83400 3.140624 -2.958877 0.699556
17 0 2 0.41700 2.416048 -3.267548 1.282072
18 0 2 0.41700 3.733007 -3.780312 0.657627
19 0 1 -0.83400 -2.702605 -5.503344 -2.185117
20 0 2 0.41700 -2.503651 -6.454759 -1.864686
21 0 2 0.41700 -2.445484 -4.875090 -1.412444
22 0 1 -0.83400 -0.499359 1.396504 -3.109410
23 0 2 0.41700 -0.051681 2.161550 -2.706675
24 0 2 0.41700 -1.148357 1.125379 -2.447316
25 0 1 -0.83400 4.890520 4.325756 3.842052
26 0 2 0.41700 3.893761 4.308535 3.950637
27 0 2 0.41700 4.946166 4.514250 2.851741
28 0 1 -0.83400 5.691644 1.713787 4.310484
29 0 2 0.41700 5.228679 2.581555 4.361998
30 0 2 0.41700 5.119255 1.176301 3.635805
31 0 1 -0.83400 0.560959 0.041910 -5.382932
32 0 2 0.41700 1.221529 -0.722558 -5.312134
33 0 2 0.41700 -0.033504 0.016189 -4.590395
34 0 1 -0.83400 -0.740775 1.579130 1.430754
35 0 2 0.41700 0.200064 1.382700 1.565649
36 0 2 0.41700 -0.918129 1.879209 2.375874
37 0 1 -0.83400 3.602330 -0.138439 -3.581327
38 0 2 0.41700 4.487536 -0.216376 -4.000513
39 0 2 0.41700 3.049262 -0.796203 -4.061640
40 0 1 -0.83400 -2.574131 1.816065 -0.773020
41 0 2 0.41700 -1.984990 1.759512 0.021520
42 0 2 0.41700 -2.623056 0.813950 -0.951715
43 0 1 -0.83400 -0.681860 -2.105217 2.617966
44 0 2 0.41700 0.075591 -2.677482 2.470155
45 0 2 0.41700 -0.381447 -1.260528 3.119035
46 0 1 -0.83400 0.877670 3.520059 -2.346170
47 0 2 0.41700 0.962603 4.130609 -3.093700
48 0 2 0.41700 1.694708 2.956694 -2.260009
49 0 1 -0.83400 4.626681 -5.379887 -3.195904
50 0 2 0.41700 5.384273 -5.281869 -2.664131
51 0 2 0.41700 4.959718 -5.195755 -4.090586
52 0 1 -0.83400 -2.975363 -0.549128 -4.157351
53 0 2 0.41700 -3.005586 -1.347160 -4.749504
54 0 2 0.41700 -3.484397 0.188753 -4.601707
55 0 1 -0.83400 -1.784475 4.961314 -4.576682
56 0 2 0.41700 -1.799259 4.090209 -5.083548
57 0 2 0.41700 -2.115771 4.808141 -3.667451
58 0 1 -0.83400 3.259544 2.452140 -2.230180
59 0 2 0.41700 3.323170 1.530411 -2.542184
60 0 2 0.41700 3.802574 3.049282 -2.844435
61 0 1 -0.83400 1.201227 -3.873074 1.979232
62 0 2 0.41700 0.666072 -4.403011 1.263244
63 0 2 0.41700 1.518668 -4.606497 2.643697
64 0 1 -0.83400 1.656255 1.671444 2.585800
65 0 2 0.41700 2.558345 1.396868 2.334225
66 0 2 0.41700 1.332188 1.089240 3.372965
67 0 1 -0.83400 2.403906 -1.938370 -5.265845
68 0 2 0.41700 2.088628 -2.761173 -4.852894
69 0 2 0.41700 3.112550 -2.143084 -5.990367
70 0 1 -0.83400 6.671015 -0.695457 -1.582148
71 0 2 0.41700 5.710948 -0.796794 -1.184378
72 0 2 0.41700 6.545527 -0.771012 -2.574381
73 0 1 -0.83400 -5.424609 -1.825624 2.814190
74 0 2 0.41700 -4.617447 -2.210882 3.171264
75 0 2 0.41700 -5.776719 -2.412234 2.075929
76 0 1 -0.83400 1.150487 -4.096740 5.844391
77 0 2 0.41700 1.076286 -3.915393 6.837958
78 0 2 0.41700 0.183470 -4.044319 5.594055
79 0 1 -0.83400 2.061664 4.194185 3.777119
80 0 2 0.41700 1.882571 3.326557 3.243961
81 0 2 0.41700 1.683407 4.114458 4.646069
82 0 1 -0.83400 -2.311755 -4.122312 0.194948
83 0 2 0.41700 -1.444386 -4.631613 0.333538
84 0 2 0.41700 -2.118545 -3.162947 0.233986
85 0 1 -0.83400 1.118351 -3.252459 -1.395623
86 0 2 0.41700 0.435993 -2.622296 -1.064746
87 0 2 0.41700 1.972678 -3.141898 -0.956755
88 0 1 -0.83400 4.038733 -0.963636 -0.898121
89 0 2 0.41700 3.616635 -1.752805 -0.471089
90 0 2 0.41700 3.665491 -0.726014 -1.803310
91 0 1 -0.83400 -0.910973 -1.540333 -0.388194
92 0 2 0.41700 -1.741083 -1.200928 -0.798897
93 0 2 0.41700 -0.901836 -1.451834 0.541945
94 0 1 -0.83400 4.850315 2.494782 0.151704
95 0 2 0.41700 4.126910 2.456315 -0.566034
96 0 2 0.41700 5.642328 2.128654 -0.307363
Bonds
1 1 1 2
2 1 1 3
3 1 4 5
4 1 4 6
5 1 7 8
6 1 7 9
7 1 10 11
8 1 10 12
9 1 13 14
10 1 13 15
11 1 16 17
12 1 16 18
13 1 19 20
14 1 19 21
15 1 22 23
16 1 22 24
17 1 25 26
18 1 25 27
19 1 28 29
20 1 28 30
21 1 31 32
22 1 31 33
23 1 34 35
24 1 34 36
25 1 37 38
26 1 37 39
27 1 40 41
28 1 40 42
29 1 43 44
30 1 43 45
31 1 46 47
32 1 46 48
33 1 49 50
34 1 49 51
35 1 52 53
36 1 52 54
37 1 55 56
38 1 55 57
39 1 58 59
40 1 58 60
41 1 61 62
42 1 61 63
43 1 64 65
44 1 64 66
45 1 67 68
46 1 67 69
47 1 70 71
48 1 70 72
49 1 73 74
50 1 73 75
51 1 76 77
52 1 76 78
53 1 79 80
54 1 79 81
55 1 82 83
56 1 82 84
57 1 85 86
58 1 85 87
59 1 88 89
60 1 88 90
61 1 91 92
62 1 91 93
63 1 94 95
64 1 94 96
Angles
1 1 2 1 3
2 1 5 4 6
3 1 8 7 9
4 1 11 10 12
5 1 14 13 15
6 1 17 16 18
7 1 20 19 21
8 1 23 22 24
9 1 26 25 27
10 1 29 28 30
11 1 32 31 33
12 1 35 34 36
13 1 38 37 39
14 1 41 40 42
15 1 44 43 45
16 1 47 46 48
17 1 50 49 51
18 1 53 52 54
19 1 56 55 57
20 1 59 58 60
21 1 62 61 63
22 1 65 64 66
23 1 68 67 69
24 1 71 70 72
25 1 74 73 75
26 1 77 76 78
27 1 80 79 81
28 1 83 82 84
29 1 86 85 87
30 1 89 88 90
31 1 92 91 93
32 1 95 94 96

View File

@ -0,0 +1,28 @@
units real
neigh_modify delay 0 every 1 check yes
atom_style full
bond_style harmonic
angle_style harmonic
pair_style lj/cut/coul/long 10.0
pair_modify mix arithmetic
kspace_style pppm 1e-4
special_bonds amber
#atom_modify sort 0.0 0
read_data data.water
timestep 1.0
dump 1 all custom 1 dump.lammpstrj id element xu yu zu
dump_modify 1 element O H
thermo_style multi
thermo 1
group wat id 25:27
fix 1 wat qmmm
fix 2 all nvt temp 300.0 300.0 70.0

View File

@ -0,0 +1,46 @@
LAMMPS data file for water
3 atoms
2 bonds
1 angles
2 atom types
1 bond types
1 angle types
0.0 9.865 xlo xhi
0.0 9.865 ylo yhi
0.0 9.865 zlo zhi
Masses
1 15.9994
2 1.008
Pair Coeffs
1 0.102 3.188
2 0.000 0.000
Bond Coeffs
1 450 0.9572
Angle Coeffs
1 55.0 104.52
Atoms
1 0 1 -0.8340 4.890520 4.325756 3.842052
2 0 2 0.41700 3.893761 4.308535 3.950637
3 0 2 0.41700 4.946166 4.514250 2.851741
Bonds
1 1 1 2
2 1 1 3
Angles
1 1 2 1 3

View File

@ -0,0 +1,20 @@
units real
neigh_modify delay 0 every 1 check yes
atom_style full
bond_style harmonic
angle_style harmonic
pair_style lj/cut/coul/long 10.0
pair_modify mix arithmetic
kspace_style pppm 1e-4
special_bonds amber
#atom_modify sort 0.0 0
read_data data.single_water
timestep 1.0
thermo_style multi
thermo 1
fix 1 all qmmm

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
&CONTROL
title="QMMM"
calculation='md',
restart_mode = 'from_scratch',
tprnfor=.t.,
prefix='ms2',
pseudo_dir='pseudo'
nstep = 2000,
tqmmm = .true.
/
&SYSTEM
ibrav = 1,
celldm(1) = 18.642155649244,
nat = 3,
ntyp = 2,
ecutwfc = 25.0 ,
ecutrho = 250.0 ,
/
&ELECTRONS
conv_thr = 1.D-8,
/
&IONS
ion_positions = 'default'
/
ATOMIC_SPECIES
O 16.0000 O.pbe-van_bm.UPF
H 1.0000 H.pbe-van_ak.UPF
ATOMIC_POSITIONS angstrom
O 4.890520 4.325756 3.842052
H 3.893761 4.308535 3.950637
H 4.946166 4.514250 2.851741
K_POINTS gamma

View File

@ -0,0 +1,24 @@
# configuration file for QMMM wrapper
mode mech # coupling choices: o(ff), m(echanical), e(lectrostatic)
#mode elec # coupling choices: o(ff), m(echanical), e(lectrostatic)
handle qmmm # name of sysv shmem handle
steps 20 # number of QM/MM (MD) steps
verbose 1
restart water.restart # checkpoint/restart file to write out at end
# QM system config
qmdir qm-pw # directory to run QM system in
qminp water.in # input file for QM code
qmout NULL # output file for QM code (or NULL to print to screen)
# MM master config
madir mm-master # directory to run MM master in
mainp water.in # input file for MM master
maout water.out # output file for MM master (or NULL to print to screen)
# MM slave config
sldir mm-slave # directory to run MM slave in
slinp water_single.in # input file for MM slave
slout water_single.out # output file for MM slave (or NULL to print to screen)

346
lib/qmmm/libqmmm.c Normal file
View File

@ -0,0 +1,346 @@
/*
* 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 .
*
* generic QM/MM support library
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "libqmmm.h"
#define BUF_SIZE 1024
/* global variable for global QM/MM configuration */
qmmm_config_t qmmmcfg;
/* local helper function: advance char pointer beyond leading whitespace */
static char *skip_whitespace(char *ptr)
{
while ((*ptr == ' ') || (*ptr == '\t')
|| (*ptr == '\r') || (*ptr == '\n')) ++ptr;
return ptr;
}
/* local helper function: trim string to remove trailing whitespace */
static void trim_whitespace(char *ptr)
{
while ((*ptr != ' ') && (*ptr != '\t')
&& (*ptr != '\r') && (*ptr != '\n')) ++ptr;
*ptr = '\0';
}
/* read and parse global QM/MM configuration file and
store the result in a qmmm_config_t struct */
int read_qmmm_config(const char *file, qmmm_config_t *cfg)
{
FILE *fp;
char *ptr;
int i, lineno, len;
char buf[BUF_SIZE];
/* need to have config file and storage for config provided */
if ((file == NULL) || (cfg == NULL))
return QMMM_ERROR;
/* clear config */
memset(cfg, 0, sizeof(qmmm_config_t));
fp = fopen(file,"r");
if (fp == NULL) return QMMM_ERROR;
lineno = 0;
while (fgets(buf,BUF_SIZE,fp)) {
++lineno;
/* remove comments */
ptr = strchr(buf,'#');
if (ptr != NULL) *ptr = '\0';
/* skip over leading whitespace */
ptr = skip_whitespace(buf);
len = strlen(ptr);
if (len == 0) continue;
/* convert keyword to lower case */
for (i=0; i < len; ++i) {
if ((ptr[i]=='\0') || (ptr[i]==' ') || (ptr[i]=='\t'))
break;
ptr[i] = tolower(ptr[i]);
}
/* handle keywords */
if (strncmp(ptr,"mode",4) == 0) {
ptr = skip_whitespace(ptr+4);
if ((*ptr=='m') || (*ptr=='M'))
cfg->qmmm_mode = QMMM_MODE_MECH;
else if ((*ptr=='e') || (*ptr=='E'))
cfg->qmmm_mode = QMMM_MODE_ELEC;
else if ((*ptr=='o') || (*ptr=='O'))
cfg->qmmm_mode = QMMM_MODE_OFF;
else cfg->qmmm_mode = QMMM_ERROR;
} else if (strncmp(ptr,"comm",4) == 0) {
ptr = skip_whitespace(ptr+4);
if ((*ptr=='m') || (*ptr=='M'))
cfg->comm_mode = QMMM_COMM_MPI;
else if ((*ptr=='s') || (*ptr=='S'))
cfg->comm_mode = QMMM_COMM_SHM;
else cfg->comm_mode = QMMM_ERROR;
} else if (strncmp(ptr,"steps",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
cfg->steps = atoi(ptr);
} else if (strncmp(ptr,"verbose",7) == 0) {
ptr = skip_whitespace(ptr+7);
trim_whitespace(ptr);
cfg->verbose = atoi(ptr);
} else if (strncmp(ptr,"handle",6) == 0) {
ptr = skip_whitespace(ptr+6);
trim_whitespace(ptr);
if (cfg->handle) free(cfg->handle);
cfg->handle = strdup(ptr);
} else if (strncmp(ptr,"restart",7) == 0) {
ptr = skip_whitespace(ptr+7);
trim_whitespace(ptr);
if (cfg->restart) free(cfg->restart);
cfg->restart = strdup(ptr);
} else if (strncmp(ptr,"qmdir",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->qmdir) free(cfg->qmdir);
cfg->qmdir = strdup(ptr);
} else if (strncmp(ptr,"madir",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->madir) free(cfg->madir);
cfg->madir = strdup(ptr);
} else if (strncmp(ptr,"sldir",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->sldir) free(cfg->sldir);
cfg->sldir = strdup(ptr);
} else if (strncmp(ptr,"qminp",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->qminp) free(cfg->qminp);
cfg->qminp = strdup(ptr);
} else if (strncmp(ptr,"mainp",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->mainp) free(cfg->mainp);
cfg->mainp = strdup(ptr);
} else if (strncmp(ptr,"slinp",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->slinp) free(cfg->slinp);
cfg->slinp = strdup(ptr);
} else if (strncmp(ptr,"qmout",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->qmout) free(cfg->qmout);
cfg->qmout = strdup(ptr);
} else if (strncmp(ptr,"maout",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->maout) free(cfg->maout);
cfg->maout = strdup(ptr);
} else if (strncmp(ptr,"slout",5) == 0) {
ptr = skip_whitespace(ptr+5);
trim_whitespace(ptr);
if (cfg->slout) free(cfg->slout);
cfg->slout = strdup(ptr);
} else if (strncmp(ptr,"qmcmd",5) == 0) {
ptr = skip_whitespace(ptr+5);
if (cfg->qmcmd) free(cfg->qmcmd);
cfg->qmcmd = strdup(ptr);
} else if (strncmp(ptr,"macmd",5) == 0) {
ptr = skip_whitespace(ptr+5);
if (cfg->macmd) free(cfg->macmd);
cfg->macmd = strdup(ptr);
} else if (strncmp(ptr,"slcmd",5) == 0) {
ptr = skip_whitespace(ptr+5);
if (cfg->slcmd) free(cfg->slcmd);
cfg->slcmd = strdup(ptr);
} else if (strncmp(ptr,"qmarg",5) == 0) {
ptr = skip_whitespace(ptr+5);
if (cfg->qmarg) free(cfg->qmarg);
cfg->qmarg = strdup(ptr);
} else if (strncmp(ptr,"maarg",5) == 0) {
ptr = skip_whitespace(ptr+5);
if (cfg->maarg) free(cfg->maarg);
cfg->maarg = strdup(ptr);
} else if (strncmp(ptr,"slarg",5) == 0) {
ptr = skip_whitespace(ptr+5);
if (cfg->slarg) free(cfg->slarg);
cfg->slarg = strdup(ptr);
} else {
fprintf(stderr,"\nParse error in line %d of file %s\n>>%s<<\n\n",
lineno, file, buf);
return QMMM_ERROR;
}
if (feof(fp)) break;
}
fclose(fp);
return QMMM_OK;
}
/* perform consistency checks on a qmmm_config_t struct */
const char *check_qmmm_config(qmmm_config_t *cfg) {
const char *msg = NULL;
if (cfg->qmmm_mode == QMMM_MODE_NONE) {
msg = "QM/MM coupling mode not set";
} else if (cfg->steps < 1) {
msg = "Number of QM/MM steps must be > 0";
} else if (cfg->qmdir == NULL) {
msg = "QM directory not set";
} else if (cfg->madir == NULL) {
msg = "MM master directory not set";
} else if (cfg->sldir == NULL) {
msg = "MM slave directory not set";
} else if (cfg->qminp == NULL) {
msg = "QM input file not set";
} else if (cfg->mainp == NULL) {
msg = "MM master input file not set";
} else if (cfg->slinp == NULL) {
msg = "MM slave input file not set";
} else if (cfg->qmout == NULL) {
msg = "QM output file not set";
} else if (cfg->maout == NULL) {
msg = "MM master output file not set";
} else if (cfg->slout == NULL) {
msg = "MM slave output file not set";
}
return msg;
}
/* take the existing global QM/MM configuration and write it to a file */
int write_qmmm_config(const char *file, qmmm_config_t *cfg)
{
FILE *fp;
time_t now;
if (cfg == NULL)
return QMMM_ERROR;
if (file == NULL)
fp = stderr;
else {
fp = fopen(file,"w");
if (fp == NULL) return QMMM_ERROR;
}
now = time(NULL);
fprintf(fp,"# QM/MM global configuration. %s\n",ctime(&now));
fprintf(fp,"# comm_mode: %d\n", cfg->comm_mode);
if (cfg->qmmm_mode == QMMM_MODE_OFF) {
fputs("mode off\n",fp);
} else if (cfg->qmmm_mode == QMMM_MODE_NONE) {
fputs("mode none\n",fp);
} else if (cfg->qmmm_mode == QMMM_MODE_MECH) {
fputs("mode mechanical\n",fp);
} else if (cfg->qmmm_mode == QMMM_MODE_ELEC) {
fputs("mode electrostatic\n",fp);
} else fputs("mode unknown\n",fp);
if (cfg->restart) fprintf(fp,"restart %s\n",cfg->restart);
if (cfg->handle) fprintf(fp,"handle %s\n", cfg->handle);
fprintf(fp,"steps %d\n",cfg->steps);
fprintf(fp,"verbose %d\n",cfg->verbose);
fputs("\n# QM system configuration:\n",fp);
if (cfg->qmdir) fprintf(fp,"qmdir %s\n", cfg->qmdir);
else fputs("qmdir (required input not set)\n",fp);
if (cfg->qminp) fprintf(fp,"qminp %s\n", cfg->qminp);
else fputs("qminp (required input not set)\n",fp);
if (cfg->qmout) fprintf(fp,"qmout %s\n", cfg->qmout);
else fputs("qmout NULL\n",fp);
if (cfg->qmcmd) fprintf(fp,"qmcmd %s\n", cfg->qmcmd);
if (cfg->qmarg) fprintf(fp,"qmarg %s\n", cfg->qmarg);
fputs("\n# MM master system configuration:\n",fp);
if (cfg->madir) fprintf(fp,"madir %s\n", cfg->madir);
else fputs("madir (required input not set)\n",fp);
if (cfg->mainp) fprintf(fp,"mainp %s\n", cfg->mainp);
else fputs("mainp (required input not set)\n",fp);
if (cfg->maout) fprintf(fp,"maout %s\n", cfg->maout);
else fputs("maout NULL\n",fp);
if (cfg->macmd) fprintf(fp,"macmd %s\n", cfg->macmd);
if (cfg->maarg) fprintf(fp,"maarg %s\n", cfg->maarg);
fputs("\n# MM slave system configuration:\n",fp);
if (cfg->sldir) fprintf(fp,"sldir %s\n", cfg->sldir);
else fputs("sldir (required input not set)\n",fp);
if (cfg->slinp) fprintf(fp,"slinp %s\n", cfg->slinp);
else fputs("slinp (required input not set)\n",fp);
if (cfg->slout) fprintf(fp,"slout %s\n", cfg->slout);
else fputs("slout NULL\n",fp);
if (cfg->slcmd) fprintf(fp,"slcmd %s\n", cfg->slcmd);
if (cfg->slarg) fprintf(fp,"slarg %s\n", cfg->slarg);
if (file != NULL) fclose(fp);
return QMMM_OK;
}
/* free storage associated with qmmm_config_t struct */
void free_qmmm_config(qmmm_config_t *cfg) {
if (cfg->qmdir != NULL) free(cfg->qmdir);
if (cfg->madir != NULL) free(cfg->madir);
if (cfg->sldir != NULL) free(cfg->sldir);
if (cfg->qminp != NULL) free(cfg->qminp);
if (cfg->mainp != NULL) free(cfg->mainp);
if (cfg->slinp != NULL) free(cfg->slinp);
if (cfg->qmout != NULL) free(cfg->qmout);
if (cfg->maout != NULL) free(cfg->maout);
if (cfg->slout != NULL) free(cfg->slout);
if (cfg->qmcmd != NULL) free(cfg->qmcmd);
if (cfg->macmd != NULL) free(cfg->macmd);
if (cfg->slcmd != NULL) free(cfg->slcmd);
if (cfg->qmarg != NULL) free(cfg->qmarg);
if (cfg->maarg != NULL) free(cfg->maarg);
if (cfg->slarg != NULL) free(cfg->slarg);
}

75
lib/qmmm/libqmmm.h Normal file
View File

@ -0,0 +1,75 @@
/*
* 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 .
*
* common definitions, APIs and global data for QM/MM interface
*/
#ifndef QE_LIBQMMM_H
#define QE_LIBQMMM_H
#ifdef __cplusplus
extern "C" {
#endif
/* transport method for data exchange between QM and MM codes */
#define QMMM_COMM_NONE 0
#define QMMM_COMM_MPI 1
#define QMMM_COMM_SHM 2
/* type or "level" of QM/MM coupling */
#define QMMM_MODE_OFF -1
#define QMMM_MODE_NONE 0
#define QMMM_MODE_MECH 1
#define QMMM_MODE_ELEC 2
/* flag indicating the role of this process in a QM/MM calculation */
#define QMMM_ROLE_QM 1
#define QMMM_ROLE_MASTER 2
#define QMMM_ROLE_SLAVE 3
#define QMMM_OK 0
#define QMMM_ERROR -1
/* container struct for global QM/MM configuration information */
typedef struct {
int comm_mode, qmmm_mode; /* communication and coupling mode */
char *qmdir, *madir, *sldir; /* directories to run codes in */
char *qminp, *mainp, *slinp; /* input files for codes */
char *qmout, *maout, *slout; /* stdout files for codes */
char *qmcmd, *macmd, *slcmd; /* command to run codes (SHMEM only) */
char *qmarg, *maarg, *slarg; /* extra flags to pass to code */
int verbose; /* verbosity level */
int role; /* role of this rank */
int steps; /* number of MD steps */
int nmm; /* tasks reserved for MD (master and slave) */
char *restart; /* name of (MM) restart file */
char *handle; /* handle for SHEMEM communication */
int my_comm, qm_comm, mm_comm; /* MPI communicators, Fortran-style */
} qmmm_config_t;
/* declare a global variable for the QM/MM setup.
thus there can be only one QM/MM coupling currently */
extern qmmm_config_t qmmmcfg;
/* read and parse global QM/MM configuration file and
* store the result in a qmmm_config_t struct */
int read_qmmm_config(const char *, qmmm_config_t *);
/* write out the global QM/MM configuration file in
* the same format as the read function can parse */
int write_qmmm_config(const char *, qmmm_config_t *);
/* perform consistency checks on a qmmm_config_t struct */
const char *check_qmmm_config(qmmm_config_t *);
/* free storage associated with qmmm_config_t struct */
void free_qmmm_config(qmmm_config_t *);
#ifdef __cplusplus
}
#endif
#endif /* QE_LIBQMMM_H */

365
lib/qmmm/pwqmmm.c Normal file
View File

@ -0,0 +1,365 @@
/* 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"
#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 (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 is not supported */
if (strncmp("-npot",ptr,5) == 0) {
ptr=strtok(NULL,delim);
npots=atoi(ptr);
} else 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;
if (me == 0) fprintf(stderr,"QM: nimage: %d npots: %d npools: %d "
"ntg: %d nband: %d ndiag: %d\n",
nimage,npots,npool,ntg,nband,ndiag);
/* 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 *cuda, *echo, *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("-c",ptr,2) == 0)
|| (strncmp("-cuda",ptr,5) == 0)) {
ptr=strtok(NULL,delim);
cuda=strdup(ptr);
} else if ((strncmp("-e",ptr,2) == 0)
|| (strncmp("-echo",ptr,5) == 0)) {
ptr=strtok(NULL,delim);
echo=strdup(ptr);
} else 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 *cuda, *echo, *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("-c",ptr,2) == 0)
|| (strncmp("-cuda",ptr,5) == 0)) {
ptr=strtok(NULL,delim);
cuda=strdup(ptr);
} else if ((strncmp("-e",ptr,2) == 0)
|| (strncmp("-echo",ptr,5) == 0)) {
ptr=strtok(NULL,delim);
echo=strdup(ptr);
} else 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;
}