diff --git a/doc/src/Fortran.rst b/doc/src/Fortran.rst index 813a52a44b..874b57cbd7 100644 --- a/doc/src/Fortran.rst +++ b/doc/src/Fortran.rst @@ -2195,6 +2195,236 @@ Procedures Bound to the :f:type:`lammps` Derived Type -------- +.. f:function:: fix_external_get_force(id) + + Get pointer to the force array storage in a fix external instance with the + given ID. + + .. versionadded:: TBD + + Fix :doc:`external ` allows programs that are running LAMMPS + through its library interfaces to add or modify certain LAMMPS properties on + specific time steps, similar to the way other fixes do. + + This function provides access to the per-atom force storage in a fix + external instance with the given fix-ID to be added to the individual + atoms when using the "pf/array" mode. The *fexternal* array can be + accessed like other "native" per-atom arrays accessible via the + :f:func:`extract_atom` function. Please note that the array + stores the forces for *local* atoms for each MPI rank, in the order + determined by the neighbor list build. Because the underlying data + structures can change as well as the order of atom as they migrate between + MPI processes because of the domain decomposition parallelization, this + function should be always called immediately before the forces are going to + be set to get an up-to-date pointer. You can use, for example, + :f:func:`extract_setting` to obtain the number of local atoms `nlocal` and + then assume the dimensions of the returned force array as + ``REAL(c_double) :: force(3,nlocal)``. + + This function is an alternative to the callback mechanism in fix external + set up by :f:subr:`set_fix_external_callback`. The main difference is that + this mechanism can be used when forces are to be pre-computed and the + control alternates between LAMMPS and the external driver, while the + callback mechanism can call an external subroutine to compute the force when + the fix is triggered and needs them. + + 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 program. + + :p character(len=*) id: ID of :doc:`fix external ` instance + :to: :cpp:func:`lammps_fix_external_get_force` + :r fexternal: pointer to the per-atom force array allocated by the fix + :rtype fexternal: real(c_double), dimension(3,nlocal) + +-------- + +.. f:subroutine:: fix_external_set_energy_global(id, eng) + + Set the global energy contribution for a :doc:`fix external ` + instance with the given ID. + + .. versionadded:: TBD + + This is a companion function to :f:func:`set_fix_external_callback` + and :f:func:`fix_external_get_force` that also sets the contribution to the + global energy from the external program. The value of the *eng* argument + will be stored in the fix and applied on the current and all following + time steps until changed by another call to this function. The energy is in + energy units as determined by the current :doc:`units ` settings and + is the **total** energy of the contribution. Thus, when running in + parallel, all MPI processes have to call this function with the **same** + value, and this will be returned as scalar property of the fix external + instance when accessed in LAMMPS input commands or from variables. + + 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 + program. + + :p character(len=*) id: fix ID of fix external instance + :p real(c_double) eng: total energy to be added to the global energy + :to: :cpp:func:`lammps_fix_external_set_energy_global` + +-------- + +.. f:subroutine:: fix_external_set_virial_global(id, virial) + + Set the global virial contribution for a fix external instance with the + given ID. + + .. versionadded:: TBD + + This is a companion function to :f:subr:`set_fix_external_callback` + and :f:func:`fix_external_get_force` to set the contribution to the global + virial from an external program. + + The six values of the *virial* array will be stored in the fix and applied + on the current and all following time steps until changed by another call + to this function. The components of the virial need to be stored in the + following order: *xx*, *yy*, *zz*, *xy*, *xz*, *yz*. In LAMMPS, the virial + is stored internally as `stress*volume` in units of `pressure*volume` as + determined by the current :doc:`units ` settings and is the + **total** contribution. Thus, when running in parallel, all MPI processes + have to call this function with the **same** value, and this will then be + added by fix external. + + 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. + + :p character(len=*) id: fix ID of fix external instance + :p real(c_double) virial [dimension(6)]: the six global stress tensor + components to be added to the global virial + :to: :cpp:func:`lammps_fix_external_set_virial_global` + +-------- + +.. f:subroutine:: fix_external_set_energy_peratom(id, eng) + + Set the per-atom energy contribution for a fix external instance with the + given ID. + + .. versionadded:: TBD + + This is a companion function to :f:subr:`set_fix_external_callback` to set + the per-atom energy contribution due to the fix from the external code as + part of the callback function. For this to work, the handle to the LAMMPS + object must be passed as the *ptr* argument when registering the callback + function. + + .. note:: + + This function is fully independent from + :f:subr:`fix_external_set_energy_global` and will **NOT** add any + contributions to the global energy tally and will **NOT** check whether + the sum of the contributions added here are consistent with the global + added energy. + + 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. + + :p character(len=*) id: fix ID of the fix external instance + :p real(c_double) eng [dimension(:)]: array of length nlocal containing + the energy to add to the per-atom energy + :to: :cpp:func:`lammps_fix_external_set_energy_peratom` + +-------- + +.. f:subroutine:: set_fix_external_set_virial_peratom(id, virial) + + This is a companion function to :f:subr:`set_fix_external_callback` to set + the per-atom virial contribution due to the fix from the external program as + part of the callback function. For this to work, the LAMMPS object must be + passed as the *caller* argument when registering the callback function. + + .. versionadded:: TBD + + .. note:: + + This function is fully independent from + :f:subr:`fix_external_set_virial_global` and will **NOT** add any + contributions to the global virial tally and **NOT** check whether the + sum of the contributions added here are consistent with the global added + virial. + + The order and units of the per-atom stress tensor elements are the same + as for the global virial. The type and dimensions of the per-atom virial + array must be ``REAL(c_double), DIMENSION(6,nlocal)``. + + 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 program. + + :p character(len=*) id: fix ID of fix external instance + :p real(c_double) virial [dimension(:,:)]: an array of :math:`6 \times{}`\ + *nlocal* components to be added to the per-atom virial + :to: :cpp:func:`lammps_set_virial_peratom` + +-------- + +.. f:subroutine:: fix_external_set_vector_length(id, length) + + Set the vector length for a global vector stored with fix external for + analysis. + + .. versionadded:: TBD + + This is a companion function to :f:subr:`set_fix_external_callback` and + :f:func:`fix_external_get_force` to set the length of a global vector of + properties that will be stored with the fix via + :f:subr:`fix_external_set_vector`. + + This function needs to be called **before** a call to + :f:subr:`fix_external_set_vector` and **before** a run or minimize command. + When running in parallel, it must be called from **all** MPI + processes with the same length argument. + + 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 program. + + :p character(len=*) id: fix ID of fix external instance + :p integer(c_int) length: length of the global vector to be stored with the + fix + +-------- + +.. f:subroutine:: fix_external_set_vector(id, idx, val) + + Store a global vector value for a fix external instance with the given ID. + + .. versionadded:: TBD + + This is a companion function to :f:subr:`set_fix_external_callback` and + :f:func:`fix_external_get_force` to set the values of a global vector of + properties that will be stored with the fix and can be accessed from + within LAMMPS input commands (e.g., fix ave/time or variables) when used + in a vector context. + + This function needs to be called **after** a call to + :f:subr:`fix_external_set_vector_length` and **before** a run or minimize + command. When running in parallel, it must be called from **all** MPI + processes with the **same**\ *idx* and *val* parameters. The variable + *val* is assumed to be extensive. + + .. note:: + + The index in the *idx* parameter is 1-based (i.e., the first element + is set with *idx*\ :math:`{} = 1`, and the last element of the vector + with *idx*\ :math:`{} = N`, where :math:`N` is the value of the *length* + parameter of the call to :f:subr:`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. + + :p character(len=*) id: ID of fix external instance + :p integer(c_int) idx: 1-based index in global vector + :p integer(c_int) val: value to be stored in global vector at index *idx* + +-------- + .. f:subroutine:: flush_buffers() This function calls :cpp:func:`lammps_flush_buffers`, which flushes buffered diff --git a/fortran/lammps.f90 b/fortran/lammps.f90 index f6818a21d9..c5ccc17b4e 100644 --- a/fortran/lammps.f90 +++ b/fortran/lammps.f90 @@ -175,6 +175,18 @@ MODULE LIBLAMMPS GENERIC :: decode_image_flags => lmp_decode_image_flags, & lmp_decode_image_flags_bigbig PROCEDURE :: set_fix_external_callback => lmp_set_fix_external_callback + PROCEDURE :: fix_external_get_force => lmp_fix_external_get_force + PROCEDURE :: fix_external_set_energy_global & + => lmp_fix_external_set_energy_global + PROCEDURE :: fix_external_set_virial_global & + => lmp_fix_external_set_virial_global + PROCEDURE :: fix_external_set_energy_peratom & + => lmp_fix_external_set_energy_peratom + PROCEDURE :: fix_external_set_virial_peratom & + => lmp_fix_external_set_virial_peratom + PROCEDURE :: fix_external_set_vector_length & + => lmp_fix_external_set_vector_length + PROCEDURE :: fix_external_set_vector => lmp_fix_external_set_vector PROCEDURE :: flush_buffers => lmp_flush_buffers PROCEDURE :: is_running => lmp_is_running PROCEDURE :: force_timeout => lmp_force_timeout @@ -765,12 +777,42 @@ MODULE LIBLAMMPS TYPE(c_ptr) :: lammps_fix_external_get_force END FUNCTION lammps_fix_external_get_force - !SUBROUTINE lammps_fix_external_set_energy_global - !SUBROUTINE lammps_fix_external_set_energy_peratom - !SUBROUTINE lammps_fix_external_set_virial_global - !SUBROUTINE lammps_fix_external_set_virial_peratom - !SUBROUTINE lammps_fix_external_set_vector_length - !SUBROUTINE lammps_fix_external_set_vector + SUBROUTINE lammps_fix_external_set_energy_global(handle, id, eng) BIND(C) + IMPORT :: c_ptr, c_double + TYPE(c_ptr), VALUE :: handle, id + REAL(c_double), VALUE :: eng + END SUBROUTINE lammps_fix_external_set_energy_global + + SUBROUTINE lammps_fix_external_set_virial_global(handle, id, virial) & + BIND(C) + IMPORT :: c_ptr + TYPE(c_ptr), VALUE :: handle, id, virial + END SUBROUTINE lammps_fix_external_set_virial_global + + SUBROUTINE lammps_fix_external_set_energy_peratom(handle, id, eng) BIND(C) + IMPORT :: c_ptr + TYPE(c_ptr), VALUE :: handle, id, eng + END SUBROUTINE lammps_fix_external_set_energy_peratom + + SUBROUTINE lammps_fix_external_set_virial_peratom(handle, id, virial) & + BIND(C) + IMPORT :: c_ptr + TYPE(c_ptr), VALUE :: handle, id, virial + END SUBROUTINE lammps_fix_external_set_virial_peratom + + SUBROUTINE lammps_fix_external_set_vector_length(handle, id, length) & + BIND(C) + IMPORT :: c_ptr, c_int + TYPE(c_ptr), VALUE :: handle, id + INTEGER(c_int), VALUE :: length + END SUBROUTINE lammps_fix_external_set_vector_length + + SUBROUTINE lammps_fix_external_set_vector(handle, id, idx, val) BIND(C) + IMPORT :: c_ptr, c_int, c_double + TYPE(c_ptr), VALUE :: handle, id + INTEGER(c_int), VALUE :: idx + REAL(c_double), VALUE :: val + END SUBROUTINE lammps_fix_external_set_vector SUBROUTINE lammps_flush_buffers(handle) BIND(C) IMPORT :: c_ptr @@ -2591,6 +2633,92 @@ CONTAINS CALL lammps_free(Cid) END FUNCTION lmp_fix_external_get_force + SUBROUTINE lmp_fix_external_set_energy_global(self, id, eng) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: id + REAL(c_double), INTENT(OUT) :: eng + TYPE(c_ptr) :: Cid + + Cid = f2c_string(id) + CALL lammps_fix_external_set_energy_global(self%handle, Cid, eng) + CALL lammps_free(Cid) + END SUBROUTINE lmp_fix_external_set_energy_global + + SUBROUTINE lmp_fix_external_set_virial_global(self, id, virial) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: id + REAL(c_double), DIMENSION(6), TARGET, INTENT(IN) :: virial + TYPE(c_ptr) :: Cid, Cvirial + + Cid = f2c_string(id) + Cvirial = C_LOC(virial(1)) + CALL lammps_fix_external_set_virial_global(self%handle, Cid, Cvirial) + CALL lammps_free(Cid) + END SUBROUTINE lmp_fix_external_set_virial_global + + SUBROUTINE lmp_fix_external_set_energy_peratom(self, id, eng) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: id + REAL(c_double), DIMENSION(:), TARGET, INTENT(IN) :: eng + TYPE(c_ptr) :: Cid, Ceng + INTEGER(c_int) :: nlocal + + nlocal = lmp_extract_setting(self, 'nlocal') + IF (SIZE(eng) < nlocal) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'Array "eng" should be length nlocal or greater & + &[Fortran/fix_external_set_energy_peratom]') + END IF + Cid = f2c_string(id) + Ceng = C_LOC(eng) + CALL lammps_fix_external_set_energy_peratom(self%handle, Cid, Ceng) + CALL lammps_free(Cid) + END SUBROUTINE lmp_fix_external_set_energy_peratom + + SUBROUTINE lmp_fix_external_set_virial_peratom(self, id, virial) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: id + REAL(c_double), DIMENSION(:,:), TARGET, INTENT(IN) :: virial + TYPE(c_ptr) :: Cid, Cvirial + TYPE(c_ptr), TARGET :: Cptr + INTEGER(c_int) :: nlocal + + nlocal = lmp_extract_setting(self, 'nlocal') + IF (SIZE(virial,2) < nlocal .OR. SIZE(virial,1) /= 6) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'Array "virial" should be size 6 x nlocal or greater & + &[Fortran/fix_external_set_energy_peratom]') + END IF + Cid = f2c_string(id) + Cptr = C_LOC(virial(1,1)) + Cvirial = C_LOC(Cptr) + CALL lammps_fix_external_set_virial_peratom(self%handle, Cid, Cvirial) + CALL lammps_free(Cid) + END SUBROUTINE lmp_fix_external_set_virial_peratom + + SUBROUTINE lmp_fix_external_set_vector_length(self, id, length) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: id + INTEGER(c_int), INTENT(IN) :: length + TYPE(c_ptr) :: Cid + + Cid = f2c_string(id) + CALL lammps_fix_external_set_vector_length(self%handle, Cid, length) + CALL lammps_free(Cid) + END SUBROUTINE lmp_fix_external_set_vector_length + + SUBROUTINE lmp_fix_external_set_vector(self, id, idx, val) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: id + INTEGER(c_int), INTENT(IN) :: idx + REAL(c_double), INTENT(IN) :: val + TYPE(c_ptr) :: Cid + + Cid = f2c_string(id) + CALL lammps_fix_external_set_vector(self%handle, Cid, idx, val) + CALL lammps_free(Cid) + END SUBROUTINE lmp_fix_external_set_vector + ! equivalent function to lammps_flush_buffers SUBROUTINE lmp_flush_buffers(self) CLASS(lammps), INTENT(IN) :: self