/* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov 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. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "lammps.h" #include "memory.h" #include "error.h" #include "universe.h" #include "input.h" #include "atom.h" #include "update.h" #include "neighbor.h" #include "comm.h" #include "domain.h" #include "force.h" #include "modify.h" #include "group.h" #include "output.h" #include "timer.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- start up LAMMPS allocate fundamental classes (memory, error, universe, input) parse input switches initialize communicators, screen & logfile output input is allocated at end after MPI info is setup ------------------------------------------------------------------------- */ LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator) { init(narg, arg, communicator, 0); } LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator, int aslibrary) { init(narg, arg, communicator, aslibrary); } void LAMMPS::init(int narg, char **arg, MPI_Comm communicator, int aslibrary) { memory = new Memory(this); error = new Error(this, aslibrary); universe = new Universe(this,communicator); output = NULL; screen = NULL; logfile = NULL; // parse input switches int inflag = 0; int screenflag = 0; int logflag = 0; int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg],"-partition") == 0) { universe->existflag = 1; if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); iarg++; while (iarg < narg && arg[iarg][0] != '-') { universe->add_world(arg[iarg]); iarg++; } } else if (strcmp(arg[iarg],"-in") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); inflag = iarg + 1; iarg += 2; } else if (strcmp(arg[iarg],"-screen") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); screenflag = iarg + 1; iarg += 2; } else if (strcmp(arg[iarg],"-log") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); logflag = iarg + 1; iarg += 2; } else if (strcmp(arg[iarg],"-var") == 0) { if (iarg+3 > narg) error->universe_all("Invalid command-line argument"); iarg += 3; } else if (strcmp(arg[iarg],"-echo") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); iarg += 2; } else error->universe_all("Invalid command-line argument"); } // if no partition command-line switch, universe is one world w/ all procs if (universe->existflag == 0) universe->add_world(NULL); // sum of procs in all worlds must equal total # of procs if (!universe->consistent()) error->universe_all("Processor partitions are inconsistent"); // universe cannot use stdin for input file if (universe->existflag && inflag == 0) error->universe_all("Must use -in switch with multiple partitions"); // set universe screen and logfile if (universe->me == 0) { if (screenflag == 0) universe->uscreen = stdout; else if (strcmp(arg[screenflag],"none") == 0) universe->uscreen = NULL; else { universe->uscreen = fopen(arg[screenflag],"w"); if (universe->uscreen == NULL) error->universe_one("Cannot open universe screen file"); } if (logflag == 0) { universe->ulogfile = fopen("log.lammps","w"); if (universe->ulogfile == NULL) error->universe_one("Cannot open log.lammps"); } else if (strcmp(arg[logflag],"none") == 0) universe->ulogfile = NULL; else { universe->ulogfile = fopen(arg[logflag],"w"); if (universe->ulogfile == NULL) error->universe_one("Cannot open universe log file"); } } if (universe->me > 0) { if (screenflag == 0) universe->uscreen = stdout; else universe->uscreen = NULL; universe->ulogfile = NULL; } // universe does not exist on its own, only a single world // inherit settings from universe // set world screen, logfile, communicator, infile // open input script if from file if (universe->existflag == 0) { screen = universe->uscreen; logfile = universe->ulogfile; world = universe->uworld; infile = NULL; if (universe->me == 0) { if (inflag == 0) infile = stdin; else infile = fopen(arg[inflag],"r"); if (infile == NULL) { char str[128]; sprintf(str,"Cannot open input script %s",arg[inflag]); error->one(str); } } if (universe->me == 0) { if (screen) fprintf(screen,"LAMMPS (%s)\n",universe->version); if (logfile) fprintf(logfile,"LAMMPS (%s)\n",universe->version); } // universe is one or more worlds // split into separate communicators // set world screen, logfile, communicator, infile // open input script } else { int me; MPI_Comm_split(universe->uworld,universe->iworld,0,&world); MPI_Comm_rank(world,&me); if (me == 0) { if (screenflag == 0) { char str[32]; sprintf(str,"screen.%d",universe->iworld); screen = fopen(str,"w"); if (screen == NULL) error->one("Cannot open screen file"); } else if (strcmp(arg[screenflag],"none") == 0) screen = NULL; else { char str[128]; sprintf(str,"%s.%d",arg[screenflag],universe->iworld); screen = fopen(str,"w"); if (screen == NULL) error->one("Cannot open screen file"); } } else screen = NULL; if (me == 0) { if (logflag == 0) { char str[32]; sprintf(str,"log.lammps.%d",universe->iworld); logfile = fopen(str,"w"); if (logfile == NULL) error->one("Cannot open logfile"); } else if (strcmp(arg[logflag],"none") == 0) logfile = NULL; else { char str[128]; sprintf(str,"%s.%d",arg[logflag],universe->iworld); logfile = fopen(str,"w"); if (logfile == NULL) error->one("Cannot open logfile"); } } else logfile = NULL; if (me == 0) { infile = fopen(arg[inflag],"r"); if (infile == NULL) { char str[128]; sprintf(str,"Cannot open input script %s",arg[inflag]); error->one(str); } } else infile = NULL; // screen and logfile messages for universe and world if (universe->me == 0) { if (universe->uscreen) { fprintf(universe->uscreen,"LAMMPS (%s)\n",universe->version); fprintf(universe->uscreen,"Running on %d partitions of processors\n", universe->nworlds); } if (universe->ulogfile) { fprintf(universe->ulogfile,"LAMMPS (%s)\n",universe->version); fprintf(universe->ulogfile,"Running on %d partitions of processors\n", universe->nworlds); } } if (me == 0) { if (screen) { fprintf(screen,"LAMMPS (%s)\n",universe->version); fprintf(screen,"Processor partition = %d\n",universe->iworld); } if (logfile) { fprintf(logfile,"LAMMPS (%s)\n",universe->version); fprintf(logfile,"Processor partition = %d\n",universe->iworld); } } } // allocate input class now that MPI is fully setup input = new Input(this,narg,arg); // allocate top-level classes create(); } /* ---------------------------------------------------------------------- shutdown LAMMPS delete top-level classes close screen and log files in world and universe output files were already closed in destroy() delete fundamental classes ------------------------------------------------------------------------- */ LAMMPS::~LAMMPS() { destroy(); if (universe->nworlds == 1) { if (logfile) fclose(logfile); } else { if (screen && screen != stdout) fclose(screen); if (logfile) fclose(logfile); if (universe->ulogfile) fclose(universe->ulogfile); } if (world != universe->uworld) MPI_Comm_free(&world); delete input; delete universe; delete error; delete memory; } /* ---------------------------------------------------------------------- allocate single instance of top-level classes fundamental classes are allocated in constructor ------------------------------------------------------------------------- */ void LAMMPS::create() { atom = new Atom(this); neighbor = new Neighbor(this); comm = new Comm(this); domain = new Domain(this); group = new Group(this); force = new Force(this); // must be after group, to create temperature modify = new Modify(this); output = new Output(this); // must be after group, so "all" exists // must be after modify so can create Computes update = new Update(this); // must be after output, force, neighbor timer = new Timer(this); } /* ---------------------------------------------------------------------- initialize top-level classes ------------------------------------------------------------------------- */ void LAMMPS::init() { update->init(); force->init(); // pair must come after update due to minimizer domain->init(); atom->init(); // atom must come after force: // atom deletes extra array // used by fix shear_history::unpack_restart() // when force->pair->gran_history creates fix ?? modify->init(); // modify must come after update, force, atom, domain neighbor->init(); // neighbor must come after force, modify comm->init(); // comm must come after force, modify, neighbor output->init(); // output must come after domain, force, modify timer->init(); } /* ---------------------------------------------------------------------- delete single instance of top-level classes fundamental classes are deleted in destructor ------------------------------------------------------------------------- */ void LAMMPS::destroy() { delete update; delete neighbor; delete comm; delete force; delete group; delete output; delete modify; // modify must come after output, force, update // since they delete fixes delete domain; // domain must come after modify // since fix destructors access domain delete atom; // atom must come after modify, neighbor // since fixes delete callbacks in atom delete timer; }