diff --git a/fortran/lammps.f90 b/fortran/lammps.f90 index 6188385958..3eb4f54762 100644 --- a/fortran/lammps.f90 +++ b/fortran/lammps.f90 @@ -2134,7 +2134,7 @@ CONTAINS buf_size = LEN(buffer, KIND=c_int) + 1_c_int Ccategory = f2c_string(category) Cptr = C_LOC(Cbuffer) - success = lammps_style_name(self%handle, Ccategory, idx, Cptr, buf_size) + success = lammps_style_name(self%handle, Ccategory, idx - 1, Cptr, buf_size) IF (success == 1_c_int) THEN buffer = array2string(Cbuffer) ELSE @@ -2185,7 +2185,7 @@ CONTAINS Ccategory = f2c_string(category) buf_size = LEN(buffer, KIND=c_int) Cptr = C_LOC(Cbuffer(1)) - success = lammps_id_name(self%handle, Ccategory, idx, Cptr, buf_size) + success = lammps_id_name(self%handle, Ccategory, idx - 1, Cptr, buf_size) IF (success /= 0) THEN buffer = array2string(Cbuffer) ELSE @@ -2206,7 +2206,7 @@ CONTAINS buf_size = MIN(LEN(stylebuf, KIND=c_int), LEN(namebuf, KIND=c_int)) Cstylebuf = lammps_malloc(INT(buf_size, KIND=c_size_t)) Cnamebuf = lammps_malloc(INT(buf_size, KIND=c_size_t)) - success = lammps_plugin_name(idx, Cstylebuf, Cnamebuf, buf_size) + success = lammps_plugin_name(idx - 1, Cstylebuf, Cnamebuf, buf_size) IF (success /= 0_c_int) THEN stylebuf = c2f_string(Cstylebuf) namebuf = c2f_string(Cnamebuf) diff --git a/unittest/fortran/test_fortran_configuration.f90 b/unittest/fortran/test_fortran_configuration.f90 index 1b9844a415..3c95249326 100644 --- a/unittest/fortran/test_fortran_configuration.f90 +++ b/unittest/fortran/test_fortran_configuration.f90 @@ -308,3 +308,166 @@ FUNCTION f_lammps_style_count(ptr) BIND(C) END DO f_lammps_style_count = lmp%style_count(category) END FUNCTION f_lammps_style_count + +FUNCTION f_lammps_style_name(category_ptr, idx) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_ptr, c_int, c_char, c_size_t, & + C_F_POINTER + USE LIBLAMMPS + USE keepstuff, ONLY : lmp, c_strlen, f2c_string + IMPLICIT NONE + TYPE(c_ptr), INTENT(IN), VALUE :: category_ptr + INTEGER(c_int), INTENT(IN), VALUE :: idx + TYPE(c_ptr) :: f_lammps_style_name + CHARACTER(LEN=1, KIND=c_char), DIMENSION(:), POINTER :: C_category + INTEGER(c_size_t) :: length, i + CHARACTER(LEN=:), ALLOCATABLE :: category + CHARACTER(LEN=100) :: buffer + + length = c_strlen(category_ptr) + CALL C_F_POINTER(category_ptr, C_category, [length]) + ALLOCATE(CHARACTER(LEN=length) :: category) + DO i = 1, length + category(i:i) = C_category(i) + END DO + CALL lmp%style_name(category, idx, buffer) + f_lammps_style_name = f2c_string(buffer) +END FUNCTION f_lammps_style_name + +SUBROUTINE f_setup_has_id() BIND(C) + USE keepstuff, ONLY : lmp + IMPLICIT NONE + CHARACTER(LEN=100), DIMENSION(*), PARAMETER :: setup_commands = & + [CHARACTER(LEN=100) :: 'units lj', & + 'region simbox block 0 2 0 3 0 4 units box', & + 'create_box 1 simbox', & + 'create_atoms 1 single 0.01 0.01 0.01 units box', & + 'create_atoms 1 single 1.0 1.0 1.0 units box', & + 'pair_style lj/cut 2.5', & + 'pair_coeff * * 1.0 1.0', & + 'mass * 1.0', & + 'compute COM all com', & + 'dump 1 all atom 1000 dump.tmp', & + 'fix 1 all nve', & + 'group one id 1', & + 'variable pi equal acos(-1)', & + !'molecule A file1 file2', & + 'run 0' & + ] + + CALL lmp%commands_list(setup_commands) +END SUBROUTINE + +FUNCTION f_lammps_has_id(Ccategory, Cname) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_ptr, c_int, c_size_t, c_char, & + C_F_POINTER + USE keepstuff, ONLY : lmp, c_strlen + IMPLICIT NONE + TYPE(c_ptr), VALUE :: Ccategory, Cname + INTEGER(c_int) :: f_lammps_has_id + INTEGER(c_size_t) :: len_cat, len_name, i + CHARACTER(LEN=:), ALLOCATABLE :: category, name + CHARACTER(LEN=1, KIND=c_char), DIMENSION(:), POINTER :: Fcategory, Fname + LOGICAL :: has_id + + len_cat = c_strlen(Ccategory) + len_name = c_strlen(Cname) + CALL C_F_POINTER(Ccategory, Fcategory, [len_cat]) + CALL C_F_POINTER(Cname, Fname, [len_name]) + ALLOCATE(CHARACTER(LEN=len_cat) :: category) + ALLOCATE(CHARACTER(LEN=len_name) :: name) + DO i = 1, len_cat + category(i:i) = Fcategory(i) + END DO + DO i = 1, len_name + name(i:i) = Fname(i) + END DO + has_id = lmp%has_id(category, name) + IF (has_id) THEN + f_lammps_has_id = 1_c_int + ELSE + f_lammps_has_id = 0_c_int + END IF +END FUNCTION f_lammps_has_id + +FUNCTION f_lammps_id_count(Ccategory) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_ptr, c_int, c_size_t, c_char, & + C_F_POINTER + USE keepstuff, ONLY : lmp, c_strlen + IMPLICIT NONE + TYPE(c_ptr), VALUE :: Ccategory + INTEGER(c_int) :: f_lammps_id_count + INTEGER(c_size_t) :: len_cat, i + CHARACTER(LEN=:), ALLOCATABLE :: category + CHARACTER(LEN=1, KIND=c_char), DIMENSION(:), POINTER :: Fcategory + + len_cat = c_strlen(Ccategory) + CALL C_F_POINTER(Ccategory, Fcategory, [len_cat]) + ALLOCATE(CHARACTER(LEN=len_cat) :: category) + DO i = 1, len_cat + category(i:i) = Fcategory(i) + END DO + f_lammps_id_count = lmp%id_count(category) +END FUNCTION f_lammps_id_count + +FUNCTION f_lammps_id_name(Ccategory, idx) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_ptr, c_int, c_size_t, c_char, & + C_F_POINTER + USE keepstuff, ONLY : lmp, c_strlen, f2c_string + IMPLICIT NONE + TYPE(c_ptr), VALUE :: Ccategory + INTEGER(c_int), VALUE :: idx + TYPE(c_ptr) :: f_lammps_id_name + INTEGER(c_size_t) :: len_cat, i + CHARACTER(LEN=:), ALLOCATABLE :: category + CHARACTER(LEN=1, KIND=c_char), DIMENSION(:), POINTER :: Fcategory + CHARACTER(LEN=100) :: buffer + + len_cat = c_strlen(Ccategory) + CALL C_F_POINTER(Ccategory, Fcategory, [len_cat]) + ALLOCATE(CHARACTER(LEN=len_cat) :: category) + DO i = 1, len_cat + category(i:i) = Fcategory(i) + END DO + CALL lmp%id_name(category, idx, buffer) + f_lammps_id_name = f2c_string(buffer) +END FUNCTION f_lammps_id_name + +FUNCTION f_lammps_plugin_count() BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_int + USE keepstuff, ONLY : lmp + INTEGER(c_int) :: f_lammps_plugin_count + + f_lammps_plugin_count = lmp%plugin_count(); +END FUNCTION f_lammps_plugin_count + +FUNCTION f_lammps_plugin_name(idx, Cstyle, Cname) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_ptr, c_int, c_size_t, c_char, & + C_F_POINTER + USE keepstuff, ONLY : lmp, c_strlen, f2c_string + IMPLICIT NONE + INTEGER(c_int), INTENT(IN), VALUE :: idx + TYPE(c_ptr), INTENT(IN), VALUE :: Cstyle, Cname + CHARACTER(LEN=1, KIND=c_char), DIMENSION(:), POINTER :: Fstyle, Fname + INTEGER(c_int) :: f_lammps_plugin_name + CHARACTER(LEN=100) :: style, name + INTEGER(c_size_t) :: len_style, len_name, i + LOGICAL :: all_are_identical + + CALL lmp%plugin_name(idx, style, name) + len_style = c_strlen(Cstyle) + len_name = c_strlen(Cname) + CALL C_F_POINTER(Cstyle, Fstyle, [len_style]) + CALL C_F_POINTER(Cname, Fname, [len_name]) + all_are_identical = .TRUE. + DO i = 1, len_style + all_are_identical = all_are_identical .AND. (style(i:i) == Fstyle(i)) + END DO + DO i = 1, len_name + all_are_identical = all_are_identical .AND. (name(i:i) == Fname(i)) + END DO + IF (all_are_identical) THEN + f_lammps_plugin_name = 1_c_int + ELSE + f_lammps_plugin_name = 0_c_int + END IF +END FUNCTION f_lammps_plugin_name diff --git a/unittest/fortran/wrap_configuration.cpp b/unittest/fortran/wrap_configuration.cpp index 396e1f3097..24a095a979 100644 --- a/unittest/fortran/wrap_configuration.cpp +++ b/unittest/fortran/wrap_configuration.cpp @@ -4,6 +4,10 @@ #include "library.h" #include "info.h" +#ifdef LMP_PLUGIN +#include "plugin.h" +#endif + #include #include "gmock/gmock.h" @@ -29,7 +33,13 @@ int f_lammps_has_gpu(); char* f_lammps_get_gpu_info(size_t); int f_lammps_has_style(const char*, const char*); int f_lammps_style_count(const char*); -int f_lammps_style_name(); +char* f_lammps_style_name(const char*, int); +void f_setup_has_id(); +int f_lammps_has_id(const char*, const char*); +int f_lammps_id_count(const char*); +char* f_lammps_id_name(const char*, int); +int f_lammps_plugin_count(); +int f_lammps_plugin_name(); } namespace LAMMPS_NS { @@ -38,6 +48,9 @@ using ::testing::ContainsRegex; class LAMMPS_configuration : public ::testing::Test { protected: LAMMPS *lmp; + std::vector style_category = {"atom","integrate","minimize", + "pair","bond","angle","dihedral","improper","kspace","fix","compute", + "region","dump","command"}; void SetUp() override { @@ -145,7 +158,6 @@ TEST_F(LAMMPS_configuration, package_name) i++; } }; - TEST_F(LAMMPS_configuration, installed_packages) { const char *package_name; @@ -220,17 +232,15 @@ TEST_F(LAMMPS_configuration, get_gpu_info) TEST_F(LAMMPS_configuration, has_style) { - std::vector category = {"atom","integrate","minimize","pair", - "bond","angle","dihedral","improper","kspace","fix","compute","region", - "dump","command"}; Info info(lmp); - for (int c = 0; c < category.size(); c++) + for (int c = 0; c < style_category.size(); c++) { - std::vector name = info.get_available_styles(category[c]); + std::vector name = + info.get_available_styles(style_category[c]); for (int s = 0; s < name.size(); s++) { - EXPECT_EQ(f_lammps_has_style(category[c].c_str(), - name[s].c_str()), info.has_style(category[c], name[s])); + EXPECT_EQ(f_lammps_has_style(style_category[c].c_str(), + name[s].c_str()), info.has_style(style_category[c], name[s])); } } EXPECT_EQ(f_lammps_has_style("atom","none"), 0); @@ -239,14 +249,127 @@ TEST_F(LAMMPS_configuration, has_style) TEST_F(LAMMPS_configuration, style_count) { Info info(lmp); - std::vector category = {"atom","integrate","minimize","pair", - "bond","angle","dihedral","improper","kspace","fix","compute","region", - "dump","command"}; - for (int i = 0; i < category.size(); i++) + for (int i = 0; i < style_category.size(); i++) + EXPECT_EQ(f_lammps_style_count(style_category[i].c_str()), + info.get_available_styles(style_category[i].c_str()).size()); +}; + +TEST_F(LAMMPS_configuration, style_name) { - EXPECT_EQ(f_lammps_style_count(category[i].c_str()), - info.get_available_styles(category[i].c_str()).size()); -} + char *buffer; + Info info(lmp); + for (int c = 0; c < style_category.size(); c++) { + int nnames = f_lammps_style_count(style_category[c].c_str()); + auto styles = info.get_available_styles(style_category[c]); + for (int i = 0; i < nnames; i++) { + buffer = f_lammps_style_name(style_category[c].c_str(), i + 1); + EXPECT_STREQ(buffer, styles[i].c_str()); + std::free(buffer); + } + } + +}; + +TEST_F(LAMMPS_configuration, has_id) +{ + f_setup_has_id(); + EXPECT_EQ(f_lammps_has_id("compute","com"), 0); + EXPECT_EQ(f_lammps_has_id("compute","COM"), 1); + EXPECT_EQ(f_lammps_has_id("dump","atom"), 0); + EXPECT_EQ(f_lammps_has_id("dump","1"), 1); + EXPECT_EQ(f_lammps_has_id("fix","nve"), 0); + EXPECT_EQ(f_lammps_has_id("fix","1"), 1); + EXPECT_EQ(f_lammps_has_id("group","one"), 1); + EXPECT_EQ(f_lammps_has_id("group","all"), 1); + // Skip this one (we're testing thoroughly enough; molecules require files) + //EXPECT_EQ(f_lammps_has_id("molecule") + EXPECT_EQ(f_lammps_has_id("region","simbox"), 1); + EXPECT_EQ(f_lammps_has_id("region","box"), 0); + EXPECT_EQ(f_lammps_has_id("variable","pi"), 1); + EXPECT_EQ(f_lammps_has_id("variable","PI"), 0); +}; + +TEST_F(LAMMPS_configuration, id_count) +{ + f_setup_has_id(); + // computes: thermo_temp, thermo_press, thermo_pe, COM + EXPECT_EQ(f_lammps_id_count("compute"), 4); + EXPECT_EQ(f_lammps_id_count("dump"), 1); // only the one we defined + EXPECT_EQ(f_lammps_id_count("fix"), 1); // only the one we defined + EXPECT_EQ(f_lammps_id_count("group"), 2); // "one" and "all" + EXPECT_EQ(f_lammps_id_count("molecule"), 0); + EXPECT_EQ(f_lammps_id_count("region"), 1); // onle the one we created + EXPECT_EQ(f_lammps_id_count("variable"), 3); // "zpos", "x", and "pi" +}; + +TEST_F(LAMMPS_configuration, id_name) +{ + f_setup_has_id(); + char *name; + int nnames = f_lammps_id_count("compute"); + EXPECT_EQ(nnames, 4); + + name = f_lammps_id_name("compute",1); + EXPECT_STREQ(name, "thermo_temp"); + std::free(name); + + name = f_lammps_id_name("compute",2); + EXPECT_STREQ(name, "thermo_press"); + std::free(name); + + name = f_lammps_id_name("compute",3); + EXPECT_STREQ(name, "thermo_pe"); + std::free(name); + + name = f_lammps_id_name("compute",4); + EXPECT_STREQ(name, "COM"); + std::free(name); + + name = f_lammps_id_name("dump",1); + EXPECT_STREQ(name, "1"); + std::free(name); + + name = f_lammps_id_name("fix",1); + EXPECT_STREQ(name, "1"); + std::free(name); + + name = f_lammps_id_name("group",1); + EXPECT_STREQ(name, "all"); + std::free(name); + + name = f_lammps_id_name("group",2); + EXPECT_STREQ(name, "one"); + std::free(name); + + name = f_lammps_id_name("region",1); + EXPECT_STREQ(name, "simbox"); + std::free(name); + + name = f_lammps_id_name("variable",1); + EXPECT_STREQ(name, "zpos"); + std::free(name); + + name = f_lammps_id_name("variable",2); + EXPECT_STREQ(name, "x"); + std::free(name); + + name = f_lammps_id_name("variable",3); + EXPECT_STREQ(name, "pi"); + std::free(name); + +}; + +TEST_F(LAMMPS_configuration, plugins) +{ +#ifndef LMP_PLUGIN + GTEST_SKIP(); +#else + int nplugins = f_lammps_plugin_count(); + for (int n = 0; n < nplugins; n++) { + lammpsplugin_t *plugin = plugin_get_info(n); + EXPECT_EQ(f_lammps_plugin_name(n+1, plugin->style, plugin->name), 1); + } +#endif }; } // namespace LAMMPS_NS