From fa654f2270233fac4b586afa5c95d8363ce14917 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 16 Jul 2021 23:41:25 -0400 Subject: [PATCH] add support for set_vector for fix external in c-library, python and unittest --- .gitignore | 1 + doc/src/Library_utility.rst | 24 ++++++ python/lammps/core.py | 37 ++++++++ src/library.cpp | 90 ++++++++++++++++++-- src/library.h | 2 +- unittest/c-library/test_library_external.cpp | 31 +++++-- unittest/python/python-fix-external.py | 19 ++++- 7 files changed, 188 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 14d9dbebc9..b71a750c7d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ Thumbs.db /build* /CMakeCache.txt /CMakeFiles/ +/Testing /Makefile /cmake_install.cmake /lmp diff --git a/doc/src/Library_utility.rst b/doc/src/Library_utility.rst index 2748d418b6..32fac6bcc8 100644 --- a/doc/src/Library_utility.rst +++ b/doc/src/Library_utility.rst @@ -8,7 +8,11 @@ functions. They do not directly call the LAMMPS library. - :cpp:func:`lammps_decode_image_flags` - :cpp:func:`lammps_set_fix_external_callback` - :cpp:func:`lammps_fix_external_set_energy_global` +- :cpp:func:`lammps_fix_external_set_energy_peratom` - :cpp:func:`lammps_fix_external_set_virial_global` +- :cpp:func:`lammps_fix_external_set_virial_peratom` +- :cpp:func:`lammps_fix_external_set_vector_length` +- :cpp:func:`lammps_fix_external_set_vector` - :cpp:func:`lammps_free` - :cpp:func:`lammps_is_running` - :cpp:func:`lammps_force_timeout` @@ -43,11 +47,31 @@ where such memory buffers were allocated that require the use of ----------------------- +.. doxygenfunction:: lammps_fix_external_set_energy_peratom + :project: progguide + +----------------------- + .. doxygenfunction:: lammps_fix_external_set_virial_global :project: progguide ----------------------- +.. doxygenfunction:: lammps_fix_external_set_virial_peratom + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_fix_external_set_vector_length + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_fix_external_set_vector + :project: progguide + +----------------------- + .. doxygenfunction:: lammps_free :project: progguide diff --git a/python/lammps/core.py b/python/lammps/core.py index 44cd51bb33..05192b5f6e 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -303,6 +303,9 @@ class lammps(object): self.lib.lammps_fix_external_set_energy_peratom.argtypes = [c_void_p, c_char_p, POINTER(c_double)] self.lib.lammps_fix_external_set_virial_peratom.argtypes = [c_void_p, c_char_p, POINTER(POINTER(c_double))] + self.lib.lammps_fix_external_set_vector_length.argtypes = [c_void_p, c_char_p, c_int] + self.lib.lammps_fix_external_set_vector.argtypes = [c_void_p, c_char_p, c_int, c_double] + # detect if Python is using a version of mpi4py that can pass communicators # only needed if LAMMPS has been compiled with MPI support. self.has_mpi4py = False @@ -1806,6 +1809,40 @@ class lammps(object): with ExceptionCheck(self): return self.lib.lammps_fix_external_set_energy_global(self.lmp, fix_id.encode(), eng) + # ------------------------------------------------------------------------- + def fix_external_set_vector_length(self, fix_id, length): + """Set the vector length for a global vector stored with fix external for analysis + + This is a wrapper around the :cpp:func:`lammps_fix_external_set_vector_length` function + of the C-library interface. + + :param fix_id: Fix-ID of a fix external instance + :type: string + :param length: length of the global vector + :type: int + """ + + with ExceptionCheck(self): + return self.lib.lammps_fix_external_set_vector_length(self.lmp, fix_id.encode(), length) + + # ------------------------------------------------------------------------- + def fix_external_set_vector(self, fix_id, idx, val): + """Store a global vector value for a fix external instance with the given ID. + + This is a wrapper around the :cpp:func:`lammps_fix_external_set_vector` function + of the C-library interface. + + :param fix_id: Fix-ID of a fix external instance + :type: string + :param idx: 1-based index of the value in the global vector + :type: int + :param val: value to be stored in the global vector + :type: float + """ + + with ExceptionCheck(self): + return self.lib.lammps_fix_external_set_vector(self.lmp, fix_id.encode(), idx, val) + # ------------------------------------------------------------------------- def get_neighlist(self, idx): diff --git a/src/library.cpp b/src/library.cpp index 4488114579..2c75657447 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4821,7 +4821,7 @@ mode. The function has to have C language bindings with the prototype: void func(void *ptr, bigint timestep, int nlocal, tagint *ids, double **x, double **fexternal); -This is an alternative to the array mechanism set up by :cpp:func:`lammps_fix_external_set_force`. +This is an alternative to the array mechanism set up by :cpp:func:`lammps_fix_external_get_force`. Please see the documentation for :doc:`fix external ` for more information about how to use the fix and how to couple it with an @@ -4913,7 +4913,7 @@ double **lammps_fix_external_get_force(void *handle, const char *id) \verbatim embed:rst This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and -:cpp:func:`lammps_fix_external_set_force` to also set the contribution +:cpp:func:`lammps_fix_external_get_force` to also set the contribution to the global energy from the external code. Please see the documentation for :doc:`fix external ` for @@ -4952,7 +4952,7 @@ void lammps_fix_external_set_energy_global(void *handle, const char *id, double \verbatim embed:rst This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and -:cpp:func:`lammps_fix_external_set_force` to also set the contribution +:cpp:func:`lammps_fix_external_get_force` to also set the contribution to the global virial from the external code. Please see the documentation for :doc:`fix external ` for @@ -4991,7 +4991,7 @@ void lammps_fix_external_set_virial_global(void *handle, const char *id, double \verbatim embed:rst This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and -:cpp:func:`lammps_fix_external_set_force` to also set the contribution +:cpp:func:`lammps_fix_external_get_force` to also set the contribution to the per-atom energy from the external code. Please see the documentation for :doc:`fix external ` for @@ -5030,7 +5030,7 @@ void lammps_fix_external_set_energy_peratom(void *handle, const char *id, double \verbatim embed:rst This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and -:cpp:func:`lammps_fix_external_set_force` to also set the contribution +:cpp:func:`lammps_fix_external_get_force` to also set the contribution to the per-atom virial from the external code. Please see the documentation for :doc:`fix external ` for @@ -5064,6 +5064,86 @@ void lammps_fix_external_set_virial_peratom(void *handle, const char *id, double END_CAPTURE } +/** Set the vector length for a global vector stored with fix external for analysis + +\verbatim embed:rst + +This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and +:cpp:func:`lammps_fix_external_get_force` to set the length of a global vector of +properties that will be stored with the fix via :cpp:func:`lammps_fix_external_set_vector`. + +Please see the documentation for :doc:`fix external ` for +more information about how to use the fix and how to couple it with an +external code. + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. + * \param id fix ID of fix external instance + * \param len length of the global vector to be stored with the fix */ + +void lammps_fix_external_set_vector_length(void *handle, const char *id, int len) +{ + LAMMPS *lmp = (LAMMPS *) handle; + + BEGIN_CAPTURE + { + int ifix = lmp->modify->find_fix(id); + if (ifix < 0) + lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id); + + Fix *fix = lmp->modify->fix[ifix]; + + if (strcmp("external",fix->style) != 0) + lmp->error->all(FLERR,"Fix '{}' is not of style external!", id); + + FixExternal *fext = (FixExternal*) fix; + fext->set_vector_length(len); + } + END_CAPTURE +} + +/** Store global vector for a fix external instance with the given ID. + +\verbatim embed:rst + +This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and +:cpp:func:`lammps_fix_external_get_force` to set the values of a global vector of +properties that will be stored with the fix. The length of the vector +must be set beforehand with :cpp:func:`lammps_fix_external_set_vector_length`. + +Please see the documentation for :doc:`fix external ` for +more information about how to use the fix and how to couple it with an +external code. + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. + * \param id fix ID of fix external instance + * \param idx 1 based index of in global vector + * \param val value to be stored in global vector */ + +void lammps_fix_external_set_vector(void *handle, const char *id, int idx, double val) +{ + LAMMPS *lmp = (LAMMPS *) handle; + + BEGIN_CAPTURE + { + int ifix = lmp->modify->find_fix(id); + if (ifix < 0) + lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id); + + Fix *fix = lmp->modify->fix[ifix]; + + if (strcmp("external",fix->style) != 0) + lmp->error->all(FLERR,"Fix '{}' is not of style external!", id); + + FixExternal * fext = (FixExternal*) fix; + fext->set_vector(idx, val); + } + END_CAPTURE +} + /* ---------------------------------------------------------------------- */ /** Free memory buffer allocated by LAMMPS. diff --git a/src/library.h b/src/library.h index 25b5199dc7..654eda38fa 100644 --- a/src/library.h +++ b/src/library.h @@ -240,7 +240,7 @@ void lammps_fix_external_set_energy_peratom(void *handle, const char *id, double void lammps_fix_external_set_virial_global(void *handle, const char *id, double *virial); void lammps_fix_external_set_virial_peratom(void *handle, const char *id, double **virial); void lammps_fix_external_set_vector_length(void *handle, const char *id, int len); -void lammps_fix_external_set_virial_peratom(void *handle, const char *id, double **val); +void lammps_fix_external_set_vector(void *handle, const char *id, int idx, double val); void lammps_free(void *ptr); diff --git a/unittest/c-library/test_library_external.cpp b/unittest/c-library/test_library_external.cpp index 7c53daaef7..d44f3ff2ee 100644 --- a/unittest/c-library/test_library_external.cpp +++ b/unittest/c-library/test_library_external.cpp @@ -28,12 +28,20 @@ static void callback_one(void *handle, step_t timestep, int nlocal, tag_t *, dou { for (int i = 0; i < nlocal; ++i) f[i][0] = f[i][1] = f[i][2] = (double)timestep; - if (timestep < 10) - lammps_fix_external_set_energy_global(handle, "ext", 0.0); - else - lammps_fix_external_set_energy_global(handle, "ext", 1.0); + double v[6] = {1.0, 1.0, 1.0, 0.0, 0.0, 0.0}; lammps_fix_external_set_virial_global(handle, "ext", v); + if (timestep < 10) { + lammps_fix_external_set_energy_global(handle, "ext", 0.5); + lammps_fix_external_set_vector(handle, "ext", 1, timestep); + lammps_fix_external_set_vector(handle, "ext", 3, 1.0); + lammps_fix_external_set_vector(handle, "ext", 4, -0.25); + } else { + lammps_fix_external_set_energy_global(handle, "ext", 1.0); + lammps_fix_external_set_vector(handle, "ext", 2, timestep); + lammps_fix_external_set_vector(handle, "ext", 5, -1.0); + lammps_fix_external_set_vector(handle, "ext", 6, 0.25); + } } } @@ -57,11 +65,12 @@ TEST(lammps_external, callback) "pair_style zero 0.1\n" "pair_coeff 1 1\n" "velocity all set 0.1 0.0 -0.1\n" - "thermo 5\n" "fix 1 all nve\n" "fix ext all external pf/callback 5 1\n" + "thermo_style custom step temp pe ke etotal press\n" + "thermo 5\n" "fix_modify ext energy yes virial yes\n"); - + lammps_fix_external_set_vector_length(handle, "ext", 6); output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -71,11 +80,19 @@ TEST(lammps_external, callback) double temp = lammps_get_thermo(handle, "temp"); double pe = lammps_get_thermo(handle, "pe"); double press = lammps_get_thermo(handle, "press"); - output = ::testing::internal::GetCapturedStdout(); + double val = 0.0; + double *valp; + for (int i = 0; i < 6; ++i) { + valp = (double *)lammps_extract_fix(handle, "ext", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, i, 0); + val += *valp; + lammps_free(valp); + } + output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; EXPECT_DOUBLE_EQ(temp, 1.0 / 30.0); EXPECT_DOUBLE_EQ(pe, 1.0 / 8.0); EXPECT_DOUBLE_EQ(press, 0.15416666666666667); + EXPECT_DOUBLE_EQ(val, 15); ::testing::internal::CaptureStdout(); lammps_close(handle); diff --git a/unittest/python/python-fix-external.py b/unittest/python/python-fix-external.py index 02fe805626..eab4687e2b 100644 --- a/unittest/python/python-fix-external.py +++ b/unittest/python/python-fix-external.py @@ -1,6 +1,6 @@ import sys,os,unittest from ctypes import * -from lammps import lammps +from lammps import lammps, LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR # add timestep dependent force def callback_one(lmp, ntimestep, nlocal, tag, x, f): @@ -9,9 +9,15 @@ def callback_one(lmp, ntimestep, nlocal, tag, x, f): f[i][1] = float(ntimestep) f[i][2] = float(ntimestep) if ntimestep < 10: - lmp.fix_external_set_energy_global("ext",0.5) + lmp.fix_external_set_energy_global("ext", 0.5) + lmp.fix_external_set_vector("ext", 1, ntimestep) + lmp.fix_external_set_vector("ext", 3, 1.0) + lmp.fix_external_set_vector("ext", 4, -0.25) else: - lmp.fix_external_set_energy_global("ext",1.0) + lmp.fix_external_set_energy_global("ext", 1.0) + lmp.fix_external_set_vector("ext", 2, ntimestep) + lmp.fix_external_set_vector("ext", 5, -1.0) + lmp.fix_external_set_vector("ext", 6, 0.25) class PythonExternal(unittest.TestCase): def testExternalCallback(self): @@ -31,15 +37,22 @@ class PythonExternal(unittest.TestCase): pair_style zero 0.1 pair_coeff 1 1 velocity all set 0.1 0.0 -0.1 + thermo_style custom step temp pe ke etotal press thermo 5 fix 1 all nve fix ext all external pf/callback 5 1 + fix_modify ext energy yes virial yes """ lmp.commands_string(basic_system) + lmp.fix_external_set_vector_length("ext",6); lmp.set_fix_external_callback("ext",callback_one,lmp) lmp.command("run 10 post no") self.assertAlmostEqual(lmp.get_thermo("temp"),1.0/30.0,14) self.assertAlmostEqual(lmp.get_thermo("pe"),1.0/8.0,14) + val = 0.0 + for i in range(0,6): + val += lmp.extract_fix("ext",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=i) + self.assertAlmostEqual(val,15.0,14) def testExternalArray(self): """Test fix external from Python with pf/array"""