diff --git a/python/lammps.py b/python/lammps.py index a554f66a02..112fdc4108 100644 --- a/python/lammps.py +++ b/python/lammps.py @@ -40,6 +40,7 @@ LAMMPS_DOUBLE2D = 3 LAMMPS_BIGINT = 4 LAMMPS_TAGINT = 5 LAMMPS_STRING = 6 +LAMMPS_TAGINT2D = 7 # these must be kept in sync with the enums in library.h LMP_STYLE_GLOBAL = 0 diff --git a/src/atom.cpp b/src/atom.cpp index 21e6c87c7b..6fc66bf813 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -30,6 +30,7 @@ #include "neighbor.h" #include "update.h" #include "variable.h" +#include "library.h" #include #include @@ -2580,6 +2581,80 @@ void *Atom::extract(const char *name) return nullptr; } + +/** Provide data type about internal data of the Atom class + * + * \param name string with the keyword of the desired property. + * \return data type constant for desired property or -1 */ +int Atom::extract_datatype(const char *name) +{ + // -------------------------------------------------------------------- + // 5th customization section: customize by adding new variable name + + if (strcmp(name,"mass") == 0) return LAMMPS_DOUBLE; + + if (strcmp(name,"id") == 0) return LAMMPS_TAGINT; + if (strcmp(name,"type") == 0) return LAMMPS_INT; + if (strcmp(name,"mask") == 0) return LAMMPS_INT; + if (strcmp(name,"image") == 0) return LAMMPS_TAGINT; + if (strcmp(name,"x") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"v") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"f") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"molecule") == 0) return LAMMPS_TAGINT; + if (strcmp(name,"q") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"mu") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"omega") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"angmom") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"torque") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"radius") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"rmass") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"ellipsoid") == 0) return LAMMPS_INT; + if (strcmp(name,"line") == 0) return LAMMPS_INT; + if (strcmp(name,"tri") == 0) return LAMMPS_INT; + if (strcmp(name,"body") == 0) return LAMMPS_INT; + + if (strcmp(name,"vfrac") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"s0") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"x0") == 0) return LAMMPS_DOUBLE2D; + + if (strcmp(name,"spin") == 0) return LAMMPS_INT; + if (strcmp(name,"eradius") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"ervel") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"erforce") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"ervelforce") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"cs") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"csforce") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"vforce") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name,"etag") == 0) return LAMMPS_INT; + + if (strcmp(name,"rho") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"drho") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"esph") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"desph") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"cv") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"vest") == 0) return LAMMPS_DOUBLE2D; + + // USER-MESONT package + if (strcmp(name,"length") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"buckling") == 0) return LAMMPS_INT; + if (strcmp(name,"bond_nt") == 0) return LAMMPS_TAGINT2D; + + if (strcmp(name, "contact_radius") == 0) return LAMMPS_DOUBLE; + if (strcmp(name, "smd_data_9") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name, "smd_stress") == 0) return LAMMPS_DOUBLE2D; + if (strcmp(name, "eff_plastic_strain") == 0) return LAMMPS_DOUBLE; + if (strcmp(name, "eff_plastic_strain_rate") == 0) return LAMMPS_DOUBLE; + if (strcmp(name, "damage") == 0) return LAMMPS_DOUBLE; + + if (strcmp(name,"dpdTheta") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"edpd_temp") == 0) return LAMMPS_DOUBLE; + + // end of customization section + // -------------------------------------------------------------------- + + return -1; +} + /* ---------------------------------------------------------------------- return # of bytes of allocated memory call to avec tallies per-atom vectors diff --git a/src/atom.h b/src/atom.h index 10631d2435..bc69d3b27a 100644 --- a/src/atom.h +++ b/src/atom.h @@ -335,6 +335,7 @@ class Atom : protected Pointers { virtual void sync_modify(ExecutionSpace, unsigned int, unsigned int) {} void *extract(const char *); + int extract_datatype(const char *); inline int* get_map_array() {return map_array;}; inline int get_map_size() {return map_tag_max+1;}; diff --git a/src/library.cpp b/src/library.cpp index 7ea8855e98..452e0c87dc 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -1206,6 +1206,98 @@ void *lammps_extract_atom(void *handle, const char *name) /* ---------------------------------------------------------------------- */ +/** Get data type of internal global LAMMPS variables or arrays. + * + * TODO + * + * \param handle pointer to a previously created LAMMPS instance + * \param name string with the name of the extracted property + * \return integer constant encoding the data type of the property + or -1 if not found. */ + +int lammps_extract_global_datatype(void *handle, const char *name) +{ + LAMMPS *lmp = (LAMMPS *) handle; + + if (strcmp(name,"units") == 0) return LAMMPS_STRING; + if (strcmp(name,"dt") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"ntimestep") == 0) return LAMMPS_BIGINT; + if (strcmp(name,"boxlo") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"boxhi") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"boxxlo") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"boxxhi") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"boxylo") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"boxyhi") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"boxzlo") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"boxzhi") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"periodicity") == 0) return LAMMPS_INT; + if (strcmp(name,"triclinic") == 0) return LAMMPS_INT; + if (strcmp(name,"xy") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"xz") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"yz") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"natoms") == 0) return LAMMPS_BIGINT; + if (strcmp(name,"nbonds") == 0) return LAMMPS_BIGINT; + if (strcmp(name,"nangles") == 0) return LAMMPS_BIGINT; + if (strcmp(name,"ndihedrals") == 0) return LAMMPS_BIGINT; + if (strcmp(name,"nimpropers") == 0) return LAMMPS_BIGINT; + if (strcmp(name,"nlocal") == 0) return LAMMPS_INT; + if (strcmp(name,"nghost") == 0) return LAMMPS_INT; + if (strcmp(name,"nmax") == 0) return LAMMPS_INT; + if (strcmp(name,"ntypes") == 0) return LAMMPS_INT; + + if (strcmp(name,"q_flag") == 0) return LAMMPS_INT; + + // update->atime can be referenced as a pointer + // thermo "timer" data cannot be, since it is computed on request + // lammps_get_thermo() can access all thermo keywords by value + + if (strcmp(name,"atime") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"atimestep") == 0) return LAMMPS_BIGINT; + + // global constants defined by units + + if (strcmp(name,"boltz") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"hplanck") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"mvv2e") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"ftm2v") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"mv2d") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"nktv2p") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"qqr2e") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"qe2f") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"vxmu2f") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"xxt2kmu") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"dielectric") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"qqrd2e") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"e_mass") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"hhmrr2e") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"mvh2r") == 0) return LAMMPS_DOUBLE; + + if (strcmp(name,"angstrom") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"femtosecond") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"qelectron") == 0) return LAMMPS_DOUBLE; + + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/** Get data type of a LAMMPS per-atom property + * + * TODO + * + * \param handle pointer to a previously created LAMMPS instance + * \param name string with the name of the extracted property + * \return integer constant encoding the data type of the property + * or -1 if not found. */ + +int lammps_extract_atom_datatype(void *handle, const char *name) +{ + LAMMPS *lmp = (LAMMPS *) handle; + return lmp->atom->extract_datatype(name); +} + +/* ---------------------------------------------------------------------- */ + /** Create N atoms from list of coordinates * \verbatim embed:rst diff --git a/src/library.h b/src/library.h index 4cf2dd6d19..587ea88a2a 100644 --- a/src/library.h +++ b/src/library.h @@ -40,6 +40,21 @@ #include /* for int64_t */ #endif +/** Data type constants for extracting data from atoms, computes and fixes + * + * Must be kept in sync with the equivalent constants in lammps.py */ + +enum _LMP_DATATYPE_CONST { + LAMMPS_INT = 0, + LAMMPS_INT2D = 1, + LAMMPS_DOUBLE = 2, + LAMMPS_DOUBLE2D = 3, + LAMMPS_BIGINT = 4, + LAMMPS_TAGINT = 5, + LAMMPS_STRING = 6, + LAMMPS_TAGINT2D = 7 +}; + /** Style constants for extracting data from computes and fixes. * * Must be kept in sync with the equivalent constants in lammps.py */ @@ -113,6 +128,9 @@ int lammps_extract_setting(void *handle, const char *keyword); void *lammps_extract_global(void *handle, const char *name); void *lammps_extract_atom(void *handle, const char *name); +int lammps_extract_global_datatype(void *handle, const char *name); +int lammps_extract_atom_datatype(void *handle, const char *name); + #if !defined(LAMMPS_BIGBIG) int lammps_create_atoms(void *handle, int n, int *id, int *type, double *x, double *v, int *image, int bexpand); diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index eb0e1a7df6..d51d2d53e9 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -251,4 +251,90 @@ TEST_F(LibraryProperties, global) EXPECT_EQ((*b_ptr), 2); d_ptr = (double *)lammps_extract_global(lmp, "dt"); EXPECT_DOUBLE_EQ((*d_ptr), 0.1); + int dtype = lammps_extract_global_datatype(lmp, "dt"); + EXPECT_EQ(dtype, LAMMPS_DOUBLE); }; + +class AtomProperties : public ::testing::Test { +protected: + void *lmp; + + AtomProperties(){}; + ~AtomProperties() override{}; + + void SetUp() override + { + const char *args[] = {"LAMMPS_test", "-log", "none", + "-echo", "screen", "-nocite"}; + + char **argv = (char **)args; + int argc = sizeof(args) / sizeof(char *); + + ::testing::internal::CaptureStdout(); + lmp = lammps_open_no_mpi(argc, argv, NULL); + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + EXPECT_THAT(output, StartsWith("LAMMPS (")); + ::testing::internal::CaptureStdout(); + lammps_command(lmp, "region box block 0 2 0 2 0 2"); + lammps_command(lmp, "create_box 1 box"); + lammps_command(lmp, "mass 1 3.0"); + lammps_command(lmp, "create_atoms 1 single 1.0 1.0 1.5"); + lammps_command(lmp, "create_atoms 1 single 0.2 0.1 0.1"); + output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + } + void TearDown() override + { + ::testing::internal::CaptureStdout(); + lammps_close(lmp); + std::string output = ::testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; + lmp = nullptr; + } +}; + +TEST_F(AtomProperties, invalid) +{ + ASSERT_EQ(lammps_extract_atom(lmp, "UNKNOWN"), nullptr); +} + +TEST_F(AtomProperties, mass) +{ + EXPECT_EQ(lammps_extract_atom_datatype(lmp, "mass"), LAMMPS_DOUBLE); + double * mass = (double *)lammps_extract_atom(lmp, "mass"); + ASSERT_NE(mass, nullptr); + ASSERT_DOUBLE_EQ(mass[1], 3.0); +} + +TEST_F(AtomProperties, id) +{ + EXPECT_EQ(lammps_extract_atom_datatype(lmp, "id"), LAMMPS_TAGINT); + LAMMPS_NS::tagint * id = (LAMMPS_NS::tagint *)lammps_extract_atom(lmp, "id"); + ASSERT_NE(id, nullptr); + ASSERT_EQ(id[0], 1); + ASSERT_EQ(id[1], 2); +} + +TEST_F(AtomProperties, type) +{ + EXPECT_EQ(lammps_extract_atom_datatype(lmp, "type"), LAMMPS_INT); + int * type = (LAMMPS_NS::tagint *)lammps_extract_atom(lmp, "type"); + ASSERT_NE(type, nullptr); + ASSERT_EQ(type[0], 1); + ASSERT_EQ(type[1], 1); +} + +TEST_F(AtomProperties, position) +{ + EXPECT_EQ(lammps_extract_atom_datatype(lmp, "x"), LAMMPS_DOUBLE2D); + double ** x = (double **)lammps_extract_atom(lmp, "x"); + ASSERT_NE(x, nullptr); + EXPECT_DOUBLE_EQ(x[0][0], 1.0); + EXPECT_DOUBLE_EQ(x[0][1], 1.0); + EXPECT_DOUBLE_EQ(x[0][2], 1.5); + EXPECT_DOUBLE_EQ(x[1][0], 0.2); + EXPECT_DOUBLE_EQ(x[1][1], 0.1); + EXPECT_DOUBLE_EQ(x[1][2], 0.1); +}