diff --git a/python/lammps/core.py b/python/lammps/core.py index 80961186f3..932d4b863c 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -272,6 +272,9 @@ class lammps(object): self.lib.lammps_get_thermo.argtypes = [c_void_p, c_char_p] self.lib.lammps_get_thermo.restype = c_double + self.lib.lammps_last_thermo.argtypes = [c_void_p, c_char_p, c_int] + self.lib.lammps_last_thermo.restype = c_void_p + self.lib.lammps_encode_image_flags.restype = self.c_imageint self.lib.lammps_config_has_package.argtypes = [c_char_p] @@ -744,6 +747,57 @@ class lammps(object): # ------------------------------------------------------------------------- + def last_thermo(self): + """Get a dictionary of the last thermodynamic output + + This is a wrapper around the :cpp:func:`lammps_last_thermo` + function of the C-library interface. It collects the cached thermo + data from the last timestep into a dictionary. The return value + is None, if there has not been any thermo output yet. + + :return: value of thermo keyword + :rtype: dict or None + """ + + rv = dict() + with ExceptionCheck(self): + ptr = self.lib.lammps_last_thermo(self.lmp, c_char_p("step".encode()), 0) + mystep = cast(ptr, POINTER(self.c_bigint)).contents.value + if mystep < 0: + return None + + with ExceptionCheck(self): + ptr = self.lib.lammps_last_thermo(self.lmp, c_char_p("num".encode()), 0) + nfield = cast(ptr, POINTER(c_int)).contents.value + + for i in range(nfield): + with ExceptionCheck(self): + ptr = self.lib.lammps_last_thermo(self.lmp, c_char_p("keyword".encode()), i) + kw = cast(ptr, c_char_p).value.decode() + + # temporarily switch return type since this stores an int in a pointer + self.lib.lammps_last_thermo.restype = c_int + with ExceptionCheck(self): + typ = self.lib.lammps_last_thermo(self.lmp, c_char_p("type".encode()), i) + self.lib.lammps_last_thermo.restype = c_void_p + with ExceptionCheck(self): + ptr = self.lib.lammps_last_thermo(self.lmp, c_char_p("data".encode()), i) + + if typ == LAMMPS_DOUBLE: + val = cast(ptr, POINTER(c_double)).contents.value + elif typ == LAMMPS_INT: + val = cast(ptr, POINTER(c_int)).contents.value + elif typ == LAMMPS_INT64: + val = cast(ptr, POINTER(c_int64)).contents.value + else: + # we should not get here + raise TypeError("Unknown LAMMPS data type " + str(typ)) + rv[kw] = val + + return rv + + # ------------------------------------------------------------------------- + def extract_setting(self, name): """Query LAMMPS about global settings that can be expressed as an integer. diff --git a/src/library.cpp b/src/library.cpp index 02758abcda..cf5d131ba6 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -783,15 +783,15 @@ argument string. - no * - keyword - column keyword for thermo output - - const char pointer + - pointer to 0-terminated const char array - yes * - type - data type of thermo output column; see :cpp:enum:`_LMP_DATATYPE_CONST` - - const int + - const int (**not** a pointer) - yes * - data - actual field data for column - - pointer to either int, int64_t or double + - pointer to int, int64_t or double - yes \endverbatim diff --git a/src/library.h b/src/library.h index 4c2530210c..5f46e36ccf 100644 --- a/src/library.h +++ b/src/library.h @@ -148,7 +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_last_thermo(void *handle, const char *what, int index); void lammps_extract_box(void *handle, double *boxlo, double *boxhi, double *xy, double *yz, double *xz, int *pflags, int *boxflag);