diff --git a/src/potential_file_reader.cpp b/src/potential_file_reader.cpp index 13cb2d62d3..a8aa0adb43 100644 --- a/src/potential_file_reader.cpp +++ b/src/potential_file_reader.cpp @@ -22,6 +22,7 @@ #include "potential_file_reader.h" #include "utils.h" #include "tokenizer.h" +#include "fmt/format.h" #include @@ -30,102 +31,111 @@ using namespace LAMMPS_NS; PotentialFileReader::PotentialFileReader(LAMMPS *lmp, const std::string &filename, const std::string &potential_name) : - Pointers(lmp), filename(filename), potential_name(potential_name) + Pointers(lmp), + reader(nullptr), + filename(filename), + potential_name(potential_name) { if (comm->me != 0) { error->one(FLERR, "PotentialFileReader should only be called by proc 0!"); } - fp = force->open_potential(filename.c_str()); - - if (fp == NULL) { - char str[128]; - snprintf(str, 128, "cannot open %s potential file %s", potential_name.c_str(), filename.c_str()); - error->one(FLERR, str); + try { + reader = open_potential(filename); + } catch (FileReaderException & e) { + error->one(FLERR, e.what()); } } PotentialFileReader::~PotentialFileReader() { - fclose(fp); + delete reader; } void PotentialFileReader::skip_line() { - char *ptr = fgets(line, MAXLINE, fp); - if (ptr == nullptr) { - // EOF - char str[128]; - snprintf(str, 128, "Missing line in %s potential file!", potential_name.c_str()); - error->one(FLERR, str); + try { + reader->skip_line(); + } catch (FileReaderException & e) { + error->one(FLERR, e.what()); } } char *PotentialFileReader::next_line(int nparams) { - // concatenate lines until have nparams words - int n = 0; - int nwords = 0; - - char *ptr = fgets(line, MAXLINE, fp); - - if (ptr == nullptr) { - // EOF - return nullptr; + try { + return reader->next_line(nparams); + } catch (FileReaderException & e) { + error->one(FLERR, e.what()); } - - // strip comment - if ((ptr = strchr(line, '#'))) *ptr = '\0'; - - nwords = utils::count_words(line); - - if (nwords > 0) { - n = strlen(line); - } - - while(nwords == 0 || nwords < nparams) { - char *ptr = fgets(&line[n], MAXLINE - n, fp); - - if (ptr == nullptr) { - // EOF - if (nwords > 0 && nwords < nparams) { - char str[128]; - snprintf(str, 128, "Incorrect format in %s potential file! %d/%d parameters", potential_name.c_str(), nwords, nparams); - error->one(FLERR, str); - } - - return nullptr; - } - - - // strip comment - if ((ptr = strchr(line, '#'))) *ptr = '\0'; - - nwords = utils::count_words(line); - - // skip line if blank - if (nwords > 0) { - n = strlen(line); - } - } - - return line; + return nullptr; } void PotentialFileReader::next_dvector(int n, double * list) { - int i = 0; - while (i < n) { - char *ptr = fgets(line, MAXLINE, fp); - - if (ptr == nullptr) { - // EOF - if (i < n) { - char str[128]; - snprintf(str, 128, "Incorrect format in %s potential file! %d/%d values", potential_name.c_str(), i, n); - error->one(FLERR, str); - } - } - - ValueTokenizer values(line); - while(values.has_next()) { - list[i++] = values.next_double(); - } + try { + return reader->next_dvector(n, list); + } catch (FileReaderException & e) { + error->one(FLERR, e.what()); } } + +/* ---------------------------------------------------------------------- + open a potential file as specified by name + if fails, search in dir specified by env variable LAMMPS_POTENTIALS +------------------------------------------------------------------------- */ + +TextFileReader * PotentialFileReader::open_potential(const std::string& path) { + // attempt to open file directly + // if successful, return filename + std::string filepath = path; + std::string filename = utils::path_basename(path); + std::string date; + + if(utils::file_is_readable(filepath)) { + date = get_potential_date(filepath); + } else { + // try the environment variable directory + const char *path = getenv("LAMMPS_POTENTIALS"); + + if (path != nullptr){ + std::string pot = utils::path_basename(filepath); + filepath = utils::path_join(path, pot); + + if (utils::file_is_readable(filepath)) { + date = get_potential_date(filepath); + } else { + return nullptr; + } + } else { + return nullptr; + } + } + + if(!date.empty()) { + utils::logmesg(lmp, fmt::format("Reading potential file {} with DATE: {}", filename, date)); + } + + return new TextFileReader(filepath, potential_name + " potential"); +} + +/* ---------------------------------------------------------------------- + read first line of potential file + if has DATE field, print following word +------------------------------------------------------------------------- */ + +std::string PotentialFileReader::get_potential_date(const std::string & path) { + TextFileReader reader(path, potential_name + " potential"); + reader.ignore_comments = false; + char * line = nullptr; + + while (line = reader.next_line()) { + ValueTokenizer values(line); + while (values.has_next()) { + std::string word = values.next_string(); + if (word == "DATE:") { + if (values.has_next()) { + std::string date = values.next_string(); + return date; + } + } + } + } + return ""; +} diff --git a/src/potential_file_reader.h b/src/potential_file_reader.h index b18d3841c3..0d3d52acfe 100644 --- a/src/potential_file_reader.h +++ b/src/potential_file_reader.h @@ -21,15 +21,17 @@ #include #include "pointers.h" +#include "text_file_reader.h" namespace LAMMPS_NS { class PotentialFileReader : protected Pointers { - std::string potential_name; + TextFileReader * reader; std::string filename; - static const int MAXLINE = 1024; - char line[MAXLINE]; - FILE *fp; + std::string potential_name; + + TextFileReader * open_potential(const std::string& path); + std::string get_potential_date(const std::string & path); public: PotentialFileReader(class LAMMPS *lmp, const std::string &filename, const std::string &potential_name); diff --git a/src/text_file_reader.cpp b/src/text_file_reader.cpp new file mode 100644 index 0000000000..b0cf7d2f4d --- /dev/null +++ b/src/text_file_reader.cpp @@ -0,0 +1,117 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Richard Berger (Temple U) +------------------------------------------------------------------------- */ + +#include "lammps.h" +#include "force.h" +#include "error.h" +#include "comm.h" +#include "utils.h" +#include "text_file_reader.h" +#include "tokenizer.h" +#include "fmt/format.h" + +#include + +using namespace LAMMPS_NS; + +TextFileReader::TextFileReader(const std::string &filename, const std::string &filetype) + : filename(filename), filetype(filetype) +{ + fp = fopen(filename.c_str(), "r"); + + if (fp == nullptr) { + throw FileReaderException(fmt::format("cannot open {} file {}", filetype, filename)); + } +} + +TextFileReader::~TextFileReader() { + fclose(fp); +} + +void TextFileReader::skip_line() { + char *ptr = fgets(line, MAXLINE, fp); + if (ptr == nullptr) { + // EOF + throw EOFException(fmt::format("Missing line in {} file!", filetype)); + } +} + +char *TextFileReader::next_line(int nparams) { + // concatenate lines until have nparams words + int n = 0; + int nwords = 0; + + char *ptr = fgets(line, MAXLINE, fp); + + if (ptr == nullptr) { + // EOF + return nullptr; + } + + // strip comment + if (ignore_comments && (ptr = strchr(line, '#'))) *ptr = '\0'; + + nwords = utils::count_words(line); + + if (nwords > 0) { + n = strlen(line); + } + + while(nwords == 0 || nwords < nparams) { + char *ptr = fgets(&line[n], MAXLINE - n, fp); + + if (ptr == nullptr) { + // EOF + if (nwords > 0 && nwords < nparams) { + throw EOFException(fmt::format("Incorrect format in {} file! {}/{} parameters", filetype.c_str(), nwords, nparams)); + } + return nullptr; + } + + + // strip comment + if (ignore_comments && (ptr = strchr(line, '#'))) *ptr = '\0'; + + nwords = utils::count_words(line); + + // skip line if blank + if (nwords > 0) { + n = strlen(line); + } + } + + return line; +} + +void TextFileReader::next_dvector(int n, double * list) { + int i = 0; + while (i < n) { + char *ptr = fgets(line, MAXLINE, fp); + + if (ptr == nullptr) { + // EOF + if (i < n) { + throw FileReaderException(fmt::format("Incorrect format in {} file! {}/{} values", filetype, i, n)); + } + } + + ValueTokenizer values(line); + while(values.has_next()) { + list[i++] = values.next_double(); + } + } +} diff --git a/src/text_file_reader.h b/src/text_file_reader.h new file mode 100644 index 0000000000..4e31e95a67 --- /dev/null +++ b/src/text_file_reader.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Richard Berger (Temple U) +------------------------------------------------------------------------- */ + +#ifndef LMP_TEXT_FILE_READER_H +#define LMP_TEXT_FILE_READER_H + +#include +#include +#include + +namespace LAMMPS_NS +{ + class TextFileReader { + std::string filename; + std::string filetype; + static const int MAXLINE = 1024; + char line[MAXLINE]; + FILE *fp; + + public: + bool ignore_comments; + + TextFileReader(const std::string &filename, const std::string &filetype); + ~TextFileReader(); + + void skip_line(); + char * next_line(int nparams = 0); + + void next_dvector(int n, double * list); + }; + + class FileReaderException : public std::exception { + std::string message; + public: + FileReaderException(const std::string & msg) : message(msg) { + } + + ~FileReaderException() throw() { + } + + virtual const char * what() const throw() { + return message.c_str(); + } + }; + + class EOFException : public FileReaderException { + public: + EOFException(const std::string & msg) : FileReaderException(msg) { + } + }; + +} // namespace LAMMPS_NS + +#endif