441 lines
12 KiB
C++
441 lines
12 KiB
C++
// clang-format off
|
|
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
https://www.lammps.org/, Sandia National Laboratories
|
|
LAMMPS development team: developers@lammps.org
|
|
|
|
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.
|
|
------------------------------------------------------------------------- */
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Contributing author: Axel Kohlmeyer (Temple U)
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "dump_molfile.h"
|
|
|
|
#include "atom.h"
|
|
#include "comm.h"
|
|
#include "domain.h"
|
|
#include "error.h"
|
|
#include "group.h"
|
|
#include "memory.h"
|
|
#include "update.h"
|
|
|
|
#include <cmath>
|
|
#include <cstring>
|
|
|
|
#include "molfile_interface.h"
|
|
|
|
using namespace LAMMPS_NS;
|
|
typedef MolfileInterface MFI;
|
|
|
|
// syntax:
|
|
// dump <id> <groupid> molfile <every> <filename> <type> [<path>]
|
|
// path defaults to "." -> will look for .so files in CWD.
|
|
//
|
|
// XXX: potential change: add more options and make them optional
|
|
// path <path>
|
|
// template <file> <type> (import name and topology information from file)
|
|
// bonds <yes|no> (write out bond information)
|
|
// topology <yes|no> (write out all topology information)
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
DumpMolfile::DumpMolfile(LAMMPS *lmp, int narg, char **arg)
|
|
: Dump(lmp, narg, arg)
|
|
{
|
|
if (narg < 6) error->all(FLERR,"Illegal dump molfile command");
|
|
|
|
if (binary || compressed || multiproc)
|
|
error->all(FLERR,"Invalid dump molfile filename");
|
|
|
|
// required settings
|
|
|
|
sort_flag = 1;
|
|
sortcol = 0;
|
|
|
|
// storage for collected information
|
|
|
|
size_one = 4;
|
|
if (atom->molecule_flag) ++size_one;
|
|
if (atom->q_flag) ++size_one;
|
|
if (atom->rmass_flag) ++size_one;
|
|
if (atom->radius_flag) ++size_one;
|
|
|
|
need_structure = 0;
|
|
unwrap_flag = 0;
|
|
velocity_flag = 0;
|
|
topology_flag = 0;
|
|
ntotal = 0;
|
|
me = comm->me;
|
|
|
|
coords = vels = masses = charges = radiuses = nullptr;
|
|
types = molids = nullptr;
|
|
ntypes = atom->ntypes;
|
|
typenames = nullptr;
|
|
|
|
// allocate global array for atom coords
|
|
|
|
bigint n = group->count(igroup);
|
|
if (n > static_cast<bigint>(MAXSMALLINT/3/sizeof(float)))
|
|
error->all(FLERR,"Too many atoms for dump molfile");
|
|
if (n < 1)
|
|
error->all(FLERR,"Not enough atoms for dump molfile");
|
|
natoms = static_cast<int>(n);
|
|
|
|
if (me == 0) {
|
|
memory->create(types,natoms,"dump:types");
|
|
memory->create(coords,3*natoms,"dump:coords");
|
|
if (atom->molecule_flag) memory->create(molids,natoms,"dump:molids");
|
|
if (atom->q_flag) memory->create(charges,natoms,"dump:charges");
|
|
if (atom->rmass_flag) memory->create(masses,natoms,"dump:masses");
|
|
if (atom->radius_flag) memory->create(radiuses,natoms,"dump:radiuses");
|
|
|
|
mf = new MolfileInterface(arg[5],MFI::M_WRITE);
|
|
|
|
const char *path = (const char *) "."; // NOLINT
|
|
if (narg > 6)
|
|
path=arg[6];
|
|
|
|
if (mf->find_plugin(path)!= MFI::E_MATCH)
|
|
error->one(FLERR,"No suitable molfile plugin found");
|
|
|
|
if (screen)
|
|
fprintf(screen,"Dump '%s' uses molfile plugin: %s\n",
|
|
id, mf->get_plugin_name());
|
|
if (logfile)
|
|
fprintf(logfile,"Dump '%s' uses molfile plugin: %s\n",
|
|
id,mf->get_plugin_name());
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
DumpMolfile::~DumpMolfile()
|
|
{
|
|
if (me == 0) {
|
|
mf->close();
|
|
memory->destroy(types);
|
|
memory->destroy(coords);
|
|
memory->destroy(vels);
|
|
memory->destroy(masses);
|
|
memory->destroy(charges);
|
|
memory->destroy(radiuses);
|
|
delete mf;
|
|
}
|
|
|
|
if (typenames) {
|
|
for (int i = 1; i <= ntypes; i++)
|
|
delete[] typenames[i];
|
|
|
|
delete[] typenames;
|
|
typenames = nullptr;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void DumpMolfile::init_style()
|
|
{
|
|
if (sort_flag == 0 || sortcol != 0)
|
|
error->all(FLERR,"Dump molfile requires sorting by atom ID");
|
|
|
|
if (me == 0) {
|
|
|
|
/* initialize typenames array to numeric types by default */
|
|
if (typenames == nullptr) {
|
|
typenames = new char*[ntypes+1];
|
|
for (int itype = 1; itype <= ntypes; itype++) {
|
|
/* a 32-bit int can be maximally 10 digits plus sign */
|
|
typenames[itype] = utils::strdup(std::to_string(itype));
|
|
}
|
|
}
|
|
|
|
// open single file, one time only
|
|
if (multifile == 0) openfile();
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void DumpMolfile::write()
|
|
{
|
|
// simulation box dimensions
|
|
|
|
if (domain->triclinic == 1) {
|
|
double *h = domain->h;
|
|
double alen = h[0];
|
|
double blen = sqrt(h[5]*h[5] + h[1]*h[1]);
|
|
double clen = sqrt(h[4]*h[4] + h[3]*h[3] + h[2]*h[2]);
|
|
cell[0] = alen;
|
|
cell[1] = blen;
|
|
cell[2] = clen;
|
|
cell[3] = (90.0 - asin((h[5]*h[4] + h[1]*h[3]) / blen/clen)); // alpha
|
|
cell[4] = (90.0 - asin((h[0]*h[4]) / alen/clen)); // beta
|
|
cell[5] = (90.0 - asin((h[0]*h[5]) / alen/blen)); // gamma
|
|
} else {
|
|
cell[0] = domain->xprd;
|
|
cell[1] = domain->yprd;
|
|
cell[2] = domain->zprd;
|
|
cell[3] = cell[4] = cell[5] = 90.0f;
|
|
}
|
|
|
|
// nme = # of dump lines this proc will contribute to dump
|
|
|
|
nme = count();
|
|
bigint bnme = nme;
|
|
|
|
// ntotal = total # of dump lines
|
|
// nmax = max # of dump lines on any proc
|
|
|
|
int nmax;
|
|
MPI_Allreduce(&bnme,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
|
|
|
|
// for single file output, the number of atoms must not change.
|
|
if (natoms != ntotal) {
|
|
if (multifile == 0) {
|
|
error->all(FLERR,"Single file molfile dump needs constant #atoms");
|
|
} else {
|
|
natoms = ntotal;
|
|
}
|
|
}
|
|
ntotal = 0;
|
|
reorderflag = 0;
|
|
|
|
// if file per timestep, open new file
|
|
|
|
if (multifile) openfile();
|
|
|
|
// ensure proc 0 can receive everyone's info
|
|
// limit nmax*size_one to int since used as arg in MPI_Rsend() below
|
|
// pack my data into buf
|
|
// if sorting on IDs also request ID list from pack()
|
|
// sort buf as needed
|
|
|
|
if (nmax > maxbuf) {
|
|
if ((bigint) nmax * size_one > MAXSMALLINT)
|
|
error->all(FLERR,"Too much per-proc info for dump");
|
|
maxbuf = nmax;
|
|
memory->destroy(buf);
|
|
memory->create(buf,maxbuf*size_one,"dump:buf");
|
|
}
|
|
if (nmax > maxids) {
|
|
maxids = nmax;
|
|
memory->destroy(ids);
|
|
memory->create(ids,maxids,"dump:ids");
|
|
}
|
|
|
|
pack(ids);
|
|
sort();
|
|
|
|
int tmp,nlines;
|
|
|
|
if (me == 0) {
|
|
MPI_Status status;
|
|
MPI_Request request;
|
|
for (int iproc = 0; iproc < nprocs; iproc++) {
|
|
if (iproc) {
|
|
MPI_Irecv(buf,maxbuf*size_one,MPI_DOUBLE,iproc,0,world,&request);
|
|
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
|
|
MPI_Wait(&request,&status);
|
|
MPI_Get_count(&status,MPI_DOUBLE,&nlines);
|
|
nlines /= size_one;
|
|
} else nlines = nme;
|
|
|
|
write_data(nlines,buf);
|
|
}
|
|
|
|
} else {
|
|
MPI_Recv(&tmp,0,MPI_INT,0,0,world,MPI_STATUS_IGNORE);
|
|
MPI_Rsend(buf,nme*size_one,MPI_DOUBLE,0,0,world);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void DumpMolfile::openfile()
|
|
{
|
|
// single file, already opened, so just return
|
|
|
|
if (singlefile_opened) return;
|
|
if (multifile == 0) singlefile_opened = 1;
|
|
need_structure = 1;
|
|
|
|
if (me == 0) {
|
|
|
|
// close open file, if needed.
|
|
if (mf->is_open()) mf->close();
|
|
|
|
// if one file per timestep, replace '*' with current timestep
|
|
|
|
std::string filecurrent = filename;
|
|
if (multifile == 1)
|
|
filecurrent = utils::star_subst(filename, update->ntimestep, padflag);
|
|
|
|
if (mf->open(filecurrent.c_str(), &natoms))
|
|
error->one(FLERR,"Cannot open dump file {}: {}", filecurrent, utils::getsyserror());
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void DumpMolfile::pack(tagint *ids)
|
|
{
|
|
int m,n;
|
|
|
|
tagint *tag = atom->tag;
|
|
int *type = atom->type;
|
|
double **x = atom->x;
|
|
imageint *image = atom->image;
|
|
int *mask = atom->mask;
|
|
int nlocal = atom->nlocal;
|
|
|
|
m = n = 0;
|
|
if (unwrap_flag) {
|
|
double xprd = domain->xprd;
|
|
double yprd = domain->yprd;
|
|
double zprd = domain->zprd;
|
|
double xy = domain->xy;
|
|
double xz = domain->xz;
|
|
double yz = domain->yz;
|
|
|
|
for (int i = 0; i < nlocal; i++) {
|
|
if (mask[i] & groupbit) {
|
|
int ix = (image[i] & IMGMASK) - IMGMAX;
|
|
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
|
|
int iz = (image[i] >> IMG2BITS) - IMGMAX;
|
|
|
|
buf[m++] = type[i];
|
|
if (domain->triclinic) {
|
|
buf[m++] = x[i][0] + ix * xprd + iy * xy + iz * xz;
|
|
buf[m++] = x[i][1] + iy * yprd + iz * yz;
|
|
buf[m++] = x[i][2] + iz * zprd;
|
|
} else {
|
|
buf[m++] = x[i][0] + ix * xprd;
|
|
buf[m++] = x[i][1] + iy * yprd;
|
|
buf[m++] = x[i][2] + iz * zprd;
|
|
}
|
|
if (atom->molecule_flag) buf[m++] = atom->molecule[i];
|
|
if (atom->q_flag) buf[m++] = atom->q[i];
|
|
if (atom->rmass_flag) buf[m++] = atom->mass[i];
|
|
if (atom->radius_flag) buf[m++] = atom->radius[i];
|
|
ids[n++] = tag[i];
|
|
}
|
|
}
|
|
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
buf[m++] = type[i];
|
|
buf[m++] = x[i][0];
|
|
buf[m++] = x[i][1];
|
|
buf[m++] = x[i][2];
|
|
if (atom->molecule_flag) buf[m++] = atom->molecule[i];
|
|
if (atom->q_flag) buf[m++] = atom->q[i];
|
|
if (atom->rmass_flag) buf[m++] = atom->mass[i];
|
|
if (atom->radius_flag) buf[m++] = atom->radius[i];
|
|
ids[n++] = tag[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void DumpMolfile::write_data(int n, double *mybuf)
|
|
{
|
|
if (me == 0) {
|
|
// copy buf atom coords into global arrays
|
|
int m = 0;
|
|
for (int i = 0; i < n; i++) {
|
|
types[ntotal] = static_cast<int>(mybuf[m++]);
|
|
coords[3*ntotal + 0] = mybuf[m++];
|
|
coords[3*ntotal + 1] = mybuf[m++];
|
|
coords[3*ntotal + 2] = mybuf[m++];
|
|
if (atom->molecule_flag) molids[ntotal] = static_cast<int>(mybuf[m++]);
|
|
if (atom->q_flag) charges[ntotal] = mybuf[m++];
|
|
if (atom->rmass_flag) masses[ntotal] = mybuf[m++];
|
|
if (atom->radius_flag) radiuses[ntotal] = mybuf[m++];
|
|
++ntotal;
|
|
}
|
|
|
|
// if last chunk of atoms in this snapshot, write global arrays to file
|
|
|
|
if (ntotal == natoms) {
|
|
ntotal = 0;
|
|
|
|
if (need_structure) {
|
|
mf->property(MFI::P_NAME,types,typenames);
|
|
mf->property(MFI::P_TYPE,types,typenames);
|
|
|
|
if (atom->molecule_flag)
|
|
mf->property(MFI::P_RESI,molids);
|
|
|
|
if (atom->rmass_flag) {
|
|
mf->property(MFI::P_MASS,masses);
|
|
} else {
|
|
mf->property(MFI::P_MASS,types,atom->mass);
|
|
}
|
|
|
|
if (atom->q_flag)
|
|
mf->property(MFI::P_CHRG,charges);
|
|
|
|
if (atom->radius_flag)
|
|
mf->property(MFI::P_RADS,radiuses);
|
|
|
|
// update/write structure information in plugin
|
|
mf->structure();
|
|
need_structure = 0;
|
|
}
|
|
double simtime = update->ntimestep * update->dt;
|
|
mf->timestep(coords,nullptr,cell,&simtime);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int DumpMolfile::modify_param(int narg, char **arg)
|
|
{
|
|
if (strcmp(arg[0],"unwrap") == 0) {
|
|
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
|
|
unwrap_flag = utils::logical(FLERR,arg[1],false,lmp);
|
|
return 2;
|
|
|
|
} else if (strcmp(arg[0],"element") == 0) {
|
|
if (narg < ntypes+1)
|
|
error->all(FLERR, "Dump modify element names do not match atom types");
|
|
|
|
if (typenames) {
|
|
for (int i = 1; i <= ntypes; i++)
|
|
delete[] typenames[i];
|
|
|
|
delete[] typenames;
|
|
typenames = nullptr;
|
|
}
|
|
|
|
typenames = new char*[ntypes+1];
|
|
for (int itype = 1; itype <= ntypes; itype++) typenames[itype] = utils::strdup(arg[itype]);
|
|
|
|
return ntypes+1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
return # of bytes of allocated memory in buf and global coords array
|
|
------------------------------------------------------------------------- */
|
|
|
|
double DumpMolfile::memory_usage()
|
|
{
|
|
double bytes = Dump::memory_usage();
|
|
bytes += memory->usage(coords,natoms*3);
|
|
bytes += (double)sizeof(MFI);
|
|
return bytes;
|
|
}
|