diff --git a/fortran/lammps.f90 b/fortran/lammps.f90 index eb83ce3058..7fe5e7fd8a 100644 --- a/fortran/lammps.f90 +++ b/fortran/lammps.f90 @@ -193,6 +193,7 @@ MODULE LIBLAMMPS assign_doublemat_to_lammps_fix_data ! Variables, too MODULE PROCEDURE assign_double_to_lammps_variable_data, & + assign_doublevec_to_lammps_variable_data, & assign_string_to_lammps_variable_data END INTERFACE diff --git a/unittest/fortran/CMakeLists.txt b/unittest/fortran/CMakeLists.txt index 796416b7fb..8aaff70041 100644 --- a/unittest/fortran/CMakeLists.txt +++ b/unittest/fortran/CMakeLists.txt @@ -70,10 +70,10 @@ if(CMAKE_Fortran_COMPILER) add_test(NAME FortranExtractFix COMMAND test_fortran_extract_fix) add_executable(test_fortran_extract_variable wrap_extract_variable.cpp test_fortran_extract_variable.f90) + target_compile_definitions(test_fortran_extract_variable PRIVATE -DTEST_INPUT_FOLDER=${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(test_fortran_extract_variable PRIVATE flammps lammps MPI::MPI_Fortran GTest::GTestMain) add_test(NAME FortranExtractVariable COMMAND test_fortran_extract_variable) - else() message(STATUS "Skipping Tests for the LAMMPS Fortran Module: no Fortran compiler") endif() diff --git a/unittest/fortran/greetings.txt b/unittest/fortran/greetings.txt index cb547f0adf..9cccccc35d 100644 --- a/unittest/fortran/greetings.txt +++ b/unittest/fortran/greetings.txt @@ -1,8 +1,8 @@ hello -god dag +god_dag hola bonjour -guten Tag +guten_Tag konnichiwa shalom salve diff --git a/unittest/fortran/test_fortran_extract_variable.f90 b/unittest/fortran/test_fortran_extract_variable.f90 index fda68b0cad..46a4609e08 100644 --- a/unittest/fortran/test_fortran_extract_variable.f90 +++ b/unittest/fortran/test_fortran_extract_variable.f90 @@ -29,18 +29,42 @@ CONTAINS FUNCTION absolute_path(filename) CHARACTER(LEN=:), ALLOCATABLE :: absolute_path CHARACTER(LEN=*), INTENT(IN) :: filename - CHARACTER(LEN=:), ALLOCATABLE :: test_input_directory + CHARACTER(LEN=256) :: test_input_directory -print *, 'GOT HERE! filename is ', filename test_input_directory = lmp%extract_variable('input_dir') -print *, ' test_input_directory is ', test_input_directory - absolute_path = test_input_directory // '/' // TRIM(filename) + absolute_path = TRIM(test_input_directory) // '/' // TRIM(filename) END FUNCTION absolute_path + FUNCTION f2c_string(f_string) RESULT(ptr) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_char, c_ptr, c_size_t, & + c_null_char, C_F_POINTER + CHARACTER(LEN=*), INTENT(IN) :: f_string + CHARACTER(LEN=1, KIND=c_char), POINTER :: c_string(:) + TYPE(c_ptr) :: ptr + INTEGER(c_size_t) :: i, n + + INTERFACE + FUNCTION lammps_malloc(size) BIND(C, name='malloc') + IMPORT :: c_ptr, c_size_t + IMPLICIT NONE + INTEGER(c_size_t), VALUE :: size + TYPE(c_ptr) :: lammps_malloc + END FUNCTION lammps_malloc + END INTERFACE + + n = LEN_TRIM(f_string) + ptr = lammps_malloc(n+1) + CALL C_F_POINTER(ptr, c_string, [1]) + DO i=1, n + c_string(i) = f_string(i:i) + END DO + c_string(n+1) = c_null_char + END FUNCTION f2c_string + END MODULE keepvar FUNCTION f_lammps_with_C_args(argc, argv) BIND(C) - USE ISO_C_BINDING, ONLY: c_ptr, c_char, c_int, c_size_t, c_f_pointer + USE ISO_C_BINDING, ONLY: c_ptr, c_char, c_int, c_size_t, C_F_POINTER USE liblammps USE keepvar, ONLY: lmp IMPLICIT NONE @@ -87,33 +111,36 @@ SUBROUTINE f_lammps_close() BIND(C) END SUBROUTINE f_lammps_close SUBROUTINE f_lammps_setup_extract_variable () BIND(C) - USE LIBLAMMPS - USE keepvar, ONLY : lmp, demo_input, cont_input, pair_input, absolute_path - IMPLICIT NONE + USE LIBLAMMPS + USE keepvar, ONLY : lmp, demo_input, cont_input, pair_input, absolute_path + IMPLICIT NONE - CALL lmp%commands_list(demo_input) - CALL lmp%commands_list(cont_input) - CALL lmp%commands_list(pair_input) - CALL lmp%command('variable idx index "hello" "goodbye"') - CALL lmp%command('variable lp loop 10') - CALL lmp%command('variable lp_pad loop 10 pad') - !CALL lmp%command('variable wld world "group1" "group2" "group3"') - CALL lmp%command('variable wld world "group1"') - CALL lmp%command('variable uni universe "universe1" "universeA"') - CALL lmp%command('variable ulp uloop 2') - CALL lmp%command('variable str index "this is a string"') - CALL lmp%command('variable fmt format lp %.6G') - CALL lmp%command('variable fmt_pad format lp %0.6g') - CALL lmp%command('variable shell getenv SHELL') -! CALL lmp%command('variable greet file ' // absolute_path('greetings.txt')) -! CALL lmp%command('variable atfile atomfile ' // absolute_path('atomdata.txt') - IF ( lmp%config_has_package('PYTHON') ) THEN - CALL lmp%command('variable py python square_it') - END IF - CALL lmp%command('variable time timer') - CALL lmp%command('variable int internal 4') - CALL lmp%command("variable nat equal count(all)") - CALL lmp%command("variable ts equal step") + CALL lmp%command('atom_modify map array') + CALL lmp%commands_list(demo_input) + CALL lmp%commands_list(cont_input) + CALL lmp%commands_list(pair_input) + CALL lmp%command('variable idx index "hello" "goodbye"') + CALL lmp%command('variable lp loop 10') + CALL lmp%command('variable lp_pad loop 10 pad') + CALL lmp%command('variable wld world "group1"') + CALL lmp%command('variable uni universe "universe1" "universeA"') + CALL lmp%command('variable ulp uloop 2') + CALL lmp%command('variable str string "this is a string"') + CALL lmp%command('variable ex equal exp(v_lp)') + CALL lmp%command('variable fmt format ex %.6G') + CALL lmp%command('variable fmt_pad format ex %08.6g') + ! USERNAME should exist on all platforms (incl. Windows) + CALL lmp%command('variable username getenv USERNAME') + CALL lmp%command('variable greeting file ' // absolute_path('greetings.txt')) + CALL lmp%command('variable atfile atomfile ' & + // absolute_path('atomdata.txt')) + IF ( lmp%config_has_package('PYTHON') ) THEN + CALL lmp%command('variable py python square_it') + END IF + CALL lmp%command('variable time timer') + CALL lmp%command('variable int internal 4') + CALL lmp%command("variable nat equal count(all)") + CALL lmp%command("variable ts equal step") END SUBROUTINE f_lammps_setup_extract_variable FUNCTION f_lammps_extract_variable_index_1 () BIND(C) @@ -159,3 +186,128 @@ FUNCTION f_lammps_extract_variable_loop () BIND(C) loop = lmp%extract_variable('lp') READ(loop,*) f_lammps_extract_variable_loop END FUNCTION f_lammps_extract_variable_loop + +FUNCTION f_lammps_extract_variable_loop_pad () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_loop_pad + CHARACTER(LEN=20) :: loop + + loop = lmp%extract_variable('lp_pad') + f_lammps_extract_variable_loop_pad = f2c_string(loop) +END FUNCTION f_lammps_extract_variable_loop_pad + +FUNCTION f_lammps_extract_variable_world () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_world + CHARACTER(LEN=20) :: world + + world = lmp%extract_variable('wld') + f_lammps_extract_variable_world = f2c_string(world) +END FUNCTION f_lammps_extract_variable_world + +FUNCTION f_lammps_extract_variable_universe () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_universe + CHARACTER(LEN=20) :: universe + + universe = lmp%extract_variable('uni') + f_lammps_extract_variable_universe = f2c_string(universe) +END FUNCTION f_lammps_extract_variable_universe + +FUNCTION f_lammps_extract_variable_uloop () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int + USE LIBLAMMPS + USE keepvar, ONLY : lmp + IMPLICIT NONE + INTEGER(c_int) :: f_lammps_extract_variable_uloop + CHARACTER(LEN=80) :: uloop + + uloop = lmp%extract_variable('ulp') + READ(uloop,*) f_lammps_extract_variable_uloop +END FUNCTION f_lammps_extract_variable_uloop + +FUNCTION f_lammps_extract_variable_string () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_string + CHARACTER(LEN=20) :: string + + string = lmp%extract_variable('str') + f_lammps_extract_variable_string = f2c_string(string) +END FUNCTION f_lammps_extract_variable_string + +FUNCTION f_lammps_extract_variable_format () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_format + CHARACTER(LEN=20) :: form + + form = lmp%extract_variable('fmt') + f_lammps_extract_variable_format = f2c_string(form) +END FUNCTION f_lammps_extract_variable_format + +FUNCTION f_lammps_extract_variable_format_pad () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_format_pad + CHARACTER(LEN=20) :: form + + form = lmp%extract_variable('fmt_pad') + f_lammps_extract_variable_format_pad = f2c_string(form) +END FUNCTION f_lammps_extract_variable_format_pad + +FUNCTION f_lammps_extract_variable_getenv () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_getenv + CHARACTER(LEN=20) :: string + + string = lmp%extract_variable('username') + f_lammps_extract_variable_getenv = f2c_string(string) +END FUNCTION f_lammps_extract_variable_getenv + +FUNCTION f_lammps_extract_variable_file () BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_ptr + USE LIBLAMMPS + USE keepvar, ONLY : lmp, f2c_string + IMPLICIT NONE + TYPE(c_ptr) :: f_lammps_extract_variable_file + CHARACTER(LEN=40) :: string + + string = lmp%extract_variable('greeting') + f_lammps_extract_variable_file = f2c_string(string) +END FUNCTION f_lammps_extract_variable_file + +FUNCTION f_lammps_extract_variable_atomfile(i) BIND(C) + USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int, C_double + USE LIBLAMMPS + USE keepvar, ONLY : lmp + IMPLICIT NONE + INTEGER(c_int), INTENT(IN), VALUE :: i + REAL(c_double) :: f_lammps_extract_variable_atomfile + REAL(c_double), DIMENSION(:), POINTER :: atom_data + + atom_data = lmp%extract_variable('atfile') +print*, 'TESTING: atom_data is', atom_data + f_lammps_extract_variable_atomfile = atom_data(i) +END FUNCTION f_lammps_extract_variable_atomfile diff --git a/unittest/fortran/wrap_extract_variable.cpp b/unittest/fortran/wrap_extract_variable.cpp index 0e3ffecfac..3d139c222a 100644 --- a/unittest/fortran/wrap_extract_variable.cpp +++ b/unittest/fortran/wrap_extract_variable.cpp @@ -1,13 +1,14 @@ // unit tests for extracting compute data from a LAMMPS instance through the // Fortran wrapper -#include #include "lammps.h" #include "library.h" #include #include +#include #include #include +#include #include "gtest/gtest.h" @@ -22,18 +23,19 @@ void f_lammps_setup_extract_variable(); int f_lammps_extract_variable_index_1(); int f_lammps_extract_variable_index_2(); int f_lammps_extract_variable_loop(); -double f_lammps_extract_variable_loop_pad(); -void f_lammps_setup_extract_variable_world(); -void f_lammps_setup_extract_variable_universe(); -int f_lammps_setup_extract_variable_uloop(); -void f_lammps_setup_extract_variable_string(); -void f_lammps_setup_extract_variable_format(); -void f_lammps_setup_extract_variable_getenv(); -void f_lammps_setup_extract_variable_file(); -void f_lammps_setup_extract_variable_atomfile(); -double f_lammps_setup_extract_variable_python(); -double f_lammps_setup_extract_variable_timer(); -double f_lammps_setup_extract_variable_internal(); +char* f_lammps_extract_variable_loop_pad(); +char* f_lammps_extract_variable_world(); +char* f_lammps_extract_variable_universe(); +int f_lammps_extract_variable_uloop(); +char* f_lammps_extract_variable_string(); +char* f_lammps_extract_variable_format(); +char* f_lammps_extract_variable_format_pad(); +char* f_lammps_extract_variable_getenv(); +char* f_lammps_extract_variable_file(); +double f_lammps_extract_variable_atomfile(int); +double f_lammps_extract_variable_python(); +double f_lammps_extract_variable_timer(); +double f_lammps_extract_variable_internal(); double f_lammps_extract_variable_equal_natoms(); double f_lammps_extract_variable_equal_dt(); double f_lammps_extract_variable_vector(int); @@ -55,7 +57,6 @@ protected: char** argv = (char**) args; int argc = sizeof(args) / sizeof(const char*); ::testing::internal::CaptureStdout(); -std::fprintf(stderr,"THIS IS A TEST\n"); lmp = (LAMMPS_NS::LAMMPS*)f_lammps_with_c_args(argc, argv); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.substr(0, 8).c_str(), "LAMMPS ("); @@ -83,5 +84,120 @@ TEST_F(LAMMPS_extract_variable, index) TEST_F(LAMMPS_extract_variable, loop) { f_lammps_setup_extract_variable(); - EXPECT_EQ(f_lammps_extract_variable_loop(), 1); + int i; + for ( i = 1; i <= 10; i++ ) { + EXPECT_EQ(f_lammps_extract_variable_loop(), i); + lammps_command(lmp, "next lp"); + } +}; + +TEST_F(LAMMPS_extract_variable, loop_pad) +{ + f_lammps_setup_extract_variable(); + int i; + char str[10]; + char* fstr; + for ( i = 1; i <= 10; i++ ) { + std::sprintf(str,"%02d",i); + fstr = f_lammps_extract_variable_loop_pad(); + EXPECT_STREQ(fstr, str); + std::free(fstr); + lammps_command(lmp, "next lp_pad"); + } +}; + +TEST_F(LAMMPS_extract_variable, world) +{ + f_lammps_setup_extract_variable(); + char* fstr = f_lammps_extract_variable_world(); + EXPECT_STREQ(fstr, "group1"); + std::free(fstr); +}; + +TEST_F(LAMMPS_extract_variable, universe) +{ + f_lammps_setup_extract_variable(); + char* fstr = f_lammps_extract_variable_universe(); + EXPECT_STREQ(fstr, "universe1"); + std::free(fstr); +}; + +TEST_F(LAMMPS_extract_variable, uloop) +{ + f_lammps_setup_extract_variable(); + EXPECT_EQ(f_lammps_extract_variable_uloop(), 1); +}; + +TEST_F(LAMMPS_extract_variable, string) +{ + f_lammps_setup_extract_variable(); + char* fstr = f_lammps_extract_variable_string(); + EXPECT_STREQ(fstr, "this is a string"); + std::free(fstr); +}; + +TEST_F(LAMMPS_extract_variable, format) +{ + f_lammps_setup_extract_variable(); + int i; + char str[10]; + char* fstr; + for ( i = 1; i <= 10; i++ ) { + std::sprintf(str,"%.6G",std::exp(i)); + fstr = f_lammps_extract_variable_format(); + EXPECT_STREQ(fstr, str); + std::free(fstr); + lammps_command(lmp, "next lp"); + } +}; + +TEST_F(LAMMPS_extract_variable, format_pad) +{ + f_lammps_setup_extract_variable(); + int i; + char str[10]; + char* fstr; + for ( i = 1; i <= 10; i++ ) { + std::sprintf(str,"%08.6G",std::exp(i)); + fstr = f_lammps_extract_variable_format_pad(); + EXPECT_STREQ(fstr, str); + std::free(fstr); + lammps_command(lmp, "next lp"); + } +}; + +TEST_F(LAMMPS_extract_variable, getenv) +{ + f_lammps_setup_extract_variable(); + char *env = std::getenv("USERNAME"); + char *fenv = f_lammps_extract_variable_getenv(); + EXPECT_STREQ(fenv, env); + std::free(fenv); +}; + +TEST_F(LAMMPS_extract_variable, file) +{ + f_lammps_setup_extract_variable(); + int i; + const char* str[9] = {"hello","god_dag","hola","bonjour","guten_Tag", + "konnichiwa","shalom","salve","goedendag"}; + char* fstr; + for ( i = 0; i < 9; i++ ) { + fstr = f_lammps_extract_variable_file(); + EXPECT_STREQ(fstr, str[i]); + std::free(fstr); + lammps_command(lmp, "next greeting"); + } +}; + +TEST_F(LAMMPS_extract_variable, atomfile) +{ + f_lammps_setup_extract_variable(); + EXPECT_DOUBLE_EQ(f_lammps_extract_variable_atomfile(1), 5.2); + EXPECT_DOUBLE_EQ(f_lammps_extract_variable_atomfile(2), 1.6); + EXPECT_DOUBLE_EQ(f_lammps_extract_variable_atomfile(3), -1.4); +/* lammps_command(lmp, "next atfile"); + EXPECT_DOUBLE_EQ(f_lammps_extract_variable_atomfile(1), -1.1); + EXPECT_DOUBLE_EQ(f_lammps_extract_variable_atomfile(2), 0.0); + EXPECT_DOUBLE_EQ(f_lammps_extract_variable_atomfile(3), 2.5); */ };