2441 lines
86 KiB
C++
2441 lines
86 KiB
C++
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
https://www.lammps.org/, 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 "read_data.h"
|
|
|
|
#include "angle.h"
|
|
#include "atom.h"
|
|
#include "atom_vec.h"
|
|
#include "atom_vec_body.h"
|
|
#include "atom_vec_ellipsoid.h"
|
|
#include "atom_vec_line.h"
|
|
#include "atom_vec_tri.h"
|
|
#include "bond.h"
|
|
#include "comm.h"
|
|
#include "dihedral.h"
|
|
#include "domain.h"
|
|
#include "error.h"
|
|
#include "fix.h"
|
|
#include "force.h"
|
|
#include "group.h"
|
|
#include "improper.h"
|
|
#include "irregular.h"
|
|
#include "label_map.h"
|
|
#include "memory.h"
|
|
#include "modify.h"
|
|
#include "molecule.h"
|
|
#include "pair.h"
|
|
#include "special.h"
|
|
#include "tokenizer.h"
|
|
#include "update.h"
|
|
|
|
#include <cctype>
|
|
#include <cstring>
|
|
#include <unordered_set>
|
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
static constexpr int MAXLINE = 256;
|
|
static constexpr double LB_FACTOR = 1.1;
|
|
static constexpr int CHUNK = 1024;
|
|
static constexpr int DELTA = 4; // must be 2 or larger
|
|
static constexpr int MAXBODY = 32; // max # of lines in one body
|
|
|
|
// customize for new sections
|
|
|
|
// clang-format off
|
|
static std::unordered_set<std::string> section_keywords = {
|
|
"Atoms", "Velocities", "Ellipsoids", "Lines", "Triangles", "Bodies",
|
|
"Bonds", "Angles", "Dihedrals", "Impropers",
|
|
"Masses", "Pair Coeffs", "PairIJ Coeffs", "Bond Coeffs", "Angle Coeffs",
|
|
"Dihedral Coeffs", "Improper Coeffs",
|
|
"BondBond Coeffs", "BondAngle Coeffs", "MiddleBondTorsion Coeffs",
|
|
"EndBondTorsion Coeffs", "AngleTorsion Coeffs",
|
|
"AngleAngleTorsion Coeffs", "BondBond13 Coeffs", "AngleAngle Coeffs",
|
|
"Atom Type Labels", "Bond Type Labels", "Angle Type Labels",
|
|
"Dihedral Type Labels", "Improper Type Labels"
|
|
};
|
|
|
|
// function to check whether a string is a known data section name
|
|
// made a static class member, so it can be called from other classes
|
|
|
|
bool ReadData::is_data_section(const std::string &keyword)
|
|
{
|
|
return section_keywords.count(keyword) > 0;
|
|
}
|
|
|
|
enum{NONE, APPEND, VALUE, MERGE};
|
|
|
|
// pair style suffixes to ignore
|
|
// when matching Pair Coeffs comment to currently-defined pair style
|
|
|
|
static const char *suffixes[] = {"/cuda", "/gpu", "/opt", "/omp", "/kk", "/coul/cut", "/coul/long",
|
|
"/coul/msm", "/coul/dsf", "/coul/debye", "/coul/charmm", nullptr};
|
|
|
|
static const char *labeltypes[] = {"Atom", "Bond", "Angle", "Dihedral", "Improper" };
|
|
|
|
// clang-format on
|
|
/* ---------------------------------------------------------------------- */
|
|
ReadData::ReadData(LAMMPS *_lmp) : Command(_lmp), fp(nullptr), coeffarg(nullptr), lmap(nullptr)
|
|
{
|
|
MPI_Comm_rank(world, &me);
|
|
line = new char[MAXLINE];
|
|
keyword = new char[MAXLINE];
|
|
style = new char[MAXLINE];
|
|
buffer = new char[CHUNK * MAXLINE];
|
|
ncoeffarg = maxcoeffarg = 0;
|
|
|
|
// customize for new sections
|
|
// pointers to atom styles that store bonus info
|
|
|
|
nellipsoids = 0;
|
|
avec_ellipsoid = dynamic_cast<AtomVecEllipsoid *>(atom->style_match("ellipsoid"));
|
|
nlines = 0;
|
|
avec_line = dynamic_cast<AtomVecLine *>(atom->style_match("line"));
|
|
ntris = 0;
|
|
avec_tri = dynamic_cast<AtomVecTri *>(atom->style_match("tri"));
|
|
nbodies = 0;
|
|
avec_body = dynamic_cast<AtomVecBody *>(atom->style_match("body"));
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
ReadData::~ReadData()
|
|
{
|
|
delete[] line;
|
|
delete[] keyword;
|
|
delete[] style;
|
|
delete[] buffer;
|
|
memory->sfree(coeffarg);
|
|
|
|
for (int i = 0; i < nfix; i++) {
|
|
delete[] fix_header[i];
|
|
delete[] fix_section[i];
|
|
}
|
|
memory->sfree(fix_index);
|
|
memory->sfree(fix_header);
|
|
memory->sfree(fix_section);
|
|
|
|
delete lmap;
|
|
}
|
|
|
|
// clang format off
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::command(int narg, char **arg)
|
|
{
|
|
if (narg < 1) utils::missing_cmd_args(FLERR, "read_data", error);
|
|
|
|
MPI_Barrier(world);
|
|
double time1 = platform::walltime();
|
|
|
|
// optional args
|
|
|
|
addflag = NONE;
|
|
coeffflag = 1;
|
|
id_offset = mol_offset = 0;
|
|
offsetflag = shiftflag = settypeflag = 0;
|
|
tlabelflag = blabelflag = alabelflag = dlabelflag = ilabelflag = 0;
|
|
toffset = boffset = aoffset = doffset = ioffset = 0;
|
|
shift[0] = shift[1] = shift[2] = 0.0;
|
|
extra_atom_types = extra_bond_types = extra_angle_types = extra_dihedral_types =
|
|
extra_improper_types = 0;
|
|
|
|
groupbit = 0;
|
|
|
|
nfix = 0;
|
|
fix_index = nullptr;
|
|
fix_header = nullptr;
|
|
fix_section = nullptr;
|
|
|
|
int iarg = 1;
|
|
while (iarg < narg) {
|
|
if (strcmp(arg[iarg], "add") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data add", error);
|
|
if (strcmp(arg[iarg + 1], "append") == 0)
|
|
addflag = APPEND;
|
|
else if (strcmp(arg[iarg + 1], "merge") == 0)
|
|
addflag = MERGE;
|
|
else {
|
|
if (atom->molecule_flag && (iarg + 3 > narg))
|
|
utils::missing_cmd_args(FLERR, "read_data add", error);
|
|
addflag = VALUE;
|
|
bigint offset = utils::bnumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (offset > MAXTAGINT)
|
|
error->all(FLERR, "Read data add atomID offset {} is too big", offset);
|
|
id_offset = offset;
|
|
|
|
if (atom->molecule_flag) {
|
|
offset = utils::bnumeric(FLERR, arg[iarg + 2], false, lmp);
|
|
if (offset > MAXTAGINT)
|
|
error->all(FLERR, "Read data add molID offset {} is too big", offset);
|
|
mol_offset = offset;
|
|
iarg++;
|
|
}
|
|
}
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "offset") == 0) {
|
|
if (iarg + 6 > narg) utils::missing_cmd_args(FLERR, "read_data offset", error);
|
|
offsetflag = 1;
|
|
toffset = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
boffset = utils::inumeric(FLERR, arg[iarg + 2], false, lmp);
|
|
aoffset = utils::inumeric(FLERR, arg[iarg + 3], false, lmp);
|
|
doffset = utils::inumeric(FLERR, arg[iarg + 4], false, lmp);
|
|
ioffset = utils::inumeric(FLERR, arg[iarg + 5], false, lmp);
|
|
if (toffset < 0 || boffset < 0 || aoffset < 0 || doffset < 0 || ioffset < 0)
|
|
error->all(FLERR, "Illegal read_data offset value(s)");
|
|
iarg += 6;
|
|
} else if (strcmp(arg[iarg], "shift") == 0) {
|
|
if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "read_data shift", error);
|
|
shiftflag = 1;
|
|
shift[0] = utils::numeric(FLERR, arg[iarg + 1], false, lmp);
|
|
shift[1] = utils::numeric(FLERR, arg[iarg + 2], false, lmp);
|
|
shift[2] = utils::numeric(FLERR, arg[iarg + 3], false, lmp);
|
|
if (domain->dimension == 2 && shift[2] != 0.0)
|
|
error->all(FLERR, "Non-zero read_data shift z value for 2d simulation not allowed");
|
|
iarg += 4;
|
|
} else if (strcmp(arg[iarg], "nocoeff") == 0) {
|
|
coeffflag = 0;
|
|
iarg++;
|
|
} else if (strcmp(arg[iarg], "extra/atom/types") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/atom/types", error);
|
|
extra_atom_types = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (extra_atom_types < 0)
|
|
error->all(FLERR, "Illegal read_data extra/atom/types value {}", extra_atom_types);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/bond/types") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/bond/types", error);
|
|
if (!atom->avec->bonds_allow)
|
|
error->all(FLERR, "No bonds allowed with atom style {}", atom->get_style());
|
|
extra_bond_types = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (extra_bond_types < 0)
|
|
error->all(FLERR, "Illegal read_data extra/bond/types value {}", extra_bond_types);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/angle/types") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/angle/types", error);
|
|
if (!atom->avec->angles_allow)
|
|
error->all(FLERR, "No angles allowed with atom style {}", atom->get_style());
|
|
extra_angle_types = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (extra_angle_types < 0)
|
|
error->all(FLERR, "Illegal read_data extra/angle/types value {}", extra_angle_types);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/dihedral/types") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/dihedral/types", error);
|
|
if (!atom->avec->dihedrals_allow)
|
|
error->all(FLERR, "No dihedrals allowed with atom style {}", atom->get_style());
|
|
extra_dihedral_types = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (extra_dihedral_types < 0)
|
|
error->all(FLERR, "Illegal read_data extra/dihedral/types value {}", extra_dihedral_types);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/improper/types") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/improper/types", error);
|
|
if (!atom->avec->impropers_allow)
|
|
error->all(FLERR, "No impropers allowed with atom style {}", atom->get_style());
|
|
extra_improper_types = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (extra_improper_types < 0)
|
|
error->all(FLERR, "Illegal read_data extra/improper/types value {}", extra_improper_types);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/bond/per/atom") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/bond/per/atom", error);
|
|
if (atom->molecular == Atom::ATOMIC)
|
|
error->all(FLERR, "No bonds allowed with atom style {}", atom->get_style());
|
|
atom->extra_bond_per_atom = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (atom->extra_bond_per_atom < 0)
|
|
error->all(FLERR, "Illegal read_data extra/bond/per/atom value {}",
|
|
atom->extra_bond_per_atom);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/angle/per/atom") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/angle/per/atom", error);
|
|
if (atom->molecular == Atom::ATOMIC)
|
|
error->all(FLERR, "No angles allowed with atom style {}", atom->get_style());
|
|
atom->extra_angle_per_atom = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (atom->extra_angle_per_atom < 0)
|
|
error->all(FLERR, "Illegal read_data extra/angle/per/atom value {}",
|
|
atom->extra_angle_per_atom);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/dihedral/per/atom") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/dihedral/per/atom", error);
|
|
if (atom->molecular == Atom::ATOMIC)
|
|
error->all(FLERR, "No dihedrals allowed with atom style {}", atom->get_style());
|
|
atom->extra_dihedral_per_atom = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (atom->extra_dihedral_per_atom < 0)
|
|
error->all(FLERR, "Illegal read_data extra/dihedral/per/atom value {}",
|
|
atom->extra_dihedral_per_atom);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/improper/per/atom") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/improper/per/atom", error);
|
|
if (atom->molecular == Atom::ATOMIC)
|
|
error->all(FLERR, "No impropers allowed with atom style {}", atom->get_style());
|
|
atom->extra_improper_per_atom = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (atom->extra_improper_per_atom < 0)
|
|
error->all(FLERR, "Illegal read_data extra/improper/per/atom value {}",
|
|
atom->extra_improper_per_atom);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "extra/special/per/atom") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data extra/special/per/atom", error);
|
|
if (atom->molecular == Atom::ATOMIC)
|
|
error->all(FLERR, "No bonded interactions allowed with atom style {}", atom->get_style());
|
|
force->special_extra = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
|
if (force->special_extra < 0)
|
|
error->all(FLERR, "Illegal read_data extra/special/per/atom value {}", force->special_extra);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "group") == 0) {
|
|
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "read_data group", error);
|
|
int igroup = group->find_or_create(arg[iarg + 1]);
|
|
groupbit = group->bitmask[igroup];
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg], "fix") == 0) {
|
|
if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "read_data fix", error);
|
|
fix_index =
|
|
(Fix **) memory->srealloc(fix_index, (nfix + 1) * sizeof(Fix *), "read_data:fix_index");
|
|
fix_header = (char **) memory->srealloc(fix_header, (nfix + 1) * sizeof(char *),
|
|
"read_data:fix_header");
|
|
fix_section = (char **) memory->srealloc(fix_section, (nfix + 1) * sizeof(char *),
|
|
"read_data:fix_section");
|
|
if (is_data_section(arg[iarg + 3]))
|
|
error->all(FLERR,
|
|
"Custom data section name {} for fix {} collides with existing data section",
|
|
arg[iarg + 3], arg[iarg + 1]);
|
|
fix_index[nfix] = modify->get_fix_by_id(arg[iarg + 1]);
|
|
if (!fix_index[nfix])
|
|
error->all(FLERR, "Fix ID {} for read_data does not exist", arg[iarg + 1]);
|
|
if (strcmp(arg[iarg + 2], "NULL") == 0)
|
|
fix_header[nfix] = nullptr;
|
|
else
|
|
fix_header[nfix] = utils::strdup(arg[iarg + 2]);
|
|
if (strcmp(arg[iarg + 3], "NULL") == 0)
|
|
fix_section[nfix] = utils::strdup(arg[iarg + 1]);
|
|
else
|
|
fix_section[nfix] = utils::strdup(arg[iarg + 3]);
|
|
nfix++;
|
|
iarg += 4;
|
|
|
|
} else
|
|
error->all(FLERR, "Unknown read_data keyword {}", arg[iarg]);
|
|
}
|
|
|
|
// error checks
|
|
|
|
if ((domain->dimension == 2) && (domain->zperiodic == 0))
|
|
error->all(FLERR, "Cannot run 2d simulation with nonperiodic Z dimension");
|
|
if ((domain->nonperiodic == 2) && utils::strmatch(force->kspace_style, "^msm"))
|
|
error->all(FLERR,
|
|
"Reading a data file with shrinkwrap boundaries is "
|
|
"not compatible with a MSM KSpace style");
|
|
if (domain->box_exist && !addflag)
|
|
error->all(FLERR, "Cannot use read_data without add keyword after simulation box is defined");
|
|
if (!domain->box_exist && addflag)
|
|
error->all(FLERR, "Cannot use read_data add before simulation box is defined");
|
|
if (offsetflag) {
|
|
if (addflag == NONE) {
|
|
error->all(FLERR, "Cannot use read_data offset without add keyword");
|
|
} else {
|
|
if (atom->labelmapflag) {
|
|
if (comm->me == 0)
|
|
error->warning(FLERR, "Using read_data offset with a labelmap. Offsets will be only "
|
|
"applied to numeric types and not to type labels");
|
|
}
|
|
}
|
|
}
|
|
if (shiftflag && addflag == NONE)
|
|
error->all(FLERR, "Cannot use read_data shift without add keyword");
|
|
if (addflag != NONE &&
|
|
(extra_atom_types || extra_bond_types || extra_angle_types || extra_dihedral_types ||
|
|
extra_improper_types))
|
|
error->all(FLERR, "Cannot use any read_data extra/*/types keyword with add keyword");
|
|
|
|
// check if data file is available and readable
|
|
|
|
if (!platform::file_is_readable(arg[0]))
|
|
error->all(FLERR, fmt::format("Cannot open file {}: {}", arg[0], utils::getsyserror()));
|
|
|
|
// reset so we can warn about reset image flags exactly once per data file
|
|
|
|
atom->reset_image_flag[0] = atom->reset_image_flag[1] = atom->reset_image_flag[2] = false;
|
|
|
|
// first time system initialization
|
|
|
|
if (addflag == NONE) {
|
|
domain->box_exist = 1;
|
|
update->ntimestep = 0;
|
|
}
|
|
|
|
// compute atomID and optionally moleculeID offset for addflag = APPEND
|
|
|
|
if (addflag == APPEND) {
|
|
tagint *tag = atom->tag;
|
|
tagint *molecule = atom->molecule;
|
|
int nlocal = atom->nlocal;
|
|
tagint maxid = 0, maxmol = 0;
|
|
for (int i = 0; i < nlocal; i++) maxid = MAX(maxid, tag[i]);
|
|
if (atom->molecule_flag)
|
|
for (int i = 0; i < nlocal; i++) maxmol = MAX(maxmol, molecule[i]);
|
|
MPI_Allreduce(&maxid, &id_offset, 1, MPI_LMP_TAGINT, MPI_MAX, world);
|
|
MPI_Allreduce(&maxmol, &mol_offset, 1, MPI_LMP_TAGINT, MPI_MAX, world);
|
|
}
|
|
|
|
// set up pointer to hold original styles while we replace them with "zero"
|
|
|
|
Pair *saved_pair = nullptr;
|
|
Bond *saved_bond = nullptr;
|
|
Angle *saved_angle = nullptr;
|
|
Dihedral *saved_dihedral = nullptr;
|
|
Improper *saved_improper = nullptr;
|
|
KSpace *saved_kspace = nullptr;
|
|
char *saved_pair_style = nullptr;
|
|
char *saved_bond_style = nullptr;
|
|
char *saved_angle_style = nullptr;
|
|
char *saved_dihedral_style = nullptr;
|
|
char *saved_improper_style = nullptr;
|
|
char *saved_kspace_style = nullptr;
|
|
|
|
if (coeffflag == 0) {
|
|
char *coeffs[2];
|
|
coeffs[0] = (char *) "10.0";
|
|
coeffs[1] = (char *) "nocoeff";
|
|
|
|
saved_pair = force->pair;
|
|
saved_pair_style = force->pair_style;
|
|
force->pair = nullptr;
|
|
force->pair_style = nullptr;
|
|
force->create_pair("zero", 0);
|
|
if (force->pair) force->pair->settings(2, coeffs);
|
|
|
|
coeffs[0] = coeffs[1];
|
|
saved_bond = force->bond;
|
|
saved_bond_style = force->bond_style;
|
|
force->bond = nullptr;
|
|
force->bond_style = nullptr;
|
|
force->create_bond("zero", 0);
|
|
if (force->bond) force->bond->settings(1, coeffs);
|
|
|
|
saved_angle = force->angle;
|
|
saved_angle_style = force->angle_style;
|
|
force->angle = nullptr;
|
|
force->angle_style = nullptr;
|
|
force->create_angle("zero", 0);
|
|
if (force->angle) force->angle->settings(1, coeffs);
|
|
|
|
saved_dihedral = force->dihedral;
|
|
saved_dihedral_style = force->dihedral_style;
|
|
force->dihedral = nullptr;
|
|
force->dihedral_style = nullptr;
|
|
force->create_dihedral("zero", 0);
|
|
if (force->dihedral) force->dihedral->settings(1, coeffs);
|
|
|
|
saved_improper = force->improper;
|
|
saved_improper_style = force->improper_style;
|
|
force->improper = nullptr;
|
|
force->improper_style = nullptr;
|
|
force->create_improper("zero", 0);
|
|
if (force->improper) force->improper->settings(1, coeffs);
|
|
|
|
saved_kspace = force->kspace;
|
|
saved_kspace_style = force->kspace_style;
|
|
force->kspace = nullptr;
|
|
force->kspace_style = nullptr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------
|
|
|
|
// perform 1-pass read if no molecular topology in file
|
|
// perform 2-pass read if molecular topology,
|
|
// first pass calculates max topology/atom
|
|
|
|
// flags for this data file
|
|
|
|
int atomflag, topoflag;
|
|
int bondflag, angleflag, dihedralflag, improperflag;
|
|
int ellipsoidflag, lineflag, triflag, bodyflag;
|
|
|
|
atomflag = topoflag = 0;
|
|
bondflag = angleflag = dihedralflag = improperflag = 0;
|
|
ellipsoidflag = lineflag = triflag = bodyflag = 0;
|
|
|
|
// values in this data file
|
|
|
|
natoms = 0;
|
|
ntypes = 0;
|
|
nbonds = nangles = ndihedrals = nimpropers = 0;
|
|
nbondtypes = nangletypes = ndihedraltypes = nimpropertypes = 0;
|
|
|
|
boxlo[0] = boxlo[1] = boxlo[2] = -0.5;
|
|
boxhi[0] = boxhi[1] = boxhi[2] = 0.5;
|
|
triclinic = 0;
|
|
keyword[0] = '\0';
|
|
|
|
nlocal_previous = atom->nlocal;
|
|
int firstpass = 1;
|
|
|
|
while (true) {
|
|
|
|
// open file on proc 0
|
|
|
|
if (me == 0) {
|
|
if (firstpass) utils::logmesg(lmp, "Reading data file ...\n");
|
|
open(arg[0]);
|
|
} else
|
|
fp = nullptr;
|
|
|
|
// read header info
|
|
|
|
header(firstpass);
|
|
|
|
// problem setup using info from header
|
|
// only done once, if firstpass and first data file
|
|
// apply extra settings before grow(), even if no topology in file
|
|
// deallocate() insures new settings are used for topology arrays
|
|
// if per-atom topology is in file, another grow() is done below
|
|
|
|
if (firstpass && addflag == NONE) {
|
|
atom->bond_per_atom = atom->extra_bond_per_atom;
|
|
atom->angle_per_atom = atom->extra_angle_per_atom;
|
|
atom->dihedral_per_atom = atom->extra_dihedral_per_atom;
|
|
atom->improper_per_atom = atom->extra_improper_per_atom;
|
|
|
|
int n;
|
|
if (comm->nprocs == 1)
|
|
n = static_cast<int>(atom->natoms);
|
|
else
|
|
n = static_cast<int>(LB_FACTOR * atom->natoms / comm->nprocs);
|
|
|
|
atom->allocate_type_arrays();
|
|
atom->deallocate_topology();
|
|
|
|
// allocate atom arrays to N, rounded up by AtomVec->DELTA
|
|
|
|
bigint nbig = n;
|
|
nbig = atom->avec->roundup(nbig);
|
|
n = static_cast<int>(nbig);
|
|
atom->avec->grow(n);
|
|
|
|
domain->boxlo[0] = boxlo[0];
|
|
domain->boxhi[0] = boxhi[0];
|
|
domain->boxlo[1] = boxlo[1];
|
|
domain->boxhi[1] = boxhi[1];
|
|
domain->boxlo[2] = boxlo[2];
|
|
domain->boxhi[2] = boxhi[2];
|
|
|
|
if (triclinic) {
|
|
domain->triclinic = 1;
|
|
domain->xy = xy;
|
|
domain->xz = xz;
|
|
domain->yz = yz;
|
|
}
|
|
|
|
domain->print_box(" ");
|
|
domain->set_initial_box();
|
|
domain->set_global_box();
|
|
comm->set_proc_grid();
|
|
domain->set_local_box();
|
|
}
|
|
|
|
// change simulation box to be union of existing box and new box + shift
|
|
// only done if firstpass and not first data file
|
|
|
|
if (firstpass && addflag != NONE) {
|
|
domain->boxlo[0] = MIN(domain->boxlo[0], boxlo[0] + shift[0]);
|
|
domain->boxhi[0] = MAX(domain->boxhi[0], boxhi[0] + shift[0]);
|
|
domain->boxlo[1] = MIN(domain->boxlo[1], boxlo[1] + shift[1]);
|
|
domain->boxhi[1] = MAX(domain->boxhi[1], boxhi[1] + shift[1]);
|
|
domain->boxlo[2] = MIN(domain->boxlo[2], boxlo[2] + shift[2]);
|
|
domain->boxhi[2] = MAX(domain->boxhi[2], boxhi[2] + shift[2]);
|
|
|
|
// NOTE: not sure what to do about tilt value in subsequent data files
|
|
//if (triclinic) {
|
|
// domain->xy = xy; domain->xz = xz; domain->yz = yz;
|
|
// }
|
|
|
|
domain->print_box(" ");
|
|
domain->set_initial_box();
|
|
domain->set_global_box();
|
|
comm->set_proc_grid();
|
|
domain->set_local_box();
|
|
}
|
|
|
|
// allocate space for type label map
|
|
|
|
if (firstpass) {
|
|
delete lmap;
|
|
lmap = new LabelMap(lmp, ntypes, nbondtypes, nangletypes, ndihedraltypes, nimpropertypes);
|
|
}
|
|
|
|
// customize for new sections
|
|
// read rest of file in free format
|
|
|
|
while (strlen(keyword)) {
|
|
|
|
if (strcmp(keyword, "Atoms") == 0) {
|
|
atomflag = 1;
|
|
if (firstpass) {
|
|
if (me == 0 && !style_match(style, atom->atom_style))
|
|
error->warning(FLERR,
|
|
"Atom style in data file differs from currently defined atom style");
|
|
atoms();
|
|
} else
|
|
skip_lines(natoms);
|
|
|
|
} else if (strcmp(keyword, "Velocities") == 0) {
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Velocities");
|
|
if (firstpass)
|
|
velocities();
|
|
else
|
|
skip_lines(natoms);
|
|
|
|
} else if (strcmp(keyword, "Bonds") == 0) {
|
|
topoflag = bondflag = 1;
|
|
if (nbonds == 0) error->all(FLERR, "Invalid data file section: Bonds");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Bonds");
|
|
bonds(firstpass);
|
|
|
|
} else if (strcmp(keyword, "Angles") == 0) {
|
|
topoflag = angleflag = 1;
|
|
if (nangles == 0) error->all(FLERR, "Invalid data file section: Angles");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Angles");
|
|
angles(firstpass);
|
|
|
|
} else if (strcmp(keyword, "Dihedrals") == 0) {
|
|
topoflag = dihedralflag = 1;
|
|
if (ndihedrals == 0) error->all(FLERR, "Invalid data file section: Dihedrals");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Dihedrals");
|
|
dihedrals(firstpass);
|
|
|
|
} else if (strcmp(keyword, "Impropers") == 0) {
|
|
topoflag = improperflag = 1;
|
|
if (nimpropers == 0) error->all(FLERR, "Invalid data file section: Impropers");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Impropers");
|
|
impropers(firstpass);
|
|
|
|
} else if (strcmp(keyword, "Ellipsoids") == 0) {
|
|
ellipsoidflag = 1;
|
|
if (!avec_ellipsoid) error->all(FLERR, "Invalid data file section: Ellipsoids");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Ellipsoids");
|
|
if (firstpass)
|
|
bonus(nellipsoids, (AtomVec *) avec_ellipsoid, "ellipsoids");
|
|
else
|
|
skip_lines(nellipsoids);
|
|
|
|
} else if (strcmp(keyword, "Lines") == 0) {
|
|
lineflag = 1;
|
|
if (!avec_line) error->all(FLERR, "Invalid data file section: Lines");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Lines");
|
|
if (firstpass)
|
|
bonus(nlines, (AtomVec *) avec_line, "lines");
|
|
else
|
|
skip_lines(nlines);
|
|
|
|
} else if (strcmp(keyword, "Triangles") == 0) {
|
|
triflag = 1;
|
|
if (!avec_tri) error->all(FLERR, "Invalid data file section: Triangles");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Triangles");
|
|
if (firstpass)
|
|
bonus(ntris, (AtomVec *) avec_tri, "triangles");
|
|
else
|
|
skip_lines(ntris);
|
|
|
|
} else if (strcmp(keyword, "Bodies") == 0) {
|
|
bodyflag = 1;
|
|
if (!avec_body) error->all(FLERR, "Invalid data file section: Bodies");
|
|
if (atomflag == 0) error->all(FLERR, "Must read Atoms before Bodies");
|
|
bodies(firstpass, (AtomVec *) avec_body);
|
|
|
|
} else if (strcmp(keyword, "Masses") == 0) {
|
|
if (firstpass)
|
|
mass();
|
|
else
|
|
skip_lines(ntypes);
|
|
} else if (strcmp(keyword, "Pair Coeffs") == 0) {
|
|
if (force->pair == nullptr) error->all(FLERR, "Must define pair_style before Pair Coeffs");
|
|
if (firstpass) {
|
|
if (me == 0 && !style_match(style, force->pair_style))
|
|
error->warning(FLERR,
|
|
"Pair style in data file differs from currently defined pair style");
|
|
paircoeffs();
|
|
} else
|
|
skip_lines(ntypes);
|
|
} else if (strcmp(keyword, "PairIJ Coeffs") == 0) {
|
|
if (force->pair == nullptr)
|
|
error->all(FLERR, "Must define pair_style before PairIJ Coeffs");
|
|
if (firstpass) {
|
|
if (me == 0 && !style_match(style, force->pair_style))
|
|
error->warning(FLERR,
|
|
"Pair style in data file differs "
|
|
"from currently defined pair style");
|
|
pairIJcoeffs();
|
|
} else
|
|
skip_lines(ntypes * (ntypes + 1) / 2);
|
|
} else if (strcmp(keyword, "Bond Coeffs") == 0) {
|
|
if (atom->avec->bonds_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: Bond Coeffs");
|
|
if (force->bond == nullptr) error->all(FLERR, "Must define bond_style before Bond Coeffs");
|
|
if (firstpass) {
|
|
if (me == 0 && !style_match(style, force->bond_style))
|
|
error->warning(FLERR,
|
|
"Bond style in data file differs from currently defined bond style");
|
|
bondcoeffs();
|
|
} else
|
|
skip_lines(nbondtypes);
|
|
} else if (strcmp(keyword, "Angle Coeffs") == 0) {
|
|
if (atom->avec->angles_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: Angle Coeffs");
|
|
if (force->angle == nullptr)
|
|
error->all(FLERR, "Must define angle_style before Angle Coeffs");
|
|
if (firstpass) {
|
|
if (me == 0 && !style_match(style, force->angle_style))
|
|
error->warning(FLERR,
|
|
"Angle style in data file differs from currently defined angle style");
|
|
anglecoeffs(0);
|
|
} else
|
|
skip_lines(nangletypes);
|
|
} else if (strcmp(keyword, "Dihedral Coeffs") == 0) {
|
|
if (atom->avec->dihedrals_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: Dihedral Coeffs");
|
|
if (force->dihedral == nullptr)
|
|
error->all(FLERR, "Must define dihedral_style before Dihedral Coeffs");
|
|
if (firstpass) {
|
|
if (me == 0 && !style_match(style, force->dihedral_style))
|
|
error->warning(FLERR,
|
|
"Dihedral style in data file differs "
|
|
"from currently defined dihedral style");
|
|
dihedralcoeffs(0);
|
|
} else
|
|
skip_lines(ndihedraltypes);
|
|
} else if (strcmp(keyword, "Improper Coeffs") == 0) {
|
|
if (atom->avec->impropers_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: Improper Coeffs");
|
|
if (force->improper == nullptr)
|
|
error->all(FLERR, "Must define improper_style before Improper Coeffs");
|
|
if (firstpass) {
|
|
if (me == 0 && !style_match(style, force->improper_style))
|
|
error->warning(FLERR,
|
|
"Improper style in data file differs "
|
|
"from currently defined improper style");
|
|
impropercoeffs(0);
|
|
} else
|
|
skip_lines(nimpropertypes);
|
|
|
|
} else if (strcmp(keyword, "BondBond Coeffs") == 0) {
|
|
if (atom->avec->angles_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: BondBond Coeffs");
|
|
if (force->angle == nullptr)
|
|
error->all(FLERR, "Must define angle_style before BondBond Coeffs");
|
|
if (firstpass)
|
|
anglecoeffs(1);
|
|
else
|
|
skip_lines(nangletypes);
|
|
|
|
} else if (strcmp(keyword, "BondAngle Coeffs") == 0) {
|
|
if (atom->avec->angles_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: BondAngle Coeffs");
|
|
if (force->angle == nullptr)
|
|
error->all(FLERR, "Must define angle_style before BondAngle Coeffs");
|
|
if (firstpass)
|
|
anglecoeffs(2);
|
|
else
|
|
skip_lines(nangletypes);
|
|
} else if (strcmp(keyword, "UreyBradley Coeffs") == 0) {
|
|
if (atom->avec->angles_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: UreyBradley Coeffs");
|
|
if (force->angle == nullptr)
|
|
error->all(FLERR, "Must define angle_style before UreyBradley Coeffs");
|
|
if (firstpass)
|
|
anglecoeffs(3);
|
|
else
|
|
skip_lines(nangletypes);
|
|
|
|
} else if (strcmp(keyword, "MiddleBondTorsion Coeffs") == 0) {
|
|
if (atom->avec->dihedrals_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: MiddleBondTorsion Coeffs");
|
|
if (force->dihedral == nullptr)
|
|
error->all(FLERR, "Must define dihedral_style before MiddleBondTorsion Coeffs");
|
|
if (firstpass)
|
|
dihedralcoeffs(1);
|
|
else
|
|
skip_lines(ndihedraltypes);
|
|
|
|
} else if (strcmp(keyword, "EndBondTorsion Coeffs") == 0) {
|
|
if (atom->avec->dihedrals_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: EndBondTorsion Coeffs");
|
|
if (force->dihedral == nullptr)
|
|
error->all(FLERR, "Must define dihedral_style before EndBondTorsion Coeffs");
|
|
if (firstpass)
|
|
dihedralcoeffs(2);
|
|
else
|
|
skip_lines(ndihedraltypes);
|
|
|
|
} else if (strcmp(keyword, "AngleTorsion Coeffs") == 0) {
|
|
if (atom->avec->dihedrals_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: AngleTorsion Coeffs");
|
|
if (force->dihedral == nullptr)
|
|
error->all(FLERR, "Must define dihedral_style before AngleTorsion Coeffs");
|
|
if (firstpass)
|
|
dihedralcoeffs(3);
|
|
else
|
|
skip_lines(ndihedraltypes);
|
|
|
|
} else if (strcmp(keyword, "AngleAngleTorsion Coeffs") == 0) {
|
|
if (atom->avec->dihedrals_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: AngleAngleTorsion Coeffs");
|
|
if (force->dihedral == nullptr)
|
|
error->all(FLERR, "Must define dihedral_style before AngleAngleTorsion Coeffs");
|
|
if (firstpass)
|
|
dihedralcoeffs(4);
|
|
else
|
|
skip_lines(ndihedraltypes);
|
|
|
|
} else if (strcmp(keyword, "BondBond13 Coeffs") == 0) {
|
|
if (atom->avec->dihedrals_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: BondBond13 Coeffs");
|
|
if (force->dihedral == nullptr)
|
|
error->all(FLERR, "Must define dihedral_style before BondBond13 Coeffs");
|
|
if (firstpass)
|
|
dihedralcoeffs(5);
|
|
else
|
|
skip_lines(ndihedraltypes);
|
|
|
|
} else if (strcmp(keyword, "AngleAngle Coeffs") == 0) {
|
|
if (atom->avec->impropers_allow == 0)
|
|
error->all(FLERR, "Invalid data file section: AngleAngle Coeffs");
|
|
if (force->improper == nullptr)
|
|
error->all(FLERR, "Must define improper_style before AngleAngle Coeffs");
|
|
if (firstpass)
|
|
impropercoeffs(1);
|
|
else
|
|
skip_lines(nimpropertypes);
|
|
|
|
} else if (strcmp(keyword, "Atom Type Labels") == 0) {
|
|
if (firstpass) {
|
|
if (atomflag == 1) error->all(FLERR, "Must read Atom Type Labels before Atoms");
|
|
tlabelflag = 1;
|
|
typelabels(Atom::ATOM);
|
|
} else
|
|
skip_lines(ntypes);
|
|
|
|
} else if (strcmp(keyword, "Bond Type Labels") == 0) {
|
|
if (nbondtypes) {
|
|
if (firstpass) {
|
|
if (bondflag == 1) error->all(FLERR, "Must read Bond Type Labels before Bonds");
|
|
blabelflag = 1;
|
|
typelabels(Atom::BOND);
|
|
} else
|
|
skip_lines(nbondtypes);
|
|
}
|
|
|
|
} else if (strcmp(keyword, "Angle Type Labels") == 0) {
|
|
if (nangletypes) {
|
|
if (firstpass) {
|
|
if (angleflag == 1) error->all(FLERR, "Must read Angle Type Labels before Angles");
|
|
alabelflag = 1;
|
|
typelabels(Atom::ANGLE);
|
|
} else
|
|
skip_lines(nangletypes);
|
|
}
|
|
|
|
} else if (strcmp(keyword, "Dihedral Type Labels") == 0) {
|
|
if (ndihedraltypes) {
|
|
if (firstpass) {
|
|
if (dihedralflag == 1)
|
|
error->all(FLERR, "Must read Dihedral Type Labels before Dihedrals");
|
|
dlabelflag = 1;
|
|
typelabels(Atom::DIHEDRAL);
|
|
} else
|
|
skip_lines(ndihedraltypes);
|
|
}
|
|
|
|
} else if (strcmp(keyword, "Improper Type Labels") == 0) {
|
|
if (nimpropertypes) {
|
|
if (firstpass) {
|
|
if (improperflag == 1)
|
|
error->all(FLERR, "Must read Improper Type Labels before Impropers");
|
|
ilabelflag = 1;
|
|
typelabels(Atom::IMPROPER);
|
|
} else
|
|
skip_lines(nimpropertypes);
|
|
}
|
|
|
|
// if specified fix matches, it processes section
|
|
|
|
} else if (nfix) {
|
|
int i;
|
|
for (i = 0; i < nfix; i++)
|
|
if (strcmp(keyword, fix_section[i]) == 0) {
|
|
if (firstpass)
|
|
fix(fix_index[i], keyword);
|
|
else
|
|
skip_lines(fix_index[i]->read_data_skip_lines(keyword));
|
|
break;
|
|
}
|
|
if (i == nfix)
|
|
error->all(FLERR, "Unknown identifier in data file: {}{}", keyword, utils::errorurl(1));
|
|
|
|
} else
|
|
error->all(FLERR, "Unknown identifier in data file: {}{}", keyword, utils::errorurl(1));
|
|
|
|
parse_keyword(0);
|
|
}
|
|
|
|
// error if natoms > 0 yet no atoms were read
|
|
|
|
if (natoms > 0 && atomflag == 0) error->all(FLERR, "No valid atoms found in data file");
|
|
|
|
// close file
|
|
|
|
if (me == 0) {
|
|
if (compressed)
|
|
platform::pclose(fp);
|
|
else
|
|
fclose(fp);
|
|
fp = nullptr;
|
|
}
|
|
|
|
// done if this was 2nd pass
|
|
|
|
if (!firstpass) break;
|
|
|
|
// at end of 1st pass, error check for required sections
|
|
// customize for new sections
|
|
|
|
if (nbonds && !bondflag)
|
|
error->one(FLERR, "Bonds section for {} bonds not found", nbonds);
|
|
if (nangles && !angleflag)
|
|
error->one(FLERR, "Angles section for {} angles not found", nangles);
|
|
if (ndihedrals && !dihedralflag)
|
|
error->one(FLERR, "Dihedrals section for {} dihedrals not found", ndihedrals);
|
|
if (nimpropers && !improperflag)
|
|
error->one(FLERR, "Impropers section for {} impropers not found", nimpropers);
|
|
|
|
if (nellipsoids && !ellipsoidflag)
|
|
error->one(FLERR, "Ellipsoids section for {} ellipsoids not found", nellipsoids);
|
|
if (nlines && !lineflag)
|
|
error->one(FLERR, "Lines section for {} lines not found", nlines);
|
|
if (ntris && !triflag)
|
|
error->one(FLERR, "Triangles section for {} triangles not found", ntris);
|
|
if (nbodies && !bodyflag)
|
|
error->one(FLERR, "Bodies section for {} bodies not found", nbodies);
|
|
|
|
// break out of loop if no molecular topology in file
|
|
// else make 2nd pass
|
|
|
|
if (!topoflag) break;
|
|
firstpass = 0;
|
|
|
|
// reallocate bond,angle,diehdral,improper arrays via grow()
|
|
// will use new bond,angle,dihedral,improper per-atom values from 1st pass
|
|
// will also observe extra settings even if bond/etc topology not in file
|
|
// leaves other atom arrays unchanged, since already nmax in length
|
|
|
|
if (addflag == NONE) atom->deallocate_topology();
|
|
atom->avec->grow(atom->nmax);
|
|
}
|
|
|
|
// init per-atom fix/compute/variable values for created atoms
|
|
|
|
atom->data_fix_compute_variable(nlocal_previous, atom->nlocal);
|
|
|
|
// assign atoms added by this data file to specified group
|
|
|
|
if (groupbit) {
|
|
int *mask = atom->mask;
|
|
int nlocal = atom->nlocal;
|
|
for (int i = nlocal_previous; i < nlocal; i++) mask[i] |= groupbit;
|
|
}
|
|
|
|
// create special bond lists for molecular systems
|
|
|
|
if (atom->molecular == Atom::MOLECULAR) {
|
|
Special special(lmp);
|
|
special.build();
|
|
}
|
|
|
|
// for atom style template just count total bonds, etc. from template(s)
|
|
|
|
if (atom->molecular == Atom::TEMPLATE) {
|
|
Molecule **onemols = atom->avec->onemols;
|
|
int *molindex = atom->molindex;
|
|
int *molatom = atom->molatom;
|
|
int nlocal = atom->nlocal;
|
|
|
|
int imol, iatom;
|
|
bigint nbonds, nangles, ndihedrals, nimpropers;
|
|
nbonds = nangles = ndihedrals = nimpropers = 0;
|
|
|
|
for (int i = 0; i < nlocal; i++) {
|
|
imol = molindex[i];
|
|
iatom = molatom[i];
|
|
if (imol >= 0) {
|
|
nbonds += onemols[imol]->num_bond[iatom];
|
|
nangles += onemols[imol]->num_angle[iatom];
|
|
ndihedrals += onemols[imol]->num_dihedral[iatom];
|
|
nimpropers += onemols[imol]->num_improper[iatom];
|
|
}
|
|
}
|
|
|
|
MPI_Allreduce(&nbonds, &atom->nbonds, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
MPI_Allreduce(&nangles, &atom->nangles, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
MPI_Allreduce(&ndihedrals, &atom->ndihedrals, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
MPI_Allreduce(&nimpropers, &atom->nimpropers, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
|
|
if (me == 0) {
|
|
std::string mesg;
|
|
|
|
if (atom->nbonds) mesg += fmt::format(" {} template bonds\n", atom->nbonds);
|
|
if (atom->nangles) mesg += fmt::format(" {} template angles\n", atom->nangles);
|
|
if (atom->ndihedrals) mesg += fmt::format(" {} template dihedrals\n", atom->ndihedrals);
|
|
if (atom->nimpropers) mesg += fmt::format(" {} template impropers\n", atom->nimpropers);
|
|
|
|
utils::logmesg(lmp, mesg);
|
|
}
|
|
}
|
|
|
|
// for atom style template systems
|
|
// insure nbondtypes,etc are still consistent with template molecules,
|
|
// in case data file re-defined them
|
|
|
|
if (atom->molecular == Atom::TEMPLATE) {
|
|
int nset = MAX(1, atom->avec->onemols[0]->nset);
|
|
for (int i = 0; i < nset; ++i) atom->avec->onemols[i]->check_attributes();
|
|
}
|
|
|
|
// if adding atoms, migrate atoms to new processors
|
|
// use irregular() b/c box size could have changed dramaticaly
|
|
// resulting in procs now owning very different subboxes
|
|
// with their previously owned atoms now far outside the subbox
|
|
|
|
if (addflag != NONE) {
|
|
if (domain->triclinic) domain->x2lamda(atom->nlocal);
|
|
auto irregular = new Irregular(lmp);
|
|
irregular->migrate_atoms(1);
|
|
delete irregular;
|
|
if (domain->triclinic) domain->lamda2x(atom->nlocal);
|
|
}
|
|
|
|
// shrink-wrap the box if necessary and move atoms to new procs
|
|
// if atoms are lost is b/c data file box was far from shrink-wrapped
|
|
// do not use irregular() comm, which would not lose atoms,
|
|
// b/c then user could specify data file box as far too big and empty
|
|
// do comm->init() but not comm->setup() b/c pair/neigh cutoffs not yet set
|
|
// need call to map_set() b/c comm->exchange clears atom map
|
|
|
|
if (domain->nonperiodic == 2) {
|
|
if (domain->triclinic) domain->x2lamda(atom->nlocal);
|
|
domain->reset_box();
|
|
auto irregular = new Irregular(lmp);
|
|
irregular->migrate_atoms(1);
|
|
delete irregular;
|
|
if (domain->triclinic) domain->lamda2x(atom->nlocal);
|
|
|
|
bigint natoms;
|
|
bigint nblocal = atom->nlocal;
|
|
MPI_Allreduce(&nblocal, &natoms, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
if (natoms != atom->natoms)
|
|
error->all(FLERR, "Read_data shrink wrap did not assign all atoms correctly");
|
|
}
|
|
|
|
// restore old styles, when reading with nocoeff flag given
|
|
|
|
if (coeffflag == 0) {
|
|
delete force->pair;
|
|
delete[] force->pair_style;
|
|
force->pair = saved_pair;
|
|
force->pair_style = saved_pair_style;
|
|
|
|
delete force->bond;
|
|
delete[] force->bond_style;
|
|
force->bond = saved_bond;
|
|
force->bond_style = saved_bond_style;
|
|
|
|
delete force->angle;
|
|
delete[] force->angle_style;
|
|
force->angle = saved_angle;
|
|
force->angle_style = saved_angle_style;
|
|
|
|
delete force->dihedral;
|
|
delete[] force->dihedral_style;
|
|
force->dihedral = saved_dihedral;
|
|
force->dihedral_style = saved_dihedral_style;
|
|
|
|
delete force->improper;
|
|
delete[] force->improper_style;
|
|
force->improper = saved_improper;
|
|
force->improper_style = saved_improper_style;
|
|
|
|
force->kspace = saved_kspace;
|
|
force->kspace_style = saved_kspace_style;
|
|
}
|
|
|
|
// total time
|
|
|
|
MPI_Barrier(world);
|
|
|
|
if (comm->me == 0)
|
|
utils::logmesg(lmp, " read_data CPU = {:.3f} seconds\n", platform::walltime() - time1);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read free-format header of data file
|
|
1st line and blank lines are skipped
|
|
non-blank lines are checked for header keywords and leading value is read
|
|
header ends with EOF or non-blank line containing no header keyword
|
|
if EOF, line is set to blank line
|
|
else line has first keyword line for rest of file
|
|
some logic differs if adding atoms
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::header(int firstpass)
|
|
{
|
|
int n;
|
|
char *ptr;
|
|
|
|
// initialize type counts by the "extra" numbers so they get counted
|
|
// in case the corresponding "types" line is missing and thus the extra
|
|
// value will not be processed.
|
|
if (addflag == NONE) {
|
|
atom->ntypes = extra_atom_types;
|
|
atom->nbondtypes = extra_bond_types;
|
|
atom->nangletypes = extra_angle_types;
|
|
atom->ndihedraltypes = extra_dihedral_types;
|
|
atom->nimpropertypes = extra_improper_types;
|
|
}
|
|
|
|
// skip 1st line of file
|
|
|
|
if (me == 0) {
|
|
char *eof = utils::fgets_trunc(line, MAXLINE, fp);
|
|
if (eof == nullptr) error->one(FLERR, "Unexpected end of data file");
|
|
}
|
|
|
|
while (true) {
|
|
|
|
// read a line and bcast length
|
|
|
|
if (me == 0) {
|
|
if (utils::fgets_trunc(line, MAXLINE, fp) == nullptr)
|
|
n = 0;
|
|
else
|
|
n = strlen(line) + 1;
|
|
}
|
|
MPI_Bcast(&n, 1, MPI_INT, 0, world);
|
|
|
|
// if n = 0 then end-of-file so return with blank line
|
|
|
|
if (n == 0) {
|
|
line[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
MPI_Bcast(line, n, MPI_CHAR, 0, world);
|
|
|
|
// trim anything from '#' onward
|
|
// if line is blank, continue
|
|
|
|
if ((ptr = strchr(line, '#'))) *ptr = '\0';
|
|
if (strspn(line, " \t\n\r") == strlen(line)) continue;
|
|
|
|
// allow special fixes first chance to match and process the line
|
|
// if fix matches, continue to next header line
|
|
|
|
if (nfix) {
|
|
for (n = 0; n < nfix; n++) {
|
|
if (!fix_header[n]) continue;
|
|
if (strstr(line, fix_header[n])) {
|
|
fix_index[n]->read_data_header(line);
|
|
break;
|
|
}
|
|
}
|
|
if (n < nfix) continue;
|
|
}
|
|
|
|
// search line for header keyword and set corresponding variable
|
|
// customize for new header lines
|
|
|
|
int extra_flag_value = 0;
|
|
auto words = utils::split_words(line);
|
|
|
|
if (utils::strmatch(line, "^\\s*\\d+\\s+atoms\\s")) {
|
|
natoms = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->natoms = natoms;
|
|
else if (firstpass)
|
|
atom->natoms += natoms;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+ellipsoids\\s")) {
|
|
if (!avec_ellipsoid) error->all(FLERR, "No ellipsoids allowed with this atom style");
|
|
nellipsoids = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->nellipsoids = nellipsoids;
|
|
else if (firstpass)
|
|
atom->nellipsoids += nellipsoids;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+lines\\s")) {
|
|
if (!avec_line) error->all(FLERR, "No lines allowed with this atom style");
|
|
nlines = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->nlines = nlines;
|
|
else if (firstpass)
|
|
atom->nlines += nlines;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+triangles\\s")) {
|
|
if (!avec_tri) error->all(FLERR, "No triangles allowed with this atom style");
|
|
ntris = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->ntris = ntris;
|
|
else if (firstpass)
|
|
atom->ntris += ntris;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+bodies\\s")) {
|
|
if (!avec_body) error->all(FLERR, "No bodies allowed with this atom style");
|
|
nbodies = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->nbodies = nbodies;
|
|
else if (firstpass)
|
|
atom->nbodies += nbodies;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+bonds\\s")) {
|
|
nbonds = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->nbonds = nbonds;
|
|
else if (firstpass)
|
|
atom->nbonds += nbonds;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+angles\\s")) {
|
|
nangles = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->nangles = nangles;
|
|
else if (firstpass)
|
|
atom->nangles += nangles;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+dihedrals\\s")) {
|
|
ndihedrals = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->ndihedrals = ndihedrals;
|
|
else if (firstpass)
|
|
atom->ndihedrals += ndihedrals;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+impropers\\s")) {
|
|
nimpropers = utils::bnumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE)
|
|
atom->nimpropers = nimpropers;
|
|
else if (firstpass)
|
|
atom->nimpropers += nimpropers;
|
|
|
|
// Atom class type settings are only set by first data file
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+atom\\s+types\\s")) {
|
|
ntypes = utils::inumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE) atom->ntypes = ntypes + extra_atom_types;
|
|
|
|
} else if (utils::strmatch(line, "\\s*\\d+\\s+bond\\s+types\\s")) {
|
|
nbondtypes = utils::inumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE) atom->nbondtypes = nbondtypes + extra_bond_types;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+angle\\s+types\\s")) {
|
|
nangletypes = utils::inumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE) atom->nangletypes = nangletypes + extra_angle_types;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+dihedral\\s+types\\s")) {
|
|
ndihedraltypes = utils::inumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE) atom->ndihedraltypes = ndihedraltypes + extra_dihedral_types;
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\d+\\s+improper\\s+types\\s")) {
|
|
nimpropertypes = utils::inumeric(FLERR, words[0], false, lmp);
|
|
if (addflag == NONE) atom->nimpropertypes = nimpropertypes + extra_improper_types;
|
|
|
|
// these settings only used by first data file
|
|
// also, these are obsolescent. we parse them to maintain backward
|
|
// compatibility, but the recommended way is to set them via keywords
|
|
// in the LAMMPS input file. In case these flags are set in both,
|
|
// the input and the data file, we use the larger of the two.
|
|
|
|
} else if (strstr(line, "extra bond per atom")) {
|
|
if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp);
|
|
atom->extra_bond_per_atom = MAX(atom->extra_bond_per_atom, extra_flag_value);
|
|
} else if (strstr(line, "extra angle per atom")) {
|
|
if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp);
|
|
atom->extra_angle_per_atom = MAX(atom->extra_angle_per_atom, extra_flag_value);
|
|
} else if (strstr(line, "extra dihedral per atom")) {
|
|
if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp);
|
|
atom->extra_dihedral_per_atom = MAX(atom->extra_dihedral_per_atom, extra_flag_value);
|
|
} else if (strstr(line, "extra improper per atom")) {
|
|
if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp);
|
|
atom->extra_improper_per_atom = MAX(atom->extra_improper_per_atom, extra_flag_value);
|
|
} else if (strstr(line, "extra special per atom")) {
|
|
if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp);
|
|
force->special_extra = MAX(force->special_extra, extra_flag_value);
|
|
|
|
// local copy of box info
|
|
// so can treat differently for first vs subsequent data files
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+xlo\\s+xhi\\s")) {
|
|
boxlo[0] = utils::numeric(FLERR, words[0], false, lmp);
|
|
boxhi[0] = utils::numeric(FLERR, words[1], false, lmp);
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+ylo\\s+yhi\\s")) {
|
|
boxlo[1] = utils::numeric(FLERR, words[0], false, lmp);
|
|
boxhi[1] = utils::numeric(FLERR, words[1], false, lmp);
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+zlo\\s+zhi\\s")) {
|
|
boxlo[2] = utils::numeric(FLERR, words[0], false, lmp);
|
|
boxhi[2] = utils::numeric(FLERR, words[1], false, lmp);
|
|
|
|
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+\\f+\\s+xy\\s+xz\\s+yz\\s")) {
|
|
triclinic = 1;
|
|
xy = utils::numeric(FLERR, words[0], false, lmp);
|
|
xz = utils::numeric(FLERR, words[1], false, lmp);
|
|
yz = utils::numeric(FLERR, words[2], false, lmp);
|
|
|
|
} else
|
|
break;
|
|
}
|
|
|
|
// error check on total system size
|
|
|
|
if (atom->natoms < 0 || atom->natoms >= MAXBIGINT || atom->nellipsoids < 0 ||
|
|
atom->nellipsoids >= MAXBIGINT || atom->nlines < 0 || atom->nlines >= MAXBIGINT ||
|
|
atom->ntris < 0 || atom->ntris >= MAXBIGINT || atom->nbodies < 0 ||
|
|
atom->nbodies >= MAXBIGINT || atom->nbonds < 0 || atom->nbonds >= MAXBIGINT ||
|
|
atom->nangles < 0 || atom->nangles >= MAXBIGINT || atom->ndihedrals < 0 ||
|
|
atom->ndihedrals >= MAXBIGINT || atom->nimpropers < 0 || atom->nimpropers >= MAXBIGINT)
|
|
error->all(FLERR, "System in data file is too big");
|
|
|
|
// check that exiting string is a valid section keyword
|
|
|
|
parse_keyword(1);
|
|
if (!is_data_section(keyword)) error->all(FLERR, "Unknown identifier in data file: {}", keyword);
|
|
|
|
// error checks on header values
|
|
// must be consistent with atom style and other header values
|
|
|
|
if ((atom->nbonds || atom->nbondtypes) && atom->avec->bonds_allow == 0)
|
|
error->all(FLERR, "No bonds allowed with this atom style");
|
|
if ((atom->nangles || atom->nangletypes) && atom->avec->angles_allow == 0)
|
|
error->all(FLERR, "No angles allowed with this atom style");
|
|
if ((atom->ndihedrals || atom->ndihedraltypes) && atom->avec->dihedrals_allow == 0)
|
|
error->all(FLERR, "No dihedrals allowed with this atom style");
|
|
if ((atom->nimpropers || atom->nimpropertypes) && atom->avec->impropers_allow == 0)
|
|
error->all(FLERR, "No impropers allowed with this atom style");
|
|
|
|
if (atom->nbonds > 0 && atom->nbondtypes <= 0)
|
|
error->all(FLERR, "Bonds defined but no bond types");
|
|
if (atom->nangles > 0 && atom->nangletypes <= 0)
|
|
error->all(FLERR, "Angles defined but no angle types");
|
|
if (atom->ndihedrals > 0 && atom->ndihedraltypes <= 0)
|
|
error->all(FLERR, "Dihedrals defined but no dihedral types");
|
|
if (atom->nimpropers > 0 && atom->nimpropertypes <= 0)
|
|
error->all(FLERR, "Impropers defined but no improper types");
|
|
|
|
if (atom->molecular == Atom::TEMPLATE) {
|
|
if (atom->nbonds || atom->nangles || atom->ndihedrals || atom->nimpropers)
|
|
error->all(FLERR, "No molecule topology allowed with atom style template");
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read all atoms
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::atoms()
|
|
{
|
|
int nchunk, eof;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " reading atoms ...\n");
|
|
|
|
bigint nread = 0;
|
|
|
|
while (nread < natoms) {
|
|
nchunk = MIN(natoms - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
if (tlabelflag && !lmap->is_complete(Atom::ATOM))
|
|
error->all(FLERR, "Label map is incomplete: all types must be assigned a unique type label");
|
|
atom->data_atoms(nchunk, buffer, id_offset, mol_offset, toffset, shiftflag, shift, tlabelflag,
|
|
lmap->lmap2lmap.atom);
|
|
nread += nchunk;
|
|
}
|
|
|
|
// warn if we have read data with non-zero image flags for non-periodic boundaries.
|
|
// we may want to turn this into an error at some point, since this essentially
|
|
// creates invalid position information that works by accident most of the time.
|
|
|
|
if (comm->me == 0) {
|
|
if (atom->reset_image_flag[0])
|
|
error->warning(FLERR,
|
|
"Non-zero imageflag(s) in x direction for "
|
|
"non-periodic boundary reset to zero");
|
|
if (atom->reset_image_flag[1])
|
|
error->warning(FLERR,
|
|
"Non-zero imageflag(s) in y direction for "
|
|
"non-periodic boundary reset to zero");
|
|
if (atom->reset_image_flag[2])
|
|
error->warning(FLERR,
|
|
"Non-zero imageflag(s) in z direction for "
|
|
"non-periodic boundary reset to zero");
|
|
}
|
|
|
|
// check that all atoms were assigned correctly
|
|
|
|
bigint n = atom->nlocal;
|
|
bigint sum;
|
|
MPI_Allreduce(&n, &sum, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
bigint nassign = sum - (atom->natoms - natoms);
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} atoms\n", nassign);
|
|
|
|
if (sum != atom->natoms) error->all(FLERR, "Did not assign all atoms correctly");
|
|
|
|
// check that atom IDs are valid
|
|
|
|
atom->tag_check();
|
|
|
|
// check that bonus data has been reserved as needed
|
|
|
|
atom->bonus_check();
|
|
|
|
// create global mapping of atoms
|
|
|
|
if (atom->map_style != Atom::MAP_NONE) {
|
|
atom->map_init();
|
|
atom->map_set();
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read all velocities
|
|
to find atoms, must build atom map if not a molecular system
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::velocities()
|
|
{
|
|
int nchunk, eof;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " reading velocities ...\n");
|
|
|
|
int mapflag = 0;
|
|
if (atom->map_style == Atom::MAP_NONE) {
|
|
mapflag = 1;
|
|
atom->map_init();
|
|
atom->map_set();
|
|
}
|
|
|
|
bigint nread = 0;
|
|
|
|
while (nread < natoms) {
|
|
nchunk = MIN(natoms - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
atom->data_vels(nchunk, buffer, id_offset);
|
|
nread += nchunk;
|
|
}
|
|
|
|
if (mapflag) {
|
|
atom->map_delete();
|
|
atom->map_style = Atom::MAP_NONE;
|
|
}
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} velocities\n", natoms);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
scan or read all bonds
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::bonds(int firstpass)
|
|
{
|
|
int nchunk, eof;
|
|
|
|
if (me == 0) {
|
|
if (firstpass)
|
|
utils::logmesg(lmp, " scanning bonds ...\n");
|
|
else
|
|
utils::logmesg(lmp, " reading bonds ...\n");
|
|
}
|
|
|
|
// allocate count if firstpass
|
|
|
|
int nlocal = atom->nlocal;
|
|
int *count = nullptr;
|
|
if (firstpass) {
|
|
memory->create(count, nlocal, "read_data:count");
|
|
if (count) memset(count, 0, nlocal * sizeof(int));
|
|
}
|
|
|
|
// read and process bonds
|
|
|
|
bigint nread = 0;
|
|
|
|
while (nread < nbonds) {
|
|
nchunk = MIN(nbonds - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
if (blabelflag && !lmap->is_complete(Atom::BOND))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
atom->data_bonds(nchunk, buffer, count, id_offset, boffset, blabelflag, lmap->lmap2lmap.bond);
|
|
nread += nchunk;
|
|
}
|
|
|
|
// if firstpass: tally max bond/atom and return
|
|
// if addflag = NONE, store max bond/atom with extra
|
|
// else just check actual max does not exceed existing max
|
|
|
|
if (firstpass) {
|
|
int max = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) max = MAX(max, count[i]);
|
|
int maxall;
|
|
MPI_Allreduce(&max, &maxall, 1, MPI_INT, MPI_MAX, world);
|
|
if (addflag == NONE) maxall += atom->extra_bond_per_atom;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} = max bonds/atom\n", maxall);
|
|
|
|
if (addflag != NONE) {
|
|
if (maxall > atom->bond_per_atom)
|
|
error->all(FLERR,
|
|
"Subsequent read data induced "
|
|
"too many bonds per atom");
|
|
} else
|
|
atom->bond_per_atom = maxall;
|
|
|
|
memory->destroy(count);
|
|
return;
|
|
}
|
|
|
|
// if 2nd pass: check that bonds were assigned correctly
|
|
|
|
bigint n = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_bond[i];
|
|
bigint sum;
|
|
MPI_Allreduce(&n, &sum, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
int factor = 1;
|
|
if (!force->newton_bond) factor = 2;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} bonds\n", sum / factor);
|
|
|
|
if (sum != factor * nbonds) error->all(FLERR, "Bonds assigned incorrectly");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
scan or read all angles
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::angles(int firstpass)
|
|
{
|
|
int nchunk, eof;
|
|
|
|
if (me == 0) {
|
|
if (firstpass)
|
|
utils::logmesg(lmp, " scanning angles ...\n");
|
|
else
|
|
utils::logmesg(lmp, " reading angles ...\n");
|
|
}
|
|
|
|
// allocate count if firstpass
|
|
|
|
int nlocal = atom->nlocal;
|
|
int *count = nullptr;
|
|
if (firstpass) {
|
|
memory->create(count, nlocal, "read_data:count");
|
|
if (count) memset(count, 0, nlocal * sizeof(int));
|
|
}
|
|
|
|
// read and process angles
|
|
|
|
bigint nread = 0;
|
|
|
|
while (nread < nangles) {
|
|
nchunk = MIN(nangles - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
if (alabelflag && !lmap->is_complete(Atom::ANGLE))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
atom->data_angles(nchunk, buffer, count, id_offset, aoffset, alabelflag, lmap->lmap2lmap.angle);
|
|
nread += nchunk;
|
|
}
|
|
|
|
// if firstpass: tally max angle/atom and return
|
|
// if addflag = NONE, store max angle/atom with extra
|
|
// else just check actual max does not exceed existing max
|
|
|
|
if (firstpass) {
|
|
int max = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) max = MAX(max, count[i]);
|
|
int maxall;
|
|
MPI_Allreduce(&max, &maxall, 1, MPI_INT, MPI_MAX, world);
|
|
if (addflag == NONE) maxall += atom->extra_angle_per_atom;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} = max angles/atom\n", maxall);
|
|
|
|
if (addflag != NONE) {
|
|
if (maxall > atom->angle_per_atom)
|
|
error->all(FLERR,
|
|
"Subsequent read data induced "
|
|
"too many angles per atom");
|
|
} else
|
|
atom->angle_per_atom = maxall;
|
|
|
|
memory->destroy(count);
|
|
return;
|
|
}
|
|
|
|
// if 2nd pass: check that angles were assigned correctly
|
|
|
|
bigint n = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_angle[i];
|
|
bigint sum;
|
|
MPI_Allreduce(&n, &sum, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
int factor = 1;
|
|
if (!force->newton_bond) factor = 3;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} angles\n", sum / factor);
|
|
|
|
if (sum != factor * nangles) error->all(FLERR, "Angles assigned incorrectly");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
scan or read all dihedrals
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::dihedrals(int firstpass)
|
|
{
|
|
int nchunk, eof;
|
|
|
|
if (me == 0) {
|
|
if (firstpass)
|
|
utils::logmesg(lmp, " scanning dihedrals ...\n");
|
|
else
|
|
utils::logmesg(lmp, " reading dihedrals ...\n");
|
|
}
|
|
|
|
// allocate count if firstpass
|
|
|
|
int nlocal = atom->nlocal;
|
|
int *count = nullptr;
|
|
if (firstpass) {
|
|
memory->create(count, nlocal, "read_data:count");
|
|
if (count) memset(count, 0, nlocal * sizeof(int));
|
|
}
|
|
|
|
// read and process dihedrals
|
|
|
|
bigint nread = 0;
|
|
|
|
while (nread < ndihedrals) {
|
|
nchunk = MIN(ndihedrals - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
if (dlabelflag && !lmap->is_complete(Atom::DIHEDRAL))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
atom->data_dihedrals(nchunk, buffer, count, id_offset, doffset, dlabelflag,
|
|
lmap->lmap2lmap.dihedral);
|
|
nread += nchunk;
|
|
}
|
|
|
|
// if firstpass: tally max dihedral/atom and return
|
|
// if addflag = NONE, store max dihedral/atom with extra
|
|
// else just check actual max does not exceed existing max
|
|
|
|
if (firstpass) {
|
|
int max = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) max = MAX(max, count[i]);
|
|
int maxall;
|
|
MPI_Allreduce(&max, &maxall, 1, MPI_INT, MPI_MAX, world);
|
|
if (addflag == NONE) maxall += atom->extra_dihedral_per_atom;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} = max dihedrals/atom\n", maxall);
|
|
|
|
if (addflag != NONE) {
|
|
if (maxall > atom->dihedral_per_atom)
|
|
error->all(FLERR,
|
|
"Subsequent read data induced "
|
|
"too many dihedrals per atom");
|
|
} else
|
|
atom->dihedral_per_atom = maxall;
|
|
|
|
memory->destroy(count);
|
|
return;
|
|
}
|
|
|
|
// if 2nd pass: check that dihedrals were assigned correctly
|
|
|
|
bigint n = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_dihedral[i];
|
|
bigint sum;
|
|
MPI_Allreduce(&n, &sum, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
int factor = 1;
|
|
if (!force->newton_bond) factor = 4;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} dihedrals\n", sum / factor);
|
|
|
|
if (sum != factor * ndihedrals) error->all(FLERR, "Dihedrals assigned incorrectly");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
scan or read all impropers
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::impropers(int firstpass)
|
|
{
|
|
int nchunk, eof;
|
|
|
|
if (me == 0) {
|
|
if (firstpass)
|
|
utils::logmesg(lmp, " scanning impropers ...\n");
|
|
else
|
|
utils::logmesg(lmp, " reading impropers ...\n");
|
|
}
|
|
|
|
// allocate count if firstpass
|
|
|
|
int nlocal = atom->nlocal;
|
|
int *count = nullptr;
|
|
if (firstpass) {
|
|
memory->create(count, nlocal, "read_data:count");
|
|
if (count) memset(count, 0, nlocal * sizeof(int));
|
|
}
|
|
|
|
// read and process impropers
|
|
|
|
bigint nread = 0;
|
|
|
|
while (nread < nimpropers) {
|
|
nchunk = MIN(nimpropers - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
if (ilabelflag && !lmap->is_complete(Atom::IMPROPER))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
atom->data_impropers(nchunk, buffer, count, id_offset, ioffset, ilabelflag,
|
|
lmap->lmap2lmap.improper);
|
|
nread += nchunk;
|
|
}
|
|
|
|
// if firstpass: tally max improper/atom and return
|
|
// if addflag = NONE, store max improper/atom
|
|
// else just check it does not exceed existing max
|
|
|
|
if (firstpass) {
|
|
int max = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) max = MAX(max, count[i]);
|
|
int maxall;
|
|
MPI_Allreduce(&max, &maxall, 1, MPI_INT, MPI_MAX, world);
|
|
if (addflag == NONE) maxall += atom->extra_improper_per_atom;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} = max impropers/atom\n", maxall);
|
|
|
|
if (addflag != NONE) {
|
|
if (maxall > atom->improper_per_atom)
|
|
error->all(FLERR, "Subsequent read data induced too many impropers per atom");
|
|
} else
|
|
atom->improper_per_atom = maxall;
|
|
|
|
memory->destroy(count);
|
|
return;
|
|
}
|
|
|
|
// if 2nd pass: check that impropers were assigned correctly
|
|
|
|
bigint n = 0;
|
|
for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_improper[i];
|
|
bigint sum;
|
|
MPI_Allreduce(&n, &sum, 1, MPI_LMP_BIGINT, MPI_SUM, world);
|
|
int factor = 1;
|
|
if (!force->newton_bond) factor = 4;
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} impropers\n", sum / factor);
|
|
|
|
if (sum != factor * nimpropers) error->all(FLERR, "Impropers assigned incorrectly");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read all bonus data
|
|
to find atoms, must build atom map if not a molecular system
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type)
|
|
{
|
|
int nchunk, eof;
|
|
|
|
int mapflag = 0;
|
|
if (atom->map_style == Atom::MAP_NONE) {
|
|
mapflag = 1;
|
|
atom->map_init();
|
|
atom->map_set();
|
|
}
|
|
|
|
bigint nread = 0;
|
|
bigint natoms = nbonus;
|
|
|
|
while (nread < natoms) {
|
|
nchunk = MIN(natoms - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
atom->data_bonus(nchunk, buffer, ptr, id_offset);
|
|
nread += nchunk;
|
|
}
|
|
|
|
if (mapflag) {
|
|
atom->map_delete();
|
|
atom->map_style = Atom::MAP_NONE;
|
|
}
|
|
|
|
if (me == 0) utils::logmesg(lmp, " {} {}\n", natoms, type);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read all body data
|
|
variable amount of info per body, described by ninteger and ndouble
|
|
to find atoms, must build atom map if not a molecular system
|
|
if not firstpass, just read past body data and only process body header
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::bodies(int firstpass, AtomVec *ptr)
|
|
{
|
|
int m, nchunk, nline, nmax, ninteger, ndouble, nword, ncount, onebody;
|
|
char *eof;
|
|
|
|
int mapflag = 0;
|
|
if (atom->map_style == Atom::MAP_NONE && firstpass) {
|
|
mapflag = 1;
|
|
atom->map_init();
|
|
atom->map_set();
|
|
}
|
|
|
|
// nmax = max # of bodies to read in this chunk
|
|
// nchunk = actual # read
|
|
|
|
bigint nread = 0;
|
|
bigint nblocks = nbodies;
|
|
|
|
while (nread < nblocks) {
|
|
if (nblocks - nread > CHUNK)
|
|
nmax = CHUNK;
|
|
else
|
|
nmax = nblocks - nread;
|
|
|
|
if (me == 0) {
|
|
nchunk = 0;
|
|
nline = 0;
|
|
m = 0;
|
|
|
|
while (nchunk < nmax && nline <= CHUNK - MAXBODY) {
|
|
eof = utils::fgets_trunc(&buffer[m], MAXLINE, fp);
|
|
const char *buf = &buffer[m];
|
|
if (eof == nullptr) error->one(FLERR, "Unexpected end of data file");
|
|
try {
|
|
auto values = ValueTokenizer(utils::trim_comment(buf));
|
|
tagint tagdata = values.next_tagint() + id_offset;
|
|
ninteger = values.next_int();
|
|
ndouble = values.next_double();
|
|
if (tagdata <= 0 || tagdata > atom->map_tag_max)
|
|
throw TokenizerException("Invalid atom ID in body header", utils::trim(buf));
|
|
if (ninteger < 0)
|
|
throw TokenizerException("Invalid number of integers", utils::trim(buf));
|
|
if (ndouble < 0) throw TokenizerException("Invalid number of doubles", utils::trim(buf));
|
|
if (values.has_next())
|
|
throw TokenizerException("Too many tokens in body header", utils::trim(buf));
|
|
} catch (TokenizerException &e) {
|
|
error->one(FLERR, std::string(e.what()) + " while reading Bodies section of data file");
|
|
}
|
|
m += strlen(buf);
|
|
|
|
// read lines one at a time into buffer and count words
|
|
// count to ninteger and ndouble until have enough lines
|
|
|
|
onebody = 0;
|
|
|
|
nword = 0;
|
|
while (nword < ninteger) {
|
|
eof = utils::fgets_trunc(&buffer[m], MAXLINE, fp);
|
|
if (eof == nullptr) error->one(FLERR, "Unexpected end of data file");
|
|
ncount = utils::trim_and_count_words(&buffer[m]);
|
|
if (ncount == 0) error->one(FLERR, "Too few values in body lines in data file");
|
|
nword += ncount;
|
|
m += strlen(&buffer[m]);
|
|
onebody++;
|
|
}
|
|
if (nword > ninteger) error->one(FLERR, "Too many values in body lines in data file");
|
|
|
|
nword = 0;
|
|
while (nword < ndouble) {
|
|
eof = utils::fgets_trunc(&buffer[m], MAXLINE, fp);
|
|
if (eof == nullptr) error->one(FLERR, "Unexpected end of data file");
|
|
ncount = utils::trim_and_count_words(&buffer[m]);
|
|
if (ncount == 0) error->one(FLERR, "Too few values in body lines in data file");
|
|
nword += ncount;
|
|
m += strlen(&buffer[m]);
|
|
onebody++;
|
|
}
|
|
if (nword > ndouble) error->one(FLERR, "Too many values in body lines in data file");
|
|
|
|
if (onebody + 1 > MAXBODY)
|
|
error->one(FLERR, "Too many lines in one body in data file - boost MAXBODY");
|
|
|
|
nchunk++;
|
|
nline += onebody + 1;
|
|
}
|
|
|
|
if (buffer[m - 1] != '\n') strcpy(&buffer[m++], "\n");
|
|
m++;
|
|
}
|
|
|
|
MPI_Bcast(&nchunk, 1, MPI_INT, 0, world);
|
|
MPI_Bcast(&m, 1, MPI_INT, 0, world);
|
|
MPI_Bcast(buffer, m, MPI_CHAR, 0, world);
|
|
|
|
if (firstpass) atom->data_bodies(nchunk, buffer, ptr, id_offset);
|
|
nread += nchunk;
|
|
}
|
|
|
|
if (mapflag && firstpass) {
|
|
atom->map_delete();
|
|
atom->map_style = Atom::MAP_NONE;
|
|
}
|
|
|
|
if (me == 0 && firstpass) utils::logmesg(lmp, " {} bodies\n", nblocks);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::mass()
|
|
{
|
|
settypeflag = 1;
|
|
char *next;
|
|
auto buf = new char[ntypes * MAXLINE];
|
|
|
|
int eof = utils::read_lines_from_file(fp, ntypes, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
if (tlabelflag && !lmap->is_complete(Atom::ATOM))
|
|
error->all(FLERR, "Label map is incomplete: all types must be assigned a unique type label");
|
|
|
|
char *original = buf;
|
|
for (int i = 0; i < ntypes; i++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
atom->set_mass(FLERR, buf, toffset, tlabelflag, lmap->lmap2lmap.atom);
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::paircoeffs()
|
|
{
|
|
char *next;
|
|
auto buf = new char[ntypes * MAXLINE];
|
|
|
|
int eof = utils::read_lines_from_file(fp, ntypes, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
|
|
if (tlabelflag && !lmap->is_complete(Atom::ATOM))
|
|
error->all(FLERR, "Label map is incomplete: all types must be assigned a unique type label");
|
|
|
|
char *original = buf;
|
|
for (int i = 0; i < ntypes; i++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
parse_coeffs(buf, nullptr, 1, 2, toffset, tlabelflag, lmap->lmap2lmap.atom);
|
|
if (ncoeffarg == 0) error->all(FLERR, "Unexpected empty line in PairCoeffs section");
|
|
force->pair->coeff(ncoeffarg, coeffarg);
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::pairIJcoeffs()
|
|
{
|
|
int i, j;
|
|
char *next;
|
|
|
|
int nsq = ntypes * (ntypes + 1) / 2;
|
|
auto buf = new char[nsq * MAXLINE];
|
|
|
|
int eof = utils::read_lines_from_file(fp, nsq, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
|
|
if (tlabelflag && !lmap->is_complete(Atom::ATOM))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
|
|
char *original = buf;
|
|
for (i = 0; i < ntypes; i++)
|
|
for (j = i; j < ntypes; j++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
parse_coeffs(buf, nullptr, 0, 2, toffset, tlabelflag, lmap->lmap2lmap.atom);
|
|
if (ncoeffarg == 0) error->all(FLERR, "Unexpected empty line in PairCoeffs section");
|
|
force->pair->coeff(ncoeffarg, coeffarg);
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::bondcoeffs()
|
|
{
|
|
if (!nbondtypes) return;
|
|
|
|
char *next;
|
|
auto buf = new char[nbondtypes * MAXLINE];
|
|
|
|
int eof = utils::read_lines_from_file(fp, nbondtypes, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
|
|
if (blabelflag && !lmap->is_complete(Atom::BOND))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
|
|
char *original = buf;
|
|
for (int i = 0; i < nbondtypes; i++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
parse_coeffs(buf, nullptr, 0, 1, boffset, blabelflag, lmap->lmap2lmap.bond);
|
|
if (ncoeffarg == 0) error->all(FLERR, "Unexpected empty line in BondCoeffs section");
|
|
force->bond->coeff(ncoeffarg, coeffarg);
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::anglecoeffs(int which)
|
|
{
|
|
if (!nangletypes) return;
|
|
|
|
char *next;
|
|
auto buf = new char[nangletypes * MAXLINE];
|
|
|
|
int eof = utils::read_lines_from_file(fp, nangletypes, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
|
|
if (alabelflag && !lmap->is_complete(Atom::ANGLE))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
|
|
char *original = buf;
|
|
for (int i = 0; i < nangletypes; i++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
if (which == 0)
|
|
parse_coeffs(buf, nullptr, 0, 1, aoffset, alabelflag, lmap->lmap2lmap.angle);
|
|
else if (which == 1)
|
|
parse_coeffs(buf, "bb", 0, 1, aoffset, alabelflag, lmap->lmap2lmap.angle);
|
|
else if (which == 2)
|
|
parse_coeffs(buf, "ba", 0, 1, aoffset, alabelflag, lmap->lmap2lmap.angle);
|
|
else if (which == 3)
|
|
parse_coeffs(buf, "ub", 0, 1, aoffset, alabelflag, lmap->lmap2lmap.angle);
|
|
if (ncoeffarg == 0) error->all(FLERR, "Unexpected empty line in AngleCoeffs section");
|
|
force->angle->coeff(ncoeffarg, coeffarg);
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::dihedralcoeffs(int which)
|
|
{
|
|
if (!ndihedraltypes) return;
|
|
|
|
char *next;
|
|
auto buf = new char[ndihedraltypes * MAXLINE];
|
|
|
|
int eof = utils::read_lines_from_file(fp, ndihedraltypes, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
|
|
if (dlabelflag && !lmap->is_complete(Atom::DIHEDRAL))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
|
|
char *original = buf;
|
|
for (int i = 0; i < ndihedraltypes; i++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
if (which == 0)
|
|
parse_coeffs(buf, nullptr, 0, 1, doffset, dlabelflag, lmap->lmap2lmap.dihedral);
|
|
else if (which == 1)
|
|
parse_coeffs(buf, "mbt", 0, 1, doffset, dlabelflag, lmap->lmap2lmap.dihedral);
|
|
else if (which == 2)
|
|
parse_coeffs(buf, "ebt", 0, 1, doffset, dlabelflag, lmap->lmap2lmap.dihedral);
|
|
else if (which == 3)
|
|
parse_coeffs(buf, "at", 0, 1, doffset, dlabelflag, lmap->lmap2lmap.dihedral);
|
|
else if (which == 4)
|
|
parse_coeffs(buf, "aat", 0, 1, doffset, dlabelflag, lmap->lmap2lmap.dihedral);
|
|
else if (which == 5)
|
|
parse_coeffs(buf, "bb13", 0, 1, doffset, dlabelflag, lmap->lmap2lmap.dihedral);
|
|
if (ncoeffarg == 0) error->all(FLERR, "Unexpected empty line in DihedralCoeffs section");
|
|
force->dihedral->coeff(ncoeffarg, coeffarg);
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::impropercoeffs(int which)
|
|
{
|
|
if (!nimpropertypes) return;
|
|
|
|
char *next;
|
|
auto buf = new char[nimpropertypes * MAXLINE];
|
|
|
|
int eof = utils::read_lines_from_file(fp, nimpropertypes, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
|
|
if (ilabelflag && !lmap->is_complete(Atom::IMPROPER))
|
|
error->all(FLERR,
|
|
"Label map is incomplete: "
|
|
"all types must be assigned a unique type label");
|
|
|
|
char *original = buf;
|
|
for (int i = 0; i < nimpropertypes; i++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
if (which == 0)
|
|
parse_coeffs(buf, nullptr, 0, 1, ioffset, ilabelflag, lmap->lmap2lmap.improper);
|
|
else if (which == 1)
|
|
parse_coeffs(buf, "aa", 0, 1, ioffset, ilabelflag, lmap->lmap2lmap.improper);
|
|
if (ncoeffarg == 0) error->all(FLERR, "Unexpected empty line in ImproperCoeffs section");
|
|
force->improper->coeff(ncoeffarg, coeffarg);
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadData::typelabels(int mode)
|
|
{
|
|
if (settypeflag) error->all(FLERR, "Must read Type Labels before any section involving types");
|
|
|
|
int lntypes = 0;
|
|
std::vector<std::string> *labels;
|
|
std::unordered_map<std::string, int> *labels_map;
|
|
if (me == 0)
|
|
utils::logmesg(lmp, " reading {} labelmap ...\n", utils::lowercase(labeltypes[mode]));
|
|
|
|
switch (mode) {
|
|
case Atom::ATOM:
|
|
lntypes = lmap->natomtypes;
|
|
labels = &lmap->typelabel;
|
|
labels_map = &lmap->typelabel_map;
|
|
break;
|
|
case Atom::BOND:
|
|
lntypes = lmap->nbondtypes;
|
|
labels = &lmap->btypelabel;
|
|
labels_map = &lmap->btypelabel_map;
|
|
break;
|
|
case Atom::ANGLE:
|
|
lntypes = lmap->nangletypes;
|
|
labels = &lmap->atypelabel;
|
|
labels_map = &lmap->atypelabel_map;
|
|
break;
|
|
case Atom::DIHEDRAL:
|
|
lntypes = lmap->ndihedraltypes;
|
|
labels = &lmap->dtypelabel;
|
|
labels_map = &lmap->dtypelabel_map;
|
|
break;
|
|
case Atom::IMPROPER:
|
|
lntypes = lmap->nimpropertypes;
|
|
labels = &lmap->itypelabel;
|
|
labels_map = &lmap->itypelabel_map;
|
|
break;
|
|
}
|
|
|
|
if (lntypes == 0) return;
|
|
|
|
if (!atom->labelmapflag) atom->add_label_map();
|
|
|
|
char *buf = new char[lntypes * MAXLINE];
|
|
int eof = utils::read_lines_from_file(fp, lntypes, MAXLINE, buf, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file");
|
|
|
|
char *original = buf;
|
|
char *next;
|
|
for (int i = 0; i < lntypes; i++) {
|
|
next = strchr(buf, '\n');
|
|
*next = '\0';
|
|
auto values = Tokenizer(buf).as_vector();
|
|
int nwords = values.size();
|
|
for (std::size_t ii = 0; ii < values.size(); ++ii) {
|
|
if (utils::strmatch(values[ii], "^#")) {
|
|
nwords = ii;
|
|
break;
|
|
}
|
|
}
|
|
if (nwords != 2)
|
|
error->all(FLERR, "Invalid format in section: {} Type Labels: {}", labeltypes[mode], buf);
|
|
values[1] = utils::utf8_subst(values[1]);
|
|
if (utils::is_type(values[1]) != 1) error->all(FLERR, "Invalid type label {}", values[1]);
|
|
int itype = utils::inumeric(FLERR, values[0], false, lmp);
|
|
if ((itype < 1) || (itype > lntypes))
|
|
error->all(FLERR, "Invalid type {} in section: {} Type Labels: {}", labeltypes[mode], buf);
|
|
|
|
(*labels)[itype - 1] = values[1];
|
|
(*labels_map)[values[1]] = itype;
|
|
buf = next + 1;
|
|
}
|
|
delete[] original;
|
|
|
|
for (int i = 0; i < lntypes; ++i) {
|
|
if ((*labels)[i].empty())
|
|
error->all(FLERR, "{} Type Labels map is incomplete", labeltypes[mode]);
|
|
}
|
|
if ((int) (*labels_map).size() != lntypes)
|
|
error->all(FLERR, "{} Type Labels map is incomplete", labeltypes[mode]);
|
|
|
|
// merge this read_data label map to atom class
|
|
// determine mapping to let labels override numeric types
|
|
// valid operations for first or subsequent data files
|
|
|
|
atom->lmap->merge_lmap(lmap, mode);
|
|
lmap->create_lmap2lmap(atom->lmap, mode);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read fix section, pass lines to fix to process
|
|
n = index of fix
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::fix(Fix *ifix, char *keyword)
|
|
{
|
|
int nchunk, eof;
|
|
|
|
bigint nline = ifix->read_data_skip_lines(keyword);
|
|
|
|
bigint nread = 0;
|
|
while (nread < nline) {
|
|
nchunk = MIN(nline - nread, CHUNK);
|
|
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
|
|
if (eof) error->all(FLERR, "Unexpected end of data file while reading section {}", keyword);
|
|
ifix->read_data_section(keyword, nchunk, buffer, id_offset);
|
|
nread += nchunk;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
reallocate the count vector from cmax to amax+1 and return new length
|
|
zero new locations
|
|
------------------------------------------------------------------------- */
|
|
|
|
int ReadData::reallocate(int **pcount, int cmax, int amax)
|
|
{
|
|
int *count = *pcount;
|
|
memory->grow(count, amax + 1, "read_data:count");
|
|
for (int i = cmax; i <= amax; i++) count[i] = 0;
|
|
*pcount = count;
|
|
return amax + 1;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
proc 0 opens data file
|
|
test if compressed
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::open(const std::string &file)
|
|
{
|
|
if (platform::has_compress_extension(file)) {
|
|
compressed = 1;
|
|
fp = platform::compressed_read(file);
|
|
if (!fp) error->one(FLERR, "Cannot open compressed file {}", file);
|
|
} else {
|
|
compressed = 0;
|
|
fp = fopen(file.c_str(), "r");
|
|
if (!fp) error->one(FLERR, "Cannot open file {}: {}", file, utils::getsyserror());
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
grab next keyword
|
|
read lines until one is non-blank
|
|
keyword is all text on line w/out leading & trailing white space
|
|
optional style can be appended after comment char '#'
|
|
read one additional line (assumed blank)
|
|
if any read hits EOF, set keyword to empty
|
|
if first = 1, line variable holds non-blank line that ended header
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::parse_keyword(int first)
|
|
{
|
|
int eof = 0;
|
|
int done = 0;
|
|
|
|
// proc 0 reads upto non-blank line plus 1 following line
|
|
// eof is set to 1 if any read hits end-of-file
|
|
|
|
if (me == 0) {
|
|
if (!first) {
|
|
if (utils::fgets_trunc(line, MAXLINE, fp) == nullptr) eof = 1;
|
|
}
|
|
while (eof == 0 && done == 0) {
|
|
int blank = strspn(line, " \t\n\r");
|
|
if ((blank == (int) strlen(line)) || (line[blank] == '#')) {
|
|
if (utils::fgets_trunc(line, MAXLINE, fp) == nullptr) eof = 1;
|
|
} else
|
|
done = 1;
|
|
}
|
|
if (utils::fgets_trunc(buffer, MAXLINE, fp) == nullptr) {
|
|
eof = 1;
|
|
buffer[0] = '\0';
|
|
}
|
|
}
|
|
|
|
// if eof, set keyword empty and return
|
|
|
|
MPI_Bcast(&eof, 1, MPI_INT, 0, world);
|
|
if (eof) {
|
|
keyword[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
// bcast keyword line to all procs
|
|
|
|
int n;
|
|
if (me == 0) n = strlen(line) + 1;
|
|
MPI_Bcast(&n, 1, MPI_INT, 0, world);
|
|
MPI_Bcast(line, n, MPI_CHAR, 0, world);
|
|
|
|
// store optional "style" following comment char '#' after keyword
|
|
|
|
char *ptr;
|
|
if ((ptr = strchr(line, '#'))) {
|
|
*ptr++ = '\0';
|
|
while (*ptr == ' ' || *ptr == '\t') ptr++;
|
|
int stop = strlen(ptr) - 1;
|
|
while (ptr[stop] == ' ' || ptr[stop] == '\t' || ptr[stop] == '\n' || ptr[stop] == '\r') stop--;
|
|
ptr[stop + 1] = '\0';
|
|
strcpy(style, ptr);
|
|
} else
|
|
style[0] = '\0';
|
|
|
|
// copy non-whitespace portion of line into keyword
|
|
|
|
int start = strspn(line, " \t\n\r");
|
|
int stop = strlen(line) - 1;
|
|
while (line[stop] == ' ' || line[stop] == '\t' || line[stop] == '\n' || line[stop] == '\r')
|
|
stop--;
|
|
line[stop + 1] = '\0';
|
|
strcpy(keyword, &line[start]);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
proc 0 reads N lines from file
|
|
could be skipping Natoms lines, so use bigints
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::skip_lines(bigint n)
|
|
{
|
|
if (me) return;
|
|
if (n <= 0) return;
|
|
char *eof = nullptr;
|
|
for (bigint i = 0; i < n; i++) eof = utils::fgets_trunc(line, MAXLINE, fp);
|
|
if (eof == nullptr) error->one(FLERR, "Unexpected end of data file");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
parse a line of coeffs into words, storing them in ncoeffarg,coeffarg
|
|
trim anything from '#' onward
|
|
word strings remain in line, are not copied
|
|
if addstr != nullptr, add addstr as extra arg for class2 angle/dihedral/improper
|
|
if 2nd word starts with letter, then is hybrid style, add addstr after it
|
|
else add addstr before 2nd word
|
|
if dupflag, duplicate 1st word, so pair_coeff "2" becomes "2 2"
|
|
if noffset, add offset to first noffset args, which are atom/bond/etc types
|
|
if labelflag, use ilabel to find the correct remapping of numeric type
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadData::parse_coeffs(char *line, const char *addstr, int dupflag, int noffset, int offset,
|
|
int labelmode, int *ilabel)
|
|
{
|
|
settypeflag = 1;
|
|
char *ptr;
|
|
if ((ptr = strchr(line, '#'))) *ptr = '\0';
|
|
|
|
ncoeffarg = 0;
|
|
char *word = line;
|
|
char *end = line + strlen(line) + 1;
|
|
|
|
while (word < end) {
|
|
word += strspn(word, " \t\r\n\f");
|
|
word[strcspn(word, " \t\r\n\f")] = '\0';
|
|
if (strlen(word) == 0) break;
|
|
if (ncoeffarg == maxcoeffarg) {
|
|
maxcoeffarg += DELTA;
|
|
coeffarg =
|
|
(char **) memory->srealloc(coeffarg, maxcoeffarg * sizeof(char *), "read_data:coeffarg");
|
|
}
|
|
if (addstr && ncoeffarg == 1 && !islower(word[0])) coeffarg[ncoeffarg++] = (char *) addstr;
|
|
coeffarg[ncoeffarg++] = word;
|
|
if (addstr && ncoeffarg == 2 && islower(word[0])) coeffarg[ncoeffarg++] = (char *) addstr;
|
|
if (dupflag && ncoeffarg == 1) coeffarg[ncoeffarg++] = word;
|
|
word += strlen(word) + 1;
|
|
}
|
|
|
|
// to avoid segfaults on empty lines
|
|
|
|
if (ncoeffarg == 0) return;
|
|
|
|
if (noffset) {
|
|
int value = utils::inumeric(FLERR, coeffarg[0], false, lmp);
|
|
if (labelmode) value = ilabel[value - 1];
|
|
sprintf(argoffset1, "%d", value + offset);
|
|
coeffarg[0] = argoffset1;
|
|
if (noffset == 2) {
|
|
value = utils::inumeric(FLERR, coeffarg[1], false, lmp);
|
|
if (labelmode) value = ilabel[value - 1];
|
|
sprintf(argoffset2, "%d", value + offset);
|
|
coeffarg[1] = argoffset2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
compare two style strings if they both exist
|
|
one = comment in data file section, two = currently-defined style
|
|
ignore suffixes listed in suffixes array at top of file
|
|
------------------------------------------------------------------------- */
|
|
|
|
int ReadData::style_match(const char *one, const char *two)
|
|
{
|
|
int i, delta, len, len1, len2;
|
|
|
|
if ((one == nullptr) || (two == nullptr)) return 1;
|
|
|
|
len1 = strlen(one);
|
|
len2 = strlen(two);
|
|
|
|
for (i = 0; suffixes[i] != nullptr; i++) {
|
|
len = strlen(suffixes[i]);
|
|
if ((delta = len1 - len) > 0)
|
|
if (strcmp(one + delta, suffixes[i]) == 0) len1 = delta;
|
|
if ((delta = len2 - len) > 0)
|
|
if (strcmp(two + delta, suffixes[i]) == 0) len2 = delta;
|
|
}
|
|
|
|
if ((len1 == 0) || (len1 == len2) || (strncmp(one, two, len1) == 0)) return 1;
|
|
return 0;
|
|
}
|