From 491e152289e3abf267f4ebee6cddda7ba797591f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 7 Jun 2023 16:21:01 -0400 Subject: [PATCH] add API to library interface to access last thermo data --- src/EXTRA-DUMP/dump_yaml.cpp | 4 +- src/NETCDF/dump_netcdf.cpp | 12 ++-- src/NETCDF/dump_netcdf_mpiio.cpp | 12 ++-- src/library.cpp | 99 +++++++++++++++++++++++++++++++- src/library.h | 1 + src/thermo.cpp | 1 + src/thermo.h | 4 +- 7 files changed, 116 insertions(+), 17 deletions(-) diff --git a/src/EXTRA-DUMP/dump_yaml.cpp b/src/EXTRA-DUMP/dump_yaml.cpp index f8d2fb2264..47cab1ee02 100644 --- a/src/EXTRA-DUMP/dump_yaml.cpp +++ b/src/EXTRA-DUMP/dump_yaml.cpp @@ -61,8 +61,8 @@ void DumpYAML::write_header(bigint ndump) if (thermo) { Thermo *th = output->thermo; // output thermo data only on timesteps where it was computed - if (update->ntimestep == th->get_timestep()) { - int nfield = th->get_nfield(); + if (update->ntimestep == *th->get_timestep()) { + int nfield = *th->get_nfield(); const auto &keywords = th->get_keywords(); const auto &fields = th->get_fields(); diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index 2b064edeae..0115c0bbe9 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -224,7 +224,7 @@ void DumpNetCDF::openfile() if (thermo && !singlefile_opened) { delete[] thermovar; - thermovar = new int[output->thermo->get_nfield()]; + thermovar = new int[*output->thermo->get_nfield()]; } // now the computes and fixes have been initialized, so we can query @@ -323,7 +323,7 @@ void DumpNetCDF::openfile() if (thermo) { Thermo *th = output->thermo; const auto &keywords = th->get_keywords(); - const int nfield = th->get_nfield(); + const int nfield = *th->get_nfield(); for (int i = 0; i < nfield; i++) { NCERRX( nc_inq_varid(ncid, keywords[i].c_str(), &thermovar[i]), keywords[i].c_str() ); @@ -439,7 +439,7 @@ void DumpNetCDF::openfile() Thermo *th = output->thermo; const auto &fields = th->get_fields(); const auto &keywords = th->get_keywords(); - const int nfield = th->get_nfield(); + const int nfield = *th->get_nfield(); for (int i = 0; i < nfield; i++) { if (fields[i].type == multitype::DOUBLE) { @@ -610,18 +610,18 @@ void DumpNetCDF::write() // will output current thermo data only on timesteps where it was computed. // warn (once) about using cached copy from old timestep. - if (thermo_warn && (update->ntimestep != th->get_timestep())) { + if (thermo_warn && (update->ntimestep != *th->get_timestep())) { thermo_warn = false; if (comm->me == 0) { error->warning(FLERR, "Dump {} output on incompatible timestep with thermo output: {} vs {} \n" " Dump netcdf always stores thermo data from last thermo output", - id, th->get_timestep(), update->ntimestep); + id, *th->get_timestep(), update->ntimestep); } } const auto &keywords = th->get_keywords(); const auto &fields = th->get_fields(); - int nfield = th->get_nfield(); + int nfield = *th->get_nfield(); for (int i = 0; i < nfield; i++) { if (filewriter) { if (fields[i].type == multitype::DOUBLE) { diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index 4a34f11ab4..f9382dacef 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -221,7 +221,7 @@ void DumpNetCDFMPIIO::openfile() if (thermo && !singlefile_opened) { delete[] thermovar; - thermovar = new int[output->thermo->get_nfield()]; + thermovar = new int[*output->thermo->get_nfield()]; } // now the computes and fixes have been initialized, so we can query @@ -321,7 +321,7 @@ void DumpNetCDFMPIIO::openfile() if (thermo) { Thermo *th = output->thermo; const auto &keywords = th->get_keywords(); - const int nfield = th->get_nfield(); + const int nfield = *th->get_nfield(); for (int i = 0; i < nfield; i++) { NCERRX( ncmpi_inq_varid(ncid, keywords[i].c_str(), &thermovar[i]), keywords[i].c_str() ); @@ -429,7 +429,7 @@ void DumpNetCDFMPIIO::openfile() Thermo *th = output->thermo; const auto &fields = th->get_fields(); const auto &keywords = th->get_keywords(); - const int nfield = th->get_nfield(); + const int nfield = *th->get_nfield(); for (int i = 0; i < nfield; i++) { if (fields[i].type == multitype::DOUBLE) { @@ -603,18 +603,18 @@ void DumpNetCDFMPIIO::write() // will output current thermo data only on timesteps where it was computed. // warn (once) about using cached copy from old timestep. - if (thermo_warn && (update->ntimestep != th->get_timestep())) { + if (thermo_warn && (update->ntimestep != *th->get_timestep())) { thermo_warn = false; if (comm->me == 0) { error->warning(FLERR, "Dump {} output on incompatible timestep with thermo output: {} vs {} \n" " Dump netcdf/mpiio always stores thermo data from last thermo output", - id, th->get_timestep(), update->ntimestep); + id, *th->get_timestep(), update->ntimestep); } } const auto &keywords = th->get_keywords(); const auto &fields = th->get_fields(); - int nfield = th->get_nfield(); + int nfield = *th->get_nfield(); for (int i = 0; i < nfield; i++) { if (filewriter) { if (fields[i].type == multitype::DOUBLE) { diff --git a/src/library.cpp b/src/library.cpp index 33f49a4e53..6b079b4a93 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -719,7 +719,7 @@ double lammps_get_natoms(void *handle) /* ---------------------------------------------------------------------- */ -/** Get current value of a thermo keyword. +/** Evaluate a thermo keyword. * \verbatim embed:rst @@ -750,6 +750,103 @@ double lammps_get_thermo(void *handle, const char *keyword) /* ---------------------------------------------------------------------- */ +/** Access cached data from last thermo output + * +\verbatim embed:rst + +This function provides access to cached data from the last thermo +output. This differs from :cpp:func:`lammps_get_thermo` in that it does +not trigger an evaluation. It provides direct access to a a read-only +location of the last thermo output data and the corresponding keyword +strings. The output depends on the value of the *what* argument string. + +.. list-table:: + :header-rows: 1 + :widths: auto + + * - Value of *what + - Description of return value + - Data type + - Uses index + * - step + - timestep when the last thermo output was generated or -1 when no data available + - pointer to bigint cast to void pointer + - no + * - num + - number of fields in thermo output + - pointer to int cast to void pointer + - no + * - keyword + - column keyword for thermo output + - const char pointer cast to void pointer + - yes + * - type + - data type of thermo output column. LAMMPS_INT, LAMMPS_DOUBLE, or LAMMPS_INT64 + - const int cast to void pointer + - yes + * - data + - actual field data for column + - pointer to either int, int64_t or double cast to void pointer + - yes + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance + * \param what string with the kind of data requested + * \param idx integer with index into data arrays, ignored for scalar data + * \return pointer to location of requested data cast to void or NULL */ + +void *lammps_last_thermo(void *handle, const char *what, int idx) +{ + auto lmp = (LAMMPS *) handle; + void *val = nullptr; + Thermo *th = lmp->output->thermo; + if (!th) return nullptr; + const int nfield = *th->get_nfield(); + + BEGIN_CAPTURE + { + if (strcmp(what, "step") == 0) { + val = (void *) th->get_timestep(); + + } else if (strcmp(what, "num") == 0) { + val = (void *) th->get_nfield(); + + } else if (strcmp(what, "keyword") == 0) { + if ((idx < 0) || (idx >= nfield)) return nullptr; + const auto &keywords = th->get_keywords(); + val = (void *) keywords[idx].c_str(); + + } else if (strcmp(what, "type") == 0) { + if ((idx < 0) || (idx >= nfield)) return nullptr; + const auto &field = th->get_fields()[idx]; + if (field.type == multitype::INT) { + val = (void *) LAMMPS_INT; + } else if (field.type == multitype::BIGINT) { + val = (void *) LAMMPS_INT64; + } else if (field.type == multitype::DOUBLE) { + val = (void *) LAMMPS_DOUBLE; + } + + } else if (strcmp(what, "data") == 0) { + if ((idx < 0) || (idx >= nfield)) return nullptr; + const auto &field = th->get_fields()[idx]; + if (field.type == multitype::INT) { + val = (void *) &field.data.i; + } else if (field.type == multitype::BIGINT) { + val = (void *) &field.data.b; + } else if (field.type == multitype::DOUBLE) { + val = (void *) &field.data.d; + } + + } else val = nullptr; + } + END_CAPTURE + return val; +} + +/* ---------------------------------------------------------------------- */ + /** Extract simulation box parameters. * \verbatim embed:rst diff --git a/src/library.h b/src/library.h index 340b0edb7b..4c2530210c 100644 --- a/src/library.h +++ b/src/library.h @@ -148,6 +148,7 @@ void lammps_commands_string(void *handle, const char *str); double lammps_get_natoms(void *handle); double lammps_get_thermo(void *handle, const char *keyword); +void *lammps_last_thermo(void *handle, const char *what, int idx); void lammps_extract_box(void *handle, double *boxlo, double *boxhi, double *xy, double *yz, double *xz, int *pflags, int *boxflag); diff --git a/src/thermo.cpp b/src/thermo.cpp index 1c07da695f..c6e71354ff 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -111,6 +111,7 @@ Thermo::Thermo(LAMMPS *_lmp, int narg, char **arg) : lostflag = lostbond = Thermo::ERROR; lostbefore = warnbefore = 0; flushflag = 0; + ntimestep = -1; // set style and corresponding lineflag // custom style builds its own line of keywords, including wildcard expansion diff --git a/src/thermo.h b/src/thermo.h index f22f3103b0..333a282ca0 100644 --- a/src/thermo.h +++ b/src/thermo.h @@ -43,8 +43,8 @@ class Thermo : protected Pointers { int evaluate_keyword(const std::string &, double *); // for accessing cached thermo data - int get_nfield() const { return nfield; } - bigint get_timestep() const { return ntimestep; } + const int *get_nfield() const { return &nfield; } + const bigint *get_timestep() const { return &ntimestep; } const std::vector &get_fields() const { return field_data; } const std::vector &get_keywords() const { return keyword; }