/* ---------------------------------------------------------------------- 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 #include #include 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 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(atom->style_match("ellipsoid")); nlines = 0; avec_line = dynamic_cast(atom->style_match("line")); ntris = 0; avec_tri = dynamic_cast(atom->style_match("tri")); nbodies = 0; avec_body = dynamic_cast(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(atom->natoms); else n = static_cast(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(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 *labels; std::unordered_map *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; }