From 6dfa0857880c6f13724acf00e44cb6652f19fb08 Mon Sep 17 00:00:00 2001 From: sjplimp Date: Mon, 29 Jan 2007 23:26:26 +0000 Subject: [PATCH] git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@251 f3b2605a-c512-4ea7-a41b-209d697bcdaa --- examples/couple/README | 69 +++++++---- .../couple/{umbrella.cpp => c++_driver.cpp} | 28 +++-- examples/couple/c_driver.c | 116 ++++++++++++++++++ 3 files changed, 180 insertions(+), 33 deletions(-) rename examples/couple/{umbrella.cpp => c++_driver.cpp} (82%) create mode 100644 examples/couple/c_driver.c diff --git a/examples/couple/README b/examples/couple/README index 4989e6415e..f766505788 100644 --- a/examples/couple/README +++ b/examples/couple/README @@ -1,10 +1,15 @@ -This directory has a code that shows how LAMMPS can be linked to a -driver application as a library. The purpose is to illustrate how -another code could perform computations while using LAMMPS to perform -MD, or how an umbrella code or script could call both LAMMPS and some -other code to perform a coupled calculation. +This directory has a C and C++ code that shows how LAMMPS can be +linked to a driver application as a library. The purpose is to +illustrate how another code could perform computations while using +LAMMPS to perform MD, or how an umbrella code or script could call +both LAMMPS and some other code to perform a coupled calculation. -Umbrella.cpp is the simple driving code that will call LAMMPS. +c_driver.c is the C driver +c++_driver.c is the C++ driver + +The 2 codes do the same thing, so you can compare them to see how to +drive LAMMPS in this manner. The C driver is similar in spirit to +what one could use from a Fortran program or scripting language. LAMMPS must first be built as a library. See the "Making LAMMPS" section of Section_start.html in the documentation for info on how to @@ -15,29 +20,49 @@ make -f Makefile.lib g++ in the LAMMPS src directory to create liblmp_g++.a -You can then build the umbrella code with a compile line something +You can then build either driver code with a compile line something like this, which includes paths to the LAMMPS library interface, MPI, and FFTW. -g++ -I/home/sjplimp/tools/mpich/include -I/home/sjplimp/lammps/src - -L/home/sjplimp/lammps/src -L/home/sjplimp/tools/mpich/lib - -L/home/sjplimp/tools/fftw/lib umbrella.cpp - -llmp_g++ -lfftw -lmpich -o umbrella +This builds the C driver with the LAMMPS library using a C compiler: -You then run umbrella on a parallel machine on some number -of processors Q with 2 arguments: +gcc -I/home/sjplimp/tools/mpich/include -I/home/sjplimp/lammps/new2 \ + -L/home/sjplimp/lammps/new2 -L/home/sjplimp/tools/mpich/lib \ + -L/home/sjplimp/tools/fftw/lib c_driver.c \ + -llmp_g++ -lfftw -lmpich -lstdc++ -o c_driver -mpirun -np Q umbrella P in.lj +This builds the C++ driver with the LAMMPS library using a C++ compiler: + +g++ -I/home/sjplimp/tools/mpich/include -I/home/sjplimp/lammps/new2 \ + -L/home/sjplimp/lammps/new2 -L/home/sjplimp/tools/mpich/lib \ + -L/home/sjplimp/tools/fftw/lib c++_driver.cpp \ + -llmp_g++ -lfftw -lmpich -o c++_driver + +You then run c_driver or c++_driver on a parallel machine on some +number of processors Q with 2 arguments: + +mpirun -np Q c_driver P in.lj P is the number of procs you want LAMMPS to run on (must be <= Q). In.lj is a LAMMPS input script. -Umbrella will launch LAMMPS on P procs, read the input -script a line at a time, and pass each command line to LAMMPS. The -final line of the script is a "run" command, so LAMMPS will run -the problem. +The driver will launch LAMMPS on P procs, read the input script a line +at a time, and pass each command line to LAMMPS. The final line of +the script is a "run" command, so LAMMPS will run the problem. -Umbrella then requests all the atom coordinates from LAMMPS, moves one -of the atoms a small amount "epsilon", passes the coordinates back to -LAMMPS, and runs LAMMPS again. If you look at the output, you should -see a small energy change between runs, due to the moved atom. +The driver then requests all the atom coordinates from LAMMPS, moves +one of the atoms a small amount "epsilon", passes the coordinates back +to LAMMPS, and runs LAMMPS again. If you look at the output, you +should see a small energy change between runs, due to the moved atom. + +The C driver is calling C-style routines in the src/library.cpp file +of LAMMPS. You could add any functions you wish to this file to +manipulate LAMMPS data however you wish. + +The C++ driver does the same thing, except that it instantiates LAMMPS +as an object first. Some of the functions in src/library.cpp can be +invoked directly as methods within appropriate LAMMPS classes, which +is what the driver does. Any public LAMMPS class method could be +called from the driver this way. However the get/put functions are +only implemented in src/library.cpp, so the C++ driver calls them as +C-style functions. diff --git a/examples/couple/umbrella.cpp b/examples/couple/c++_driver.cpp similarity index 82% rename from examples/couple/umbrella.cpp rename to examples/couple/c++_driver.cpp index 4e8184186b..4b59e61575 100644 --- a/examples/couple/umbrella.cpp +++ b/examples/couple/c++_driver.cpp @@ -23,8 +23,13 @@ #include "stdlib.h" #include "string.h" #include "mpi.h" +#include "lammps.h" // these are LAMMPS include files +#include "input.h" +#include "atom.h" #include "library.h" +using namespace LAMMPS_NS; + int main(int narg, char **arg) { // setup MPI and various communicators @@ -69,9 +74,10 @@ int main(int narg, char **arg) // run the input script thru LAMMPS one line at a time until end-of-file // umbrella proc 0 reads a line, Bcasts it to all procs // (could just send it to proc 0 of comm_lammps and let it Bcast) - // all LAMMPS procs call lammps_command() on the line - - if (lammps == 1) lammps_open(0,NULL,comm_lammps); + // all LAMMPS procs call input->one() on the line + + LAMMPS *lmp; + if (lammps == 1) lmp = new LAMMPS(0,NULL,comm_lammps); int n; char line[1024]; @@ -84,30 +90,30 @@ int main(int narg, char **arg) MPI_Bcast(&n,1,MPI_INT,0,MPI_COMM_WORLD); if (n == 0) break; MPI_Bcast(line,n,MPI_CHAR,0,MPI_COMM_WORLD); - if (lammps == 1) lammps_command(line); + if (lammps == 1) lmp->input->one(line); } - // run 10 steps + // run 10 more steps // get coords from LAMMPS // change coords of 1st atom // put coords back into LAMMPS // run a single step with changed coords if (lammps == 1) { - lammps_command("run 10"); + lmp->input->one("run 10"); - int natoms = lammps_get_natoms(); + int natoms = static_cast (lmp->atom->natoms); double *x = new double[3*natoms]; - lammps_get_coords(x); + lammps_get_coords(lmp,x); // no LAMMPS class function for this double epsilon = 0.1; x[0] += epsilon; - lammps_put_coords(x); + lammps_put_coords(lmp,x); // no LAMMPS class function for this delete [] x; - lammps_command("run 1"); + lmp->input->one("run 1"); } - if (lammps == 1) lammps_close(); + if (lammps == 1) delete lmp; // close down MPI diff --git a/examples/couple/c_driver.c b/examples/couple/c_driver.c new file mode 100644 index 0000000000..b219beb608 --- /dev/null +++ b/examples/couple/c_driver.c @@ -0,0 +1,116 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + www.cs.sandia.gov/~sjplimp/lammps.html + Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* umbrella = simple example of how an umbrella program + can invoke LAMMPS as a library on some subset of procs + Syntax: umbrella P in.lammps + P = # of procs to run LAMMPS on + must be <= # of procs the umbrella code itself runs on + in.lammps = LAMMPS input script + See README for compilation instructions */ + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "mpi.h" +#include "library.h" /* this is a LAMMPS include file */ + +int main(int narg, char **arg) +{ + /* setup MPI and various communicators + umbrella is all procs in MPI_COMM_WORLD + comm_lammps only has 1st P procs (could be all or any subset) */ + + MPI_Init(&narg,&arg); + + if (narg != 3) { + printf("Syntax: umbrella P in.lammps\n"); + exit(1); + } + + int me,nprocs; + MPI_Comm_rank(MPI_COMM_WORLD,&me); + MPI_Comm_size(MPI_COMM_WORLD,&nprocs); + + int nprocs_lammps = atoi(arg[1]); + if (nprocs_lammps > nprocs) { + if (me == 0) + printf("ERROR: LAMMPS cannot use more procs than available\n"); + MPI_Abort(MPI_COMM_WORLD,1); + } + + int lammps; + if (me < nprocs_lammps) lammps = 1; + else lammps = MPI_UNDEFINED; + MPI_Comm comm_lammps; + MPI_Comm_split(MPI_COMM_WORLD,lammps,0,&comm_lammps); + + /* open LAMMPS input script */ + + FILE *fp; + if (me == 0) { + fp = fopen(arg[2],"r"); + if (fp == NULL) { + printf("ERROR: Could not open LAMMPS input script\n"); + MPI_Abort(MPI_COMM_WORLD,1); + } + } + + /* run the input script thru LAMMPS one line at a time until end-of-file + umbrella proc 0 reads a line, Bcasts it to all procs + (could just send it to proc 0 of comm_lammps and let it Bcast) + all LAMMPS procs call lammps_command() on the line */ + + void *ptr; + if (lammps == 1) lammps_open(0,NULL,comm_lammps,&ptr); + + int n; + char line[1024]; + while (1) { + if (me == 0) { + if (fgets(line,1024,fp) == NULL) n = 0; + else n = strlen(line) + 1; + if (n == 0) fclose(fp); + } + MPI_Bcast(&n,1,MPI_INT,0,MPI_COMM_WORLD); + if (n == 0) break; + MPI_Bcast(line,n,MPI_CHAR,0,MPI_COMM_WORLD); + if (lammps == 1) lammps_command(ptr,line); + } + + /* run 10 more steps + get coords from LAMMPS + change coords of 1st atom + put coords back into LAMMPS + run a single step with changed coords */ + + if (lammps == 1) { + lammps_command(ptr,"run 10"); + + int natoms = lammps_get_natoms(ptr); + double *x = (double *) malloc(3*natoms*sizeof(double)); + lammps_get_coords(ptr,x); + double epsilon = 0.1; + x[0] += epsilon; + lammps_put_coords(ptr,x); + free(x); + + lammps_command(ptr,"run 1"); + } + + if (lammps == 1) lammps_close(ptr); + + /* close down MPI */ + + MPI_Finalize(); +}