From 71f086e159ed22e69cd20024d76dea28e5578acd Mon Sep 17 00:00:00 2001 From: Karl Hammond Date: Fri, 2 Dec 2022 17:19:42 -0600 Subject: [PATCH] implemented scatter, gather, and friends; wrote and updated documentation --- doc/src/Fortran.rst | 209 ++++++++++++++++++++++-- fortran/lammps.f90 | 378 ++++++++++++++++++++++++++++++++++++++++++-- src/library.cpp | 209 ++++++++++++++++++++++-- 3 files changed, 764 insertions(+), 32 deletions(-) diff --git a/doc/src/Fortran.rst b/doc/src/Fortran.rst index 6161ccaebe..80d3447437 100644 --- a/doc/src/Fortran.rst +++ b/doc/src/Fortran.rst @@ -298,6 +298,16 @@ of the contents of the :f:mod:`LIBLAMMPS` Fortran interface to LAMMPS. :ftype scatter_atoms_subset: subroutine :f gather_bonds: :f:subr:`gather_bonds` :ftype gather_bonds: subroutine + :f gather: :f:subr:`gather` + :ftype gather: subroutine + :f gather_concat: :f:subr:`gather_concat` + :ftype gather_concat: subroutine + :f gather_subset: :f:subr:`gather_subset` + :ftype gather_subset: subroutine + :f scatter: :f:subr:`scatter` + :ftype scatter: subroutine + :f scatter_subset: :f:subr:`scatter_subset` + :ftype scatter_subset: subroutine :f create_atoms: :f:subr:`create_atoms` :ftype create_atoms: subroutine :f find_pair_neighlist: :f:func:`find_pair_neighlist` @@ -1194,8 +1204,8 @@ Procedures Bound to the :f:type:`lammps` Derived Type .. f:function:: extract_variable(name[,group]) - This function calls :cpp:func:`lammps_extract_variable` and returns a scalar, - vector, or string containing the value of the variable identified by + This function calls :cpp:func:`lammps_extract_variable` and returns a + scalar, vector, or string containing the value of the variable identified by *name*. When the variable is an *equal*-style variable (or one compatible with that style such as *internal*), the variable is evaluated and the corresponding value returned. When the variable is an *atom*-style variable, @@ -1276,15 +1286,19 @@ Procedures Bound to the :f:type:`lammps` Derived Type length (*count* :math:`\times` *natoms*), as queried by :f:func:`extract_setting`. + This function is not compatible with ``-DLAMMPS_BIGBIG``. + :p character(len=\*) name: desired quantity (e.g., *x* or *mask*) :p integer(c_int) count: number of per-atom values you expect per atom (e.g., 1 for *type*, *mask*, or *charge*; 3 for *x*, *v*, or *f*). Use *count* = 3 with *image* if you want a single image flag unpacked into *x*/*y*/*z* components. - :p real(c_double) data [dimension(:),allocatable]: array into which to store + :p polymorphic data [dimension(:),allocatable]: array into which to store the data. Array *must* have the ``ALLOCATABLE`` attribute and be of rank 1 (i.e., ``DIMENSION(:)``). If this array is already allocated, it will be - reallocated to fit the length of the incoming data. + reallocated to fit the length of the incoming data. It should have type + ``INTEGER(c_int)`` if expecting integer data and ``REAL(c_double)`` if + expecting floating-point data. :to: :cpp:func:`lammps_gather_atoms` .. note:: @@ -1324,15 +1338,19 @@ Procedures Bound to the :f:type:`lammps` Derived Type :f:func:`gather_atoms`; for a similar array but for a subset of atoms, see :f:func:`gather_atoms_subset`. + This function is not compatible with ``-DLAMMPS_BIGBIG``. + :p character(len=\*) name: desired quantity (e.g., *x* or *mask*) :p integer(c_int) count: number of per-atom values you expect per atom (e.g., 1 for *type*, *mask*, or *charge*; 3 for *x*, *v*, or *f*). Use *count* = 3 with *image* if you want a single image flag unpacked into *x*/*y*/*z* components. - :p real(c_double) data [dimension(:),allocatable]: array into which to store + :p polymorphic data [dimension(:),allocatable]: array into which to store the data. Array *must* have the ``ALLOCATABLE`` attribute and be of rank 1 (i.e., ``DIMENSION(:)``). If this array is already allocated, it will be - reallocated to fit the length of the incoming data. + reallocated to fit the length of the incoming data. It should have type + ``INTEGER(c_int)`` if expecting integer data and ``REAL(c_double)`` if + expecting floating-point data. :to: :cpp:func:`lammps_gather_atoms_concat` -------- @@ -1346,7 +1364,7 @@ Procedures Bound to the :f:type:`lammps` Derived Type .. versionadded:: 3Nov2022 This subroutine gathers data for the requested atom IDs and stores them in a - one-dimensional array allocated by the user. The data will be ordered by + one-dimensional allocatable array. The data will be ordered by atom ID, but there is no requirement that the IDs be consecutive. If you wish to return a similar array for *all* the atoms, use :f:func:`gather_atoms` or :f:func:`gather_atoms_concat`. @@ -1359,6 +1377,8 @@ Procedures Bound to the :f:type:`lammps` Derived Type user, and *data* must be of rank 1 (i.e., ``DIMENSION(:)``) and have the ``ALLOCATABLE`` attribute. + This function is not compatible with ``-DLAMMPS_BIGBIG``. + :p character(len=\*) name: desired quantity (e.g., *x* or *mask*) :p integer(c_int) count: number of per-atom values you expect per atom (e.g., 1 for *type*, *mask*, or *charge*; 3 for *x*, *v*, or *f*). Use @@ -1366,10 +1386,12 @@ Procedures Bound to the :f:type:`lammps` Derived Type *x*/*y*/*z* components. :p integer(c_int) ids [dimension(:)]: atom IDs corresponding to the atoms to be gathered - :p real(c_double) data [dimension(:),allocatable]: array into which to store + :p polymorphic data [dimension(:),allocatable]: array into which to store the data. Array *must* have the ``ALLOCATABLE`` attribute and be of rank 1 (i.e., ``DIMENSION(:)``). If this array is already allocated, it will be - reallocated to fit the length of the incoming data. + reallocated to fit the length of the incoming data. It should have type + ``INTEGER(c_int)`` if expecting integer data and ``REAL(c_double)`` if + expecting floating-point data. :to: :cpp:func:`lammps_gather_atoms_subset` -------- @@ -1443,7 +1465,7 @@ Procedures Bound to the :f:type:`lammps` Derived Type .. versionadded:: 3Nov2022 - This function copies the list of all bonds into an allocated array. + This function copies the list of all bonds into an allocatable array. The array will be filled with (bond type, bond atom 1, bond atom 2) for each bond. The array is allocated to the right length (i.e., three times the number of bonds). The array *data* must be of the same type as the LAMMPS @@ -1482,6 +1504,173 @@ Procedures Bound to the :f:type:`lammps` Derived Type -------- +.. f:subroutine:: gather(self, name, count, data) + + Gather the named per-atom, per-atom fix, per-atom compute, or fix + property/atom-based entities from all processes, in order by atom ID. + + .. versionadded:: TBD + + This subroutine gathers data from all processes and stores them in a + one-dimensional allocatable array. The array *data* will be + ordered by atom ID, which requires consecutive IDs (1 to *natoms*\ ). If you + need a similar array but for non-consecutive atom IDs, see + :cpp:func:`lammps_gather_concat`; for a similar array but for a subset of + atoms, see :cpp:func:`lammps_gather_subset`. + + The *data* array will be ordered in groups of *count* values, sorted by atom + ID (e.g., if *name* is *x*, then *data* is [x(1,1), x(2,1), x(3,1), x(1,2), + x(2,2), x(3,2), x(1,3), :math:`\dots`]); *data* must be ``ALLOCATABLE`` and + will be allocated to length (*count*\ :math:`{}\times{}`\ *natoms*), as + queried by :f:func:`extract_setting`. + + This function will return an error if fix or compute data are requested and + the fix or compute ID given does not have per-atom data. See the note about + re-interpreting the vector as a matrix at :f:subr:`gather_atoms`. + + This function is not compatible with ``-DLAMMPS_BIGBIG``. + + :p character(len=\*) name: desired quantity (e.g., "x" or "mask" for atom + properties, "f_id" for per-atom fix data, "c_id" for per-atom compute data, + "d_name" or "i_name" for fix property/atom vectors with *count* = 1, + "d2_name" or "i2_name" for fix propert/atom vectors with + *count*\ :math:`{}> 1`) + :p integer(c_int) count: number of per-atom values (e.g., 1 for *type* or + *charge*, 3 for *x* or *f*); use *count* = 3 with *image* if you want the + image flags unpacked into (*x*,\ *y*,\ *z*) components. + :p real(c_double) data [dimension(:),allocatable]: array into which to store + the data. Array *must* have the ``ALLOCATABLE`` attribute and be of rank 1 + (i.e., ``DIMENSION(:)``). If this array is already allocated, it will be + reallocated to fit the length of the incoming data. + :to: :cpp:func:`lammps_gather` + +-------- + +.. f:subroutine:: gather_concat(self, name, count, data) + + Gather the named per-atom, per-atom fix, per-atom compute, or fix + property/atom-based entities from all processes, unordered. + + This subroutine gathers data for all atoms and stores them in a + one-dimensional allocatable array. The data will be a + concatenation of chunks from each processor's owned atoms, in whatever order + the atoms are in on each processor. This process has no requirement that the + atom IDs be consecutive. If you need the ID of each atom, you can do another + call to either :f:subr:`gather_atoms_concat` or :f:subr:`gather_concat` with + *name* set to ``id``. If you have consecutive IDs and want the data to be in + order, use :f:subr:`gather`; for a similar array but for a subset of + atoms, use :f:subr:`gather_subset`. + + The *data* array will be in groups of *count* values, with *natoms* groups + total, but not in order by atom ID (e.g., if *name* is *x* and *count* is 3, + then *data* might be something like [x(1,11), x(2,11), x(3,11), x(1,3), + x(2,3), x(3,3), x(1,5), :math:`\dots`]); *data* must be ``ALLOCATABLE`` and + will be allocated to length (*count* :math:`\times` *natoms*), as queried by + :f:func:`extract_setting`. + + This function is not compatible with ``-DLAMMPS_BIGBIG``. + + :p character(len=\*) name: desired quantity (e.g., "x" or "mask" for atom + properties, "f_id" for per-atom fix data, "c_id" for per-atom compute data, + "d_name" or "i_name" for fix property/atom vectors with *count* = 1, + "d2_name" or "i2_name" for fix propert/atom vectors with + *count*\ :math:`{}> 1`) + :p integer(c_int) count: number of per-atom values you expect per atom + (e.g., 1 for *type*, *mask*, or *charge*; 3 for *x*, *v*, or *f*). Use + *count* = 3 with *image* if you want a single image flag unpacked into + *x*/*y*/*z* components. + :p polymorphic data [dimension(:),allocatable]: array into which to store + the data. Array *must* have the ``ALLOCATABLE`` attribute and be of rank 1 + (i.e., ``DIMENSION(:)``). If this array is already allocated, it will be + reallocated to fit the length of the incoming data. It should have type + ``INTEGER(c_int)`` if expecting integer data and ``REAL(c_double)`` if + expecting floating-point data. + :to: :cpp:func:`lammps_gather_concat` + +-------- + +.. f:subroutine:: gather_subset(name, count, ids, data) + + Gather the named per-atom, per-atom fix, per-atom compute, or fix + property/atom-based entities from all processes for a subset of atoms. + + This subroutine gathers data for the requested atom IDs and stores them in a + one-dimensional allocatable array. The data will be ordered by atom ID, but + there is no requirement that the IDs be consecutive. If you wish to return a + similar array for *all* the atoms, use :f:subr:`gather` or + :f:subr:`gather_concat`. + + The *data* array will be in groups of *count* values, sorted by atom ID in + the same order as the array *ids* (e.g., if *name* is *x*, *count* = 3, and + *ids* is [100, 57, 210], then *data* might look like [x(1,100), x(2,100), + x(3,100), x(1,57), x(2,57), x(3,57), x(1,210), :math:`\dots`]); *ids* must + be provided by the user, and *data* must have the ``ALLOCATABLE`` attribute + and be of rank 1 (i.e., ``DIMENSION(:)``). If *data* is already allocated, + it will be reallocated to fit the length of the incoming data. + + This function is not compatible with ``-DLAMMPS_BIGBIG``. + + :p character(len=\*) name: quantity to be scattered + + :p integer(c_int) ids [dimension(:)]: atom IDs corresponding to the atoms + being scattered (e.g., "x" or "f" for atom properties, "f_id" for per-atom + fix data, "c_id" for per-atom compute data, "d_name" or "i_name" for fix + property/atom vectors with *count* = 1, "d2_name" or "i2_name" for fix + property/atom vectors with *count*\ :math:`{} > 1`) + :p data: per-atom values packed into a one-dimensional array containing the + data to be scattered. This array must have either the same length as *ids* + (for *mask*, *type*, etc.) or three times its length (for *x*, *f*, etc.); + the array must be rank 1 and be of type ``INTEGER(c_int)`` (e.g., for + *mask* or *type*) or of type ``REAL(c_double)`` (e.g., for *charge*, *x*, + or *f*). + :ptype data: polymorphic,dimension(:) + :to: :cpp:func:`lammps_scatter_subset` + +-------- + +.. f:subroutine:: scatter(name, data) + + This function calls :cpp:func:`lammps_scatter` to scatter the named + atom-based entities in *data* to all processes. + + *This function is not yet documented, as the underlying C routine has not + been thoroughly tested yet.* + +-------- + +.. f:subroutine:: scatter_subset(name, ids, data) + + This function calls :cpp:func:`lammps_scatter_subset` to scatter the named + per-atom, per-atom fix, per-atom compute, or fix property/atom-based + entities in *data* from a subset of atoms to all processes. + + .. versionadded:: TBD + + This subroutine takes data stored in a one-dimensional array supplied by the + user and scatters them to a subset of atoms on all processes. The array + *data* contains data associated with atom IDs, but there is no requirement + that the IDs be consecutive, as they are provided in a separate array. + Use :f:subr:`scatter` to scatter data for all atoms, in order. + + The *data* array needs to be organized in groups of *count* values, with the + groups in the same order as the array *ids*. For example, if you want *data* + to be the array [x(1,1), x(2,1), x(3,1), x(1,100), x(2,100), x(3,100), + x(1,57), x(2,57), x(3,57)], then *count* = 3 and *ids* = [1, 100, 57]. + + This function is not compatible with ``-DLAMMPS_BIGBIG``. + + :p character(len=\*) name: desired quantity (e.g., "x" or "mask" for atom + properties, "f_id" for per-atom fix data, "c_id" for per-atom compute data, + "d_name" or "i_name" for fix property/atom vectors with *count* = 1, + "d2_name" or "i2_name" for fix propert/atom vectors with + *count*\ :math:`{}> 1`) + :p integer(c_int) ids: list of atom IDs to scatter data for + :p polymorphic data [dimension(:)]: per-atom values packed in a + one-dimensional array of length *size(ids)* \* *count*. + :to: :cpp:func:`lammps_scatter_subset` + +-------- + .. f:subroutine:: create_atoms([id,] type, x, [v,] [image,] [bexpand]) This method calls :cpp:func:`lammps_create_atoms` to create additional atoms diff --git a/fortran/lammps.f90 b/fortran/lammps.f90 index 18b8fa89a3..4cf90e22a2 100644 --- a/fortran/lammps.f90 +++ b/fortran/lammps.f90 @@ -135,7 +135,24 @@ MODULE LIBLAMMPS PROCEDURE, PRIVATE :: lmp_gather_bonds_big GENERIC :: gather_bonds => lmp_gather_bonds_small, & lmp_gather_bonds_big -! + PROCEDURE, PRIVATE :: lmp_gather_int + PROCEDURE, PRIVATE :: lmp_gather_double + GENERIC :: gather => lmp_gather_int, lmp_gather_double + PROCEDURE, PRIVATE :: lmp_gather_concat_int + PROCEDURE, PRIVATE :: lmp_gather_concat_double + GENERIC :: gather_concat => lmp_gather_concat_int, & + lmp_gather_concat_double + PROCEDURE, PRIVATE :: lmp_gather_subset_int + PROCEDURE, PRIVATE :: lmp_gather_subset_double + GENERIC :: gather_subset => lmp_gather_subset_int, & + lmp_gather_subset_double + PROCEDURE, PRIVATE :: lmp_scatter_int + PROCEDURE, PRIVATE :: lmp_scatter_double + GENERIC :: scatter => lmp_scatter_int, lmp_scatter_double + PROCEDURE, PRIVATE :: lmp_scatter_subset_int + PROCEDURE, PRIVATE :: lmp_scatter_subset_double + GENERIC :: scatter_subset => lmp_scatter_subset_int, & + lmp_scatter_subset_double PROCEDURE, PRIVATE :: lmp_create_atoms_int PROCEDURE, PRIVATE :: lmp_create_atoms_bigbig GENERIC :: create_atoms => lmp_create_atoms_int, & @@ -552,13 +569,42 @@ MODULE LIBLAMMPS TYPE(c_ptr), VALUE :: handle, data END SUBROUTINE lammps_gather_bonds - !SUBROUTINE lammps_gather + SUBROUTINE lammps_gather(handle, name, type, count, data) BIND(C) + IMPORT :: c_ptr, c_int + IMPLICIT NONE + TYPE(c_ptr), VALUE :: handle, name, data + INTEGER(c_int), VALUE :: type, count + END SUBROUTINE lammps_gather - !SUBROUTINE lammps_gather_concat + SUBROUTINE lammps_gather_concat(handle, name, type, count, data) BIND(C) + IMPORT :: c_ptr, c_int + IMPLICIT NONE + TYPE(c_ptr), VALUE :: handle, name, data + INTEGER(c_int), VALUE :: type, count + END SUBROUTINE lammps_gather_concat - !SUBROUTINE lammps_gather_subset + SUBROUTINE lammps_gather_subset(handle, name, type, count, ndata, ids, & + data) BIND(C) + IMPORT :: c_ptr, c_int + IMPLICIT NONE + TYPE(c_ptr), VALUE :: handle, name, ids, data + INTEGER(c_int), VALUE :: type, count, ndata + END SUBROUTINE lammps_gather_subset - !SUBROUTINE lammps_scatter_subset + SUBROUTINE lammps_scatter(handle, name, type, count, data) BIND(C) + IMPORT :: c_ptr, c_int + IMPLICIT NONE + TYPE(c_ptr), VALUE :: handle, name, data + INTEGER(c_int), VALUE :: type, count + END SUBROUTINE lammps_scatter + + SUBROUTINE lammps_scatter_subset(handle, name, type, count, ndata, ids, & + data) BIND(C) + IMPORT :: c_ptr, c_int + IMPLICIT NONE + TYPE(c_ptr), VALUE :: handle, name, ids, data + INTEGER(c_int), VALUE :: count, ndata, type + END SUBROUTINE lammps_scatter_subset FUNCTION lammps_create_atoms(handle, n, id, type, x, v, image, bexpand) & BIND(C) @@ -1622,7 +1668,7 @@ CONTAINS IF (count /= 1 .AND. count /= 3) THEN CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & 'gather_atoms_subset requires "count" to be 1 or 3 & - &[Fortran/gather_atoms]') + &[Fortran/gather_atoms_subset]') END IF ndata = SIZE(ids, KIND=c_int) @@ -1652,7 +1698,7 @@ CONTAINS IF (count /= 1 .AND. count /= 3) THEN CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & 'gather_atoms_subset requires "count" to be 1 or 3 & - &[Fortran/gather_atoms]') + &[Fortran/gather_atoms_subset]') END IF ndata = SIZE(ids, KIND=c_int) @@ -1746,7 +1792,8 @@ CONTAINS Ccount = SIZE(data, KIND=c_int) / Cndata IF (Ccount /= 1 .AND. Ccount /= 3) THEN CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & - 'scatter_atoms_subset requires either 1 or 3 data per atom') + 'scatter_atoms_subset requires either 1 or 3 data per atom & + &[Fortran/scatter_atoms_subset]') END IF Cname = f2c_string(name) @@ -1771,7 +1818,8 @@ CONTAINS Ccount = SIZE(data, KIND=c_int) / Cndata IF (Ccount /= 1 .AND. Ccount /= 3) THEN CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & - 'scatter_atoms_subset requires either 1 or 3 data per atom') + 'scatter_atoms_subset requires either 1 or 3 data per atom & + &[Fortran/scatter_atoms_subset]') END IF Cname = f2c_string(name) @@ -1792,7 +1840,7 @@ CONTAINS IF (SIZE_TAGINT /= 4_c_int) THEN CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & - 'Incompatible integer kind in gather_bonds [Fortran API]') + 'Incompatible integer kind in gather_bonds [Fortran/gather_bonds]') END IF IF (ALLOCATED(data)) DEALLOCATE(data) IF (SIZE_BIGINT == 4_c_int) THEN @@ -1815,7 +1863,7 @@ CONTAINS IF (SIZE_TAGINT /= 8_c_int) THEN CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & - 'Incompatible integer kind in gather_bonds [Fortran API]') + 'Incompatible integer kind in gather_bonds [Fortran/gather_bonds]') END IF nbonds = lmp_extract_global(self, 'nbonds') IF (ALLOCATED(data)) DEALLOCATE(data) @@ -1824,6 +1872,314 @@ CONTAINS CALL lammps_gather_bonds(self%handle, Cdata) END SUBROUTINE lmp_gather_bonds_big + ! equivalent function to lammps_gather (for int data) + SUBROUTINE lmp_gather_int(self, name, count, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), INTENT(IN) :: count + INTEGER(c_int), DIMENSION(:), ALLOCATABLE, TARGET, INTENT(OUT) :: data + TYPE(c_ptr) :: Cdata, Cname + INTEGER(c_int) :: natoms + INTEGER(c_int), PARAMETER :: Ctype = 0_c_int + REAL(c_double) :: dnatoms + CHARACTER(LEN=100) :: error_msg + + IF (count /= 1 .AND. count /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'gather requires "count" to be 1 or 3 [Fortran/gather]') + END IF + + dnatoms = lmp_get_natoms(self) + IF (dnatoms > HUGE(1_c_int)) THEN + WRITE(error_msg,'(A,1X,I0,1X,A)') & + 'Cannot use library function gather with more than', & + HUGE(0_c_int), 'atoms [Fortran/gather]' + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, error_msg) + END IF + natoms = NINT(dnatoms, c_int) + + Cname = f2c_string(name) + IF (ALLOCATED(data)) DEALLOCATE(data) + ALLOCATE(data(natoms*count)) + Cdata = C_LOC(data(1)) + CALL lammps_gather(self%handle, Cname, Ctype, count, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_gather_int + + ! equivalent function to lammps_gather_atoms (for doubles) + SUBROUTINE lmp_gather_double(self, name, count, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), INTENT(IN) :: count + REAL(c_double), DIMENSION(:), ALLOCATABLE, TARGET, INTENT(OUT) :: data + TYPE(c_ptr) :: Cdata, Cname + INTEGER(c_int) :: natoms + INTEGER(c_int), PARAMETER :: Ctype = 1_c_int + REAL(c_double) :: dnatoms + CHARACTER(LEN=100) :: error_msg + + IF (count /= 1 .AND. count /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'gather requires "count" to be 1 or 3 [Fortran/gather]') + END IF + + dnatoms = lmp_get_natoms(self) + IF (dnatoms > HUGE(1_c_int)) THEN + WRITE(error_msg,'(A,1X,I0,1X,A)') & + 'Cannot use library function gather with more than', & + HUGE(0_c_int), 'atoms [Fortran/gather]' + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, error_msg) + END IF + natoms = NINT(dnatoms, c_int) + + Cname = f2c_string(name) + IF (ALLOCATED(data)) DEALLOCATE(data) + ALLOCATE(data(natoms*count)) + Cdata = C_LOC(data(1)) + CALL lammps_gather(self%handle, Cname, Ctype, count, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_gather_double + + ! equivalent function to lammps_gather_concat (for ints) + SUBROUTINE lmp_gather_concat_int(self, name, count, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), INTENT(IN) :: count + INTEGER(c_int), DIMENSION(:), ALLOCATABLE, TARGET, INTENT(OUT) :: data + TYPE(c_ptr) :: Cdata, Cname + INTEGER(c_int) :: natoms + INTEGER(c_int), PARAMETER :: Ctype = 0_c_int + REAL(c_double) :: dnatoms + CHARACTER(LEN=100) :: error_msg + + IF (count /= 1 .AND. count /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'gather_concat requires "count" to be 1 or 3 [Fortran/gather_concat]') + END IF + + dnatoms = lmp_get_natoms(self) + IF (dnatoms > HUGE(1_c_int)) THEN + WRITE(error_msg,'(A,1X,I0,1X,A)') & + 'Cannot use library function gather_concat with more than', & + HUGE(0_c_int), 'atoms [Fortran/gather_concat]' + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, error_msg) + END IF + natoms = NINT(dnatoms, c_int) + + Cname = f2c_string(name) + IF (ALLOCATED(data)) DEALLOCATE(data) + ALLOCATE(data(natoms*count)) + Cdata = C_LOC(data(1)) + CALL lammps_gather_concat(self%handle, Cname, Ctype, count, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_gather_concat_int + + ! equivalent function to lammps_gather_concat (for doubles) + SUBROUTINE lmp_gather_concat_double(self, name, count, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), INTENT(IN) :: count + REAL(c_double), DIMENSION(:), ALLOCATABLE, TARGET, INTENT(OUT) :: data + TYPE(c_ptr) :: Cdata, Cname + INTEGER(c_int) :: natoms + INTEGER(c_int), PARAMETER :: Ctype = 1_c_int + REAL(c_double) :: dnatoms + CHARACTER(LEN=100) :: error_msg + + IF (count /= 1 .AND. count /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'gather_concat requires "count" to be 1 or 3 [Fortran/gather_concat]') + END IF + + dnatoms = lmp_get_natoms(self) + IF (dnatoms > HUGE(1_c_int)) THEN + WRITE(error_msg,'(A,1X,I0,1X,A)') & + 'Cannot use library function gather_concat with more than', & + HUGE(0_c_int), 'atoms [Fortran/gather_concat]' + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, error_msg) + END IF + natoms = NINT(dnatoms, c_int) + + Cname = f2c_string(name) + IF (ALLOCATED(data)) DEALLOCATE(data) + ALLOCATE(data(natoms*count)) + Cdata = C_LOC(data(1)) + CALL lammps_gather_concat(self%handle, Cname, Ctype, count, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_gather_concat_double + + ! equivalent function to lammps_gather_subset (for integers) + SUBROUTINE lmp_gather_subset_int(self, name, count, ids, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), INTENT(IN) :: count + INTEGER(c_int), DIMENSION(:), TARGET, INTENT(IN) :: ids + INTEGER(c_int), DIMENSION(:), ALLOCATABLE, TARGET, INTENT(OUT) :: data + INTEGER(c_int) :: ndata + TYPE(c_ptr) :: Cdata, Cname, Cids + INTEGER(c_int), PARAMETER :: Ctype = 0_c_int + + IF (count /= 1 .AND. count /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'gather_subset requires "count" to be 1 or 3 [Fortran/gather_subset]') + END IF + + ndata = SIZE(ids, KIND=c_int) + + Cname = f2c_string(name) + IF (ALLOCATED(data)) DEALLOCATE(data) + ALLOCATE(data(ndata*count)) + data = -1_c_int + Cdata = C_LOC(data(1)) + Cids = C_LOC(ids(1)) + CALL lammps_gather_subset(self%handle, Cname, Ctype, count, & + ndata, Cids, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_gather_subset_int + + ! equivalent function to lammps_gather_subset (for doubles) + SUBROUTINE lmp_gather_subset_double(self, name, count, ids, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), INTENT(IN) :: count + INTEGER(c_int), DIMENSION(:), TARGET, INTENT(IN) :: ids + REAL(c_double), DIMENSION(:), ALLOCATABLE, TARGET, INTENT(OUT) :: data + INTEGER(c_int) :: ndata + TYPE(c_ptr) :: Cdata, Cname, Cids + INTEGER(c_int), PARAMETER :: Ctype = 1_c_int + + IF (count /= 1 .AND. count /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'gather_subset requires "count" to be 1 or 3 [Fortran/gather_subset]') + END IF + + ndata = SIZE(ids, KIND=c_int) + + Cname = f2c_string(name) + IF (ALLOCATED(data)) DEALLOCATE(data) + ALLOCATE(data(ndata*count)) + Cdata = C_LOC(data(1)) + Cids = C_LOC(ids(1)) + CALL lammps_gather_subset(self%handle, Cname, Ctype, count, & + ndata, Cids, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_gather_subset_double + + ! equivalent function to lammps_scatter (for integers) + SUBROUTINE lmp_scatter_int(self, name, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), DIMENSION(:), TARGET :: data + INTEGER(c_int) :: natoms, Ccount + INTEGER(c_int), PARAMETER :: Ctype = 0_c_int + TYPE(c_ptr) :: Cname, Cdata + REAL(c_double) :: dnatoms + CHARACTER(LEN=100) :: error_msg + + dnatoms = lmp_get_natoms(self) + IF (dnatoms > HUGE(1_c_int)) THEN + WRITE(error_msg,'(A,1X,I0,1X,A)') & + 'Cannot use library function scatter with more than', & + HUGE(0_c_int), 'atoms [Fortran/scatter]' + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, error_msg) + END IF + natoms = NINT(dnatoms, c_int) + + Cname = f2c_string(name) + Cdata = C_LOC(data(1)) + Ccount = SIZE(data) / natoms + + IF (Ccount /= 1 .AND. Ccount /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'lammps_scatter requires either 1 or 3 data per atom') + END IF + CALL lammps_scatter(self%handle, Cname, Ctype, Ccount, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_scatter_int + + ! equivalent function to lammps_scatter (for doubles) + SUBROUTINE lmp_scatter_atoms_double(self, name, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + REAL(c_double), DIMENSION(:), TARGET :: data + INTEGER(c_int) :: natoms, Ccount + INTEGER(c_int), PARAMETER :: Ctype = 1_c_int + TYPE(c_ptr) :: Cname, Cdata + REAL(c_double) :: dnatoms + CHARACTER(LEN=100) :: error_msg + + dnatoms = lmp_get_natoms(self) + IF (dnatoms > HUGE(1_c_int)) THEN + WRITE(error_msg,'(A,1X,I0,1X,A)') & + 'Cannot use library function scatter with more than', & + HUGE(0_c_int), 'atoms [Fortran/scatter]' + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, error_msg) + END IF + natoms = NINT(dnatoms, c_int) + + Cname = f2c_string(name) + Cdata = C_LOC(data(1)) + Ccount = SIZE(data) / natoms + + IF (Ccount /= 1 .AND. Ccount /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'scatter requires either 1 or 3 data per atom [Fortran/scatter]') + END IF + CALL lammps_scatter(self%handle, Cname, Ctype, Ccount, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_scatter_double + + ! equivalent function to lammps_scatter_subset (for integers) + SUBROUTINE lmp_scatter_subset_int(self, name, ids, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), DIMENSION(:), TARGET :: ids + INTEGER(c_int), DIMENSION(:), TARGET :: data + INTEGER(c_int), PARAMETER :: Ctype = 0_c_int + INTEGER(c_int) :: Cndata, Ccount + TYPE(c_ptr) :: Cdata, Cname, Cids + + Cndata = SIZE(ids, KIND=c_int) + Ccount = SIZE(data, KIND=c_int) / Cndata + IF (Ccount /= 1 .AND. Ccount /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'scatter_subset requires either 1 or 3 data per atom & + &[Fortran/scatter_subset]') + END IF + + Cname = f2c_string(name) + Cdata = C_LOC(data(1)) + Cids = C_LOC(ids(1)) + CALL lammps_scatter_subset(self%handle, Cname, Ctype, Ccount, & + Cndata, Cids, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_scatter_subset_int + + ! equivalent function to lammps_scatter_subset (for doubles) + SUBROUTINE lmp_scatter_subset_double(self, name, ids, data) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: name + INTEGER(c_int), DIMENSION(:), TARGET :: ids + REAL(c_double), DIMENSION(:), TARGET :: data + INTEGER(c_int), PARAMETER :: Ctype = 1_c_int + INTEGER(c_int) :: Cndata, Ccount + TYPE(c_ptr) :: Cdata, Cname, Cids + + Cndata = SIZE(ids, KIND=c_int) + Ccount = SIZE(data, KIND=c_int) / Cndata + IF (Ccount /= 1 .AND. Ccount /= 3) THEN + CALL lmp_error(self, LMP_ERROR_ALL + LMP_ERROR_WORLD, & + 'scatter_subset requires either 1 or 3 data per atom') + END IF + + Cname = f2c_string(name) + Cdata = C_LOC(data(1)) + Cids = C_LOC(ids(1)) + CALL lammps_scatter_subset(self%handle, Cname, Ctype, Ccount, & + Cndata, Cids, Cdata) + CALL lammps_free(Cname) + END SUBROUTINE lmp_scatter_subset_double + ! equivalent function to lammps_create_atoms (int ids or id absent) SUBROUTINE lmp_create_atoms_int(self, id, type, x, v, image, bexpand) CLASS(lammps), INTENT(IN) :: self diff --git a/src/library.cpp b/src/library.cpp index 1e3c96cdcf..9dc9a701f3 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -685,7 +685,7 @@ void lammps_commands_string(void *handle, const char *str) \verbatim embed:rst This number may be very large when running large simulations across -multiple processors. Depending on compile time choices, LAMMPS may be +multiple processes. Depending on compile time choices, LAMMPS may be using either 32-bit or a 64-bit integer to store this number. For portability this function returns thus a double precision floating point number, which can represent up to a 53-bit signed @@ -2263,7 +2263,7 @@ int lammps_set_variable(void *handle, char *name, char *str) // Library functions for scatter/gather operations of data // ---------------------------------------------------------------------- -/** Gather the named atom-based entity for all atoms across all processors, +/** Gather the named atom-based entity for all atoms across all processes, * in order. * \verbatim embed:rst @@ -2282,6 +2282,8 @@ x[0][2], x[1][0], x[1][1], x[1][2], x[2][0], :math:`\dots`); *natoms*), as queried by :cpp:func:`lammps_get_natoms`, :cpp:func:`lammps_extract_global`, or :cpp:func:`lammps_extract_setting`. +This function is not compatible with ``-DLAMMPS_BIGBIG``. + \endverbatim * * \param handle pointer to a previously created LAMMPS instance @@ -2415,7 +2417,7 @@ void lammps_gather_atoms(void *handle, char *name, int type, int count, void *da END_CAPTURE } -/** Gather the named atom-based entity for all atoms across all processors, +/** Gather the named atom-based entity for all atoms across all processes, * unordered. * \verbatim embed:rst @@ -2432,12 +2434,14 @@ of atoms, use :cpp:func:`lammps_gather_atoms_subset`. The *data* array will be in groups of *count* values, with *natoms* groups total, but not in order by atom ID (e.g., if *name* is *x* and *count* -is 3, then *data* might be something like = x[10][0], x[10][1], x[10][2], +is 3, then *data* might be something like x[10][0], x[10][1], x[10][2], x[2][0], x[2][1], x[2][2], x[4][0], :math:`\dots`); *data* must be pre-allocated by the caller to length (*count* :math:`\times` *natoms*), as queried by :cpp:func:`lammps_get_natoms`, :cpp:func:`lammps_extract_global`, or :cpp:func:`lammps_extract_setting`. +This function is not compatible with ``-DLAMMPS_BIGBIG``. + \endverbatim * * \param handle: pointer to a previously created LAMMPS instance @@ -2599,6 +2603,8 @@ x[100][2], x[57][0], x[57][1], x[57][2], x[210][0], :math:`\dots`); *data* must be pre-allocated by the caller to length (*count* :math:`\times` *ndata*). +This function is not compatible with ``-DLAMMPS_BIGBIG``. + \endverbatim * * \param handle: pointer to a previously created LAMMPS instance @@ -2745,20 +2751,22 @@ void lammps_gather_atoms_subset(void *handle, char *name, int type, int count, END_CAPTURE } -/** Scatter the named atom-based entities in *data* to all processors. +/** Scatter the named atom-based entities in *data* to all processes. * \verbatim embed:rst This subroutine takes data stored in a one-dimensional array supplied by the -user and scatters them to all atoms on all processors. The data must be +user and scatters them to all atoms on all processes. The data must be ordered by atom ID, with the requirement that the IDs be consecutive. Use :cpp:func:`lammps_scatter_atoms_subset` to scatter data for some (or all) atoms, unordered. The *data* array needs to be ordered in groups of *count* values, sorted by atom ID (e.g., if *name* is *x* and *count* = 3, then -*data* = x[0][0], x[0][1], x[0][2], x[1][0], x[1][1], x[1][2], x[2][0], -:math:`\dots`); *data* must be of length (*count* :math:`\times` *natoms*). +*data* = {x[0][0], x[0][1], x[0][2], x[1][0], x[1][1], x[1][2], x[2][0], +:math:`\dots`}); *data* must be of length (*count* :math:`\times` *natoms*). + +This function is not compatible with ``-DLAMMPS_BIGBIG``. \endverbatim * @@ -2768,7 +2776,7 @@ atom ID (e.g., if *name* is *x* and *count* = 3, then * \param count number of per-atom values (e.g., 1 for *type* or *charge*, * 3 for *x* or *f*); use *count* = 3 with *image* if you have * a single image flag packed into (*x*,*y*,*z*) components. - * \param data per-atom values packed in a 1-dimensional array of length + * \param data per-atom values packed in a one-dimensional array of length * *natoms* \* *count*. * */ @@ -2879,12 +2887,12 @@ void lammps_scatter_atoms(void *handle, char *name, int type, int count, void *d } /** Scatter the named atom-based entities in *data* from a subset of atoms - * to all processors. + * to all processes. * \verbatim embed:rst This subroutine takes data stored in a one-dimensional array supplied by the -user and scatters them to a subset of atoms on all processors. The array +user and scatters them to a subset of atoms on all processes. The array *data* contains data associated with atom IDs, but there is no requirement that the IDs be consecutive, as they are provided in a separate array. Use :cpp:func:`lammps_scatter_atoms` to scatter data for all atoms, in order. @@ -2895,6 +2903,8 @@ to be the array {x[1][0], x[1][1], x[1][2], x[100][0], x[100][1], x[100][2], x[57][0], x[57][1], x[57][2]}, then *count* = 3, *ndata* = 3, and *ids* would be {1, 100, 57}. +This function is not compatible with ``-DLAMMPS_BIGBIG``. + \endverbatim * * \param handle: pointer to a previously created LAMMPS instance @@ -3146,6 +3156,43 @@ void lammps_gather_bonds(void *handle, void *data) END_CAPTURE } +/** Gather the named per-atom, per-atom fix, per-atom compute, or fix property/atom-based entities + * from all processes, in order by atom ID. + * +\verbatim embed:rst + +This subroutine gathers data from all processes and stores them in a one-dimensional array +allocated by the user. The array *data* will be ordered by atom ID, which requires consecutive IDs +(1 to *natoms*\ ). If you need a similar array but for non-consecutive atom IDs, see +:cpp:func:`lammps_gather_concat`; for a similar array but for a subset of atoms, see +:cpp:func:`lammps_gather_subset`. + +The *data* array will be ordered in groups of *count* values, sorted by atom ID (e.g., if *name* is +*x*, then *data* is {x[0][0], x[0][1], x[0][2], x[1][0], x[1][1], x[1][2], x[2][0], +:math:`\dots`}); *data* must be pre-allocated by the caller to the correct length +(*count*\ :math:`{}\times{}`\ *natoms*), as queried by :cpp:func:`lammps_get_natoms`, +:cpp:func:`lammps_extract_global`, or :cpp:func:`lammps_extract_setting`. + +This function will return an error if fix or compute data are requested and the fix or compute ID +given does not have per-atom data. + +This function is not compatible with ``-DLAMMPS_BIGBIG``. + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance + * \param name desired quantity (e.g., "x" or "f" for atom properties, "f_id" for per-atom fix + * data, "c_id" for per-atom compute data, "d_name" or "i_name" for fix + * property/atom vectors with *count* = 1, "d2_name" or "i2_name" for fix + * property/atom vectors with *count* > 1) + * \param type 0 for ``int`` values, 1 for ``double`` values + * \param count number of per-atom values (e.g., 1 for *type* or *charge*, 3 for *x* or *f*); + * use *count* = 3 with *image* if you want the image flags unpacked into + * (*x*,*y*,*z*) components. + * \param data per-atom values packed into a one-dimensional array of length + * *natoms* \* *count*. + * + */ /* ---------------------------------------------------------------------- Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France) gather the named atom-based entity for all atoms @@ -3381,6 +3428,44 @@ void lammps_gather(void *handle, char *name, int type, int count, void *data) END_CAPTURE } +/** Gather the named per-atom, per-atom fix, per-atom compute, or fix property/atom-based entities + * from all processes, unordered. + * +\verbatim embed:rst + +This subroutine gathers data for all atoms and stores them in a one-dimensional array allocated by +the user. The data will be a concatenation of chunks from each processor's owned atoms, in +whatever order the atoms are in on each processor. This process has no requirement that the atom +IDs be consecutive. If you need the ID of each atom, you can do another call to either +:cpp:func:`lammps_gather_atoms_concat` or :cpp:func:`lammps_gather_concat` with *name* set to +``id``. If you have consecutive IDs and want the data to be in order, use +:cpp:func:`lammps_gather`; for a similar array but for a subset of atoms, use +:cpp:func:`lammps_gather_subset`. + +The *data* array will be in groups of *count* values, with *natoms* groups total, but not in order +by atom ID (e.g., if *name* is *x* and *count* is 3, then *data* might be something like +{x[10][0], x[10][1], x[10][2], x[2][0], x[2][1], x[2][2], x[4][0], :math:`\dots`}); *data* must be +pre-allocated by the caller to length (*count* :math:`\times` *natoms*), as queried by +:cpp:func:`lammps_get_natoms`, :cpp:func:`lammps_extract_global`, or +:cpp:func:`lammps_extract_setting`. + +This function is not compatible with ``-DLAMMPS_BIGBIG``. + +\endverbatim + * + * \param handle: pointer to a previously created LAMMPS instance + * \param name: desired quantity (e.g., "x" or "f" for atom properties, "f_id" for per-atom fix + * data, "c_id" for per-atom compute data, "d_name" or "i_name" for fix + * property/atom vectors with count = 1, "d2_name" or "i2_name" for fix + * property/atom vectors with count > 1) + * \param type: 0 for ``int`` values, 1 for ``double`` values + * \param count: number of per-atom values (e.g., 1 for *type* or *charge*, 3 for *x* or *f*); + * use *count* = 3 with *image* if you want the image flags unpacked into + * (*x*,*y*,*z*) components. + * \param data: per-atom values packed into a one-dimensional array of length + * *natoms* \* *count*. + * + */ /* ---------------------------------------------------------------------- Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France) gather the named atom-based entity for all atoms @@ -3633,6 +3718,41 @@ void lammps_gather_concat(void *handle, char *name, int type, int count, void *d END_CAPTURE } +/** Gather the named per-atom, per-atom fix, per-atom compute, or fix property/atom-based entities + * from all processes for a subset of atoms. + * +\verbatim embed:rst + +This subroutine gathers data for the requested atom IDs and stores them in a one-dimensional array +allocated by the user. The data will be ordered by atom ID, but there is no requirement that the +IDs be consecutive. If you wish to return a similar array for *all* the atoms, use +:cpp:func:`lammps_gather` or :cpp:func:`lammps_gather_concat`. + +The *data* array will be in groups of *count* values, sorted by atom ID in the same order as the +array *ids* (e.g., if *name* is *x*, *count* = 3, and *ids* is {100, 57, 210}, then *data* might +look like {x[100][0], x[100][1], x[100][2], x[57][0], x[57][1], x[57][2], x[210][0], +:math:`\dots`}); *ids* must be provided by the user with length *ndata*, and *data* must be +pre-allocated by the caller to length (*count*\ :math:`{}\times{}`\ *ndata*). + +This function is not compatible with ``-DLAMMPS_BIGBIG``. + +\endverbatim + * + * \param handle: pointer to a previously created LAMMPS instance + * \param name desired quantity (e.g., "x" or "f" for atom properties, "f_id" for per-atom fix + * data, "c_id" for per-atom compute data, "d_name" or "i_name" for fix + * property/atom vectors with *count* = 1, "d2_name" or "i2_name" for fix + * property/atom vectors with *count* > 1) + * \param type 0 for ``int`` values, 1 for ``double`` values + * \param count number of per-atom values (e.g., 1 for *type* or *charge*, 3 for *x* or *f*); + * use *count* = 3 with *image* if you want the image flags unpacked into + * (*x*,*y*,*z*) components. + * \param ndata: number of atoms for which to return data (can be all of them) + * \param ids: list of *ndata* atom IDs for which to return data + * \param data per-atom values packed into a one-dimensional array of length + * *ndata* \* *count*. + * + */ /* ---------------------------------------------------------------------- Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France) gather the named atom-based entity for all atoms @@ -3884,6 +4004,37 @@ void lammps_gather_subset(void *handle, char *name, END_CAPTURE } +/** Scatter the named per-atom, per-atom fix, per-atom compute, or fix property/atom-based + * entity in *data* to all processes. + * +\verbatim embed:rst + +This subroutine takes data stored in a one-dimensional array supplied by the user and scatters +them to all atoms on all processes. The data must be ordered by atom ID, with the requirement that +the IDs be consecutive. Use :cpp:func:`lammps_scatter_subset` to scatter data for some (or all) +atoms, unordered. + +The *data* array needs to be ordered in groups of *count* values, sorted by atom ID (e.g., if +*name* is *x* and *count* = 3, then *data* = {x[0][0], x[0][1], x[0][2], x[1][0], x[1][1], +x[1][2], x[2][0], :math:`\dots`}); *data* must be of length (*count* :math:`\times` *natoms*). + +This function is not compatible with ``-DLAMMPS_BIGBIG``. + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance + * \param name desired quantity (e.g., "x" or "f" for atom properties, "f_id" for per-atom fix + * data, "c_id" for per-atom compute data, "d_name" or "i_name" for fix + * property/atom vectors with *count* = 1, "d2_name" or "i2_name" for fix + * property/atom vectors with *count* > 1) + * \param type 0 for ``int`` values, 1 for ``double`` values + * \param count number of per-atom values (e.g., 1 for *type* or *charge*, + * 3 for *x* or *f*); use *count* = 3 with *image* if you have + * a single image flag packed into (*x*,*y*,*z*) components. + * \param data per-atom values packed in a one-dimensional array of length + * *natoms* \* *count*. + * + */ /* ---------------------------------------------------------------------- Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France) scatter the named atom-based entity in data to all atoms @@ -4103,6 +4254,42 @@ void lammps_scatter(void *handle, char *name, int type, int count, void *data) END_CAPTURE } +/** Scatter the named per-atom, per-atom fix, per-atom compute, or fix property/atom-based + * entities in *data* from a subset of atoms to all processes. + * +\verbatim embed:rst + +This subroutine takes data stored in a one-dimensional array supplied by the +user and scatters them to a subset of atoms on all processes. The array +*data* contains data associated with atom IDs, but there is no requirement that +the IDs be consecutive, as they are provided in a separate array. +Use :cpp:func:`lammps_scatter` to scatter data for all atoms, in order. + +The *data* array needs to be organized in groups of *count* values, with the +groups in the same order as the array *ids*. For example, if you want *data* +to be the array {x[1][0], x[1][1], x[1][2], x[100][0], x[100][1], x[100][2], +x[57][0], x[57][1], x[57][2]}, then *count* = 3, *ndata* = 3, and *ids* would +be {1, 100, 57}. + +This function is not compatible with ``-DLAMMPS_BIGBIG``. + +\endverbatim + * + * \param handle: pointer to a previously created LAMMPS instance + * \param name desired quantity (e.g., "x" or "f" for atom properties, "f_id" for per-atom fix + * data, "c_id" for per-atom compute data, "d_name" or "i_name" for fix + * property/atom vectors with *count* = 1, "d2_name" or "i2_name" for fix + * property/atom vectors with *count* > 1) + * \param type: 0 for ``int`` values, 1 for ``double`` values + * \param count: number of per-atom values (e.g., 1 for *type* or *charge*, + * 3 for *x* or *f*); use *count* = 3 with "image" if you want + * single image flags unpacked into (*x*,*y*,*z*) + * \param ndata: number of atoms listed in *ids* and *data* arrays + * \param ids: list of *ndata* atom IDs to scatter data to + * \param data per-atom values packed in a 1-dimensional array of length + * *ndata* \* *count*. + * + */ /* ---------------------------------------------------------------------- Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France) scatter the named atom-based entity in data to a subset of atoms