1 // clang-format off
2 /* ----------------------------------------------------------------------
3    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
4    https://www.lammps.org/, Sandia National Laboratories
5    Steve Plimpton, sjplimp@sandia.gov
6 
7    Copyright (2003) Sandia Corporation.  Under the terms of Contract
8    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
9    certain rights in this software.  This software is distributed under
10    the GNU General Public License.
11 
12    See the README file in the top-level LAMMPS directory.
13 ------------------------------------------------------------------------- */
14 
15 // C style library interface to LAMMPS.
16 // See the manual for detailed documentation.
17 
18 #define LAMMPS_LIB_MPI 1
19 #include "library.h"
20 #include <mpi.h>
21 
22 #include "accelerator_kokkos.h"
23 #include "atom.h"
24 #include "atom_vec.h"
25 #include "comm.h"
26 #include "compute.h"
27 #include "domain.h"
28 #include "dump.h"
29 #include "error.h"
30 #include "fix.h"
31 #include "fix_external.h"
32 #include "force.h"
33 #include "group.h"
34 #include "info.h"
35 #include "input.h"
36 #include "lmppython.h"
37 #include "memory.h"
38 #include "modify.h"
39 #include "molecule.h"
40 #include "neigh_list.h"
41 #include "neighbor.h"
42 #include "output.h"
43 #if defined(LMP_PLUGIN)
44 #include "plugin.h"
45 #endif
46 #include "region.h"
47 #include "respa.h"
48 #include "thermo.h"
49 #include "timer.h"
50 #include "universe.h"
51 #include "update.h"
52 #include "variable.h"
53 
54 #include <cstring>
55 
56 #if defined(LAMMPS_EXCEPTIONS)
57 #include "exceptions.h"
58 #endif
59 
60 using namespace LAMMPS_NS;
61 
62 // for printing the non-null pointer argument warning only once
63 
64 static int ptr_argument_flag = 1;
ptr_argument_warning()65 static void ptr_argument_warning()
66 {
67   if (!ptr_argument_flag) return;
68   fprintf(stderr,"Using a 'void **' argument to return the LAMMPS handle "
69           "is deprecated.  Please use the return value instead.\n");
70   ptr_argument_flag = 0;
71 }
72 
73 // ----------------------------------------------------------------------
74 // utility macros
75 // ----------------------------------------------------------------------
76 
77 /* ----------------------------------------------------------------------
78    macros for optional code path which captures all exceptions
79    and stores the last error message. These assume there is a variable lmp
80    which is a pointer to the current LAMMPS instance.
81 
82    Usage:
83 
84    BEGIN_CAPTURE
85    {
86      // code paths which might throw exception
87      ...
88    }
89    END_CAPTURE
90 ------------------------------------------------------------------------- */
91 
92 #ifdef LAMMPS_EXCEPTIONS
93 #define BEGIN_CAPTURE \
94   Error *error = lmp->error; \
95   try
96 
97 #define END_CAPTURE \
98   catch(LAMMPSAbortException &ae) { \
99     int nprocs = 0; \
100     MPI_Comm_size(ae.universe, &nprocs ); \
101     \
102     if (nprocs > 1) { \
103       error->set_last_error(ae.message, ERROR_ABORT); \
104     } else { \
105       error->set_last_error(ae.message, ERROR_NORMAL); \
106     } \
107   } catch(LAMMPSException &e) { \
108     error->set_last_error(e.message, ERROR_NORMAL); \
109   }
110 #else
111 #define BEGIN_CAPTURE
112 #define END_CAPTURE
113 #endif
114 
115 // ----------------------------------------------------------------------
116 // Library functions to create/destroy an instance of LAMMPS
117 // ----------------------------------------------------------------------
118 
119 /** Create instance of the LAMMPS class and return pointer to it.
120  *
121 \verbatim embed:rst
122 
123 The :cpp:func:`lammps_open` function creates a new :cpp:class:`LAMMPS
124 <LAMMPS_NS::LAMMPS>` class instance while passing in a list of strings
125 as if they were :doc:`command-line arguments <Run_options>` for the
126 LAMMPS executable, and an MPI communicator for LAMMPS to run under.
127 Since the list of arguments is **exactly** as when called from the
128 command line, the first argument would be the name of the executable and
129 thus is otherwise ignored.  However ``argc`` may be set to 0 and then
130 ``argv`` may be ``NULL``.  If MPI is not yet initialized, ``MPI_Init()``
131 will be called during creation of the LAMMPS class instance.
132 
133 If for some reason the creation or initialization of the LAMMPS instance
134 fails a null pointer is returned.
135 
136 .. versionchanged:: 18Sep2020
137 
138    This function now has the pointer to the created LAMMPS class
139    instance as return value.  For backward compatibility it is still
140    possible to provide the address of a pointer variable as final
141    argument *ptr*\ .
142 
143 .. deprecated:: 18Sep2020
144 
145    The *ptr* argument will be removed in a future release of LAMMPS.
146    It should be set to ``NULL`` instead.
147 
148 .. note::
149 
150    This function is **only** declared when the code using the LAMMPS
151    ``library.h`` include file is compiled with ``-DLAMMPS_LIB_MPI``,
152    or contains a ``#define LAMMPS_LIB_MPI 1`` statement before
153    ``#include "library.h"``.  Otherwise you can only use the
154    :cpp:func:`lammps_open_no_mpi` or :cpp:func:`lammps_open_fortran`
155    functions.
156 
157 *See also*
158    :cpp:func:`lammps_open_no_mpi`, :cpp:func:`lammps_open_fortran`
159 
160 \endverbatim
161  *
162  * \param  argc  number of command line arguments
163  * \param  argv  list of command line argument strings
164  * \param  comm  MPI communicator for this LAMMPS instance
165  * \param  ptr   pointer to a void pointer variable which serves
166  *               as a handle; may be ``NULL``
167  * \return       pointer to new LAMMPS instance cast to ``void *`` */
168 
lammps_open(int argc,char ** argv,MPI_Comm comm,void ** ptr)169 void *lammps_open(int argc, char **argv, MPI_Comm comm, void **ptr)
170 {
171   LAMMPS *lmp = nullptr;
172   lammps_mpi_init();
173   if (ptr) ptr_argument_warning();
174 
175 #ifdef LAMMPS_EXCEPTIONS
176   try
177   {
178     lmp = new LAMMPS(argc, argv, comm);
179     if (ptr) *ptr = (void *) lmp;
180   }
181   catch(LAMMPSException &e) {
182     fmt::print(stderr, "LAMMPS Exception: {}", e.message);
183     if (ptr) *ptr = nullptr;
184   }
185 #else
186   lmp = new LAMMPS(argc, argv, comm);
187   if (ptr) *ptr = (void *) lmp;
188 #endif
189   return (void *) lmp;
190 }
191 
192 /* ---------------------------------------------------------------------- */
193 
194 /** Variant of ``lammps_open()`` that implicitly uses ``MPI_COMM_WORLD``.
195  *
196 \verbatim embed:rst
197 
198 This function is a version of :cpp:func:`lammps_open`, that is missing
199 the MPI communicator argument.  It will use ``MPI_COMM_WORLD`` instead.
200 The type and purpose of arguments and return value are otherwise the
201 same.
202 
203 Outside of the convenience, this function is useful, when the LAMMPS
204 library was compiled in serial mode, but the calling code runs in
205 parallel and the ``MPI_Comm`` data type of the STUBS library would not
206 be compatible with that of the calling code.
207 
208 If for some reason the creation or initialization of the LAMMPS instance
209 fails a null pointer is returned.
210 
211 .. versionchanged:: 18Sep2020
212 
213    This function now has the pointer to the created LAMMPS class
214    instance as return value.  For backward compatibility it is still
215    possible to provide the address of a pointer variable as final
216    argument *ptr*\ .
217 
218 .. deprecated:: 18Sep2020
219 
220    The *ptr* argument will be removed in a future release of LAMMPS.
221    It should be set to ``NULL`` instead.
222 
223 
224 *See also*
225    :cpp:func:`lammps_open`, :cpp:func:`lammps_open_fortran`
226 
227 \endverbatim
228  *
229  * \param  argc  number of command line arguments
230  * \param  argv  list of command line argument strings
231  * \param  ptr   pointer to a void pointer variable
232  *               which serves as a handle; may be ``NULL``
233  * \return       pointer to new LAMMPS instance cast to ``void *`` */
234 
lammps_open_no_mpi(int argc,char ** argv,void ** ptr)235 void *lammps_open_no_mpi(int argc, char **argv, void **ptr)
236 {
237   return lammps_open(argc,argv,MPI_COMM_WORLD,ptr);
238 }
239 
240 /* ---------------------------------------------------------------------- */
241 
242 /** Variant of ``lammps_open()`` using a Fortran MPI communicator.
243  *
244 \verbatim embed:rst
245 
246 This function is a version of :cpp:func:`lammps_open`, that uses an
247 integer for the MPI communicator as the MPI Fortran interface does.  It
248 is used in the :f:func:`lammps` constructor of the LAMMPS Fortran
249 module.  Internally it converts the *f_comm* argument into a C-style MPI
250 communicator with ``MPI_Comm_f2c()`` and then calls
251 :cpp:func:`lammps_open`.
252 
253 If for some reason the creation or initialization of the LAMMPS instance
254 fails a null pointer is returned.
255 
256 .. versionadded:: 18Sep2020
257 
258 *See also*
259    :cpp:func:`lammps_open_fortran`, :cpp:func:`lammps_open_no_mpi`
260 
261 \endverbatim
262  *
263  * \param  argc   number of command line arguments
264  * \param  argv   list of command line argument strings
265  * \param  f_comm Fortran style MPI communicator for this LAMMPS instance
266  * \return        pointer to new LAMMPS instance cast to ``void *`` */
267 
lammps_open_fortran(int argc,char ** argv,int f_comm)268 void *lammps_open_fortran(int argc, char **argv, int f_comm)
269 {
270   lammps_mpi_init();
271   MPI_Comm c_comm = MPI_Comm_f2c((MPI_Fint)f_comm);
272   return lammps_open(argc, argv, c_comm, nullptr);
273 }
274 
275 /* ---------------------------------------------------------------------- */
276 
277 /** Delete a LAMMPS instance created by lammps_open() or its variants.
278  *
279 \verbatim embed:rst
280 
281 This function deletes the LAMMPS class instance pointed to by ``handle``
282 that was created by one of the :cpp:func:`lammps_open` variants.  It
283 does **not** call ``MPI_Finalize()`` to allow creating and deleting
284 multiple LAMMPS instances concurrently or sequentially.  See
285 :cpp:func:`lammps_mpi_finalize` for a function performing this operation.
286 
287 \endverbatim
288  *
289  * \param  handle  pointer to a previously created LAMMPS instance */
290 
lammps_close(void * handle)291 void lammps_close(void *handle)
292 {
293   LAMMPS *lmp = (LAMMPS *) handle;
294   delete lmp;
295 }
296 
297 /* ---------------------------------------------------------------------- */
298 
299 /** Ensure the MPI environment is initialized.
300  *
301 \verbatim embed:rst
302 
303 The MPI standard requires that any MPI application must call
304 ``MPI_Init()`` exactly once before performing any other MPI function
305 calls.  This function checks, whether MPI is already initialized and
306 calls ``MPI_Init()`` in case it is not.
307 
308 .. versionadded:: 18Sep2020
309 
310 \endverbatim */
311 
lammps_mpi_init()312 void lammps_mpi_init()
313 {
314   int flag;
315   MPI_Initialized(&flag);
316 
317   if (!flag) {
318     // provide a dummy argc and argv for MPI_Init().
319     int argc = 1;
320     char *args[] = { (char *)"liblammps" , nullptr  };
321     char **argv = args;
322     MPI_Init(&argc,&argv);
323   }
324 }
325 
326 /* ---------------------------------------------------------------------- */
327 
328 /** Shut down the MPI infrastructure.
329  *
330 \verbatim embed:rst
331 
332 The MPI standard requires that any MPI application calls
333 ``MPI_Finalize()`` before exiting.  Even if a calling program does not
334 do any MPI calls, MPI is still initialized internally to avoid errors
335 accessing any MPI functions.  This function should then be called right
336 before exiting the program to wait until all (parallel) tasks are
337 completed and then MPI is cleanly shut down.  After calling this
338 function no more MPI calls may be made.
339 
340 .. versionadded:: 18Sep2020
341 
342 *See also*
343    :cpp:func:`lammps_kokkos_finalize`, :cpp:func:`lammps_python_finalize`
344 \endverbatim */
345 
lammps_mpi_finalize()346 void lammps_mpi_finalize()
347 {
348   int flag;
349   MPI_Initialized(&flag);
350   if (flag) {
351     MPI_Finalized(&flag);
352     if (!flag) {
353       MPI_Barrier(MPI_COMM_WORLD);
354       MPI_Finalize();
355     }
356   }
357 }
358 
359 /* ---------------------------------------------------------------------- */
360 
361 /** Shut down the Kokkos library environment.
362  *
363 \verbatim embed:rst
364 
365 The Kokkos library may only be initialized once during the execution of
366 a process.  This is done automatically the first time Kokkos
367 functionality is used.  This requires that the Kokkos environment
368 must be explicitly shut down after any LAMMPS instance using it is
369 closed (to release associated resources).
370 After calling this function no Kokkos functionality may be used.
371 
372 .. versionadded:: 2Jul2021
373 
374 *See also*
375    :cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_python_finalize`
376 \endverbatim */
377 
lammps_kokkos_finalize()378 void lammps_kokkos_finalize()
379 {
380   KokkosLMP::finalize();
381 }
382 
383 /* ---------------------------------------------------------------------- */
384 
385 /** Clear the embedded Python environment
386  *
387 \verbatim embed:rst
388 
389 This function resets and clears an embedded Python environment
390 by calling the `Py_Finalize() function
391 <https://docs.python.org/3/c-api/init.html#c.Py_FinalizeEx>`_
392 of the embedded Python library, if enabled.
393 This call would free up all allocated resources and release
394 loaded shared objects.
395 
396 However, this is **not** done when a LAMMPS instance is deleted because
397 a) LAMMPS may have been used through the Python module and thus
398 the Python interpreter is external and not embedded into LAMMPS
399 and therefore may not be reset by LAMMPS b) some Python modules
400 and extensions, most notably NumPy, are not compatible with being
401 initialized multiple times, which would happen if additional
402 LAMMPS instances using Python would be created *after*
403 after calling Py_Finalize().
404 
405 This function can be called to explicitly clear the Python
406 environment in case it is safe to do so.
407 
408 .. versionadded:: TBD
409 
410 *See also*
411    :cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_kokkos_finalize`
412 \endverbatim */
413 
lammps_python_finalize()414 void lammps_python_finalize()
415 {
416   Python::finalize();
417 }
418 
419 // ----------------------------------------------------------------------
420 // Library functions to process commands
421 // ----------------------------------------------------------------------
422 
423 /** Process LAMMPS input from a file.
424  *
425 \verbatim embed:rst
426 
427 This function processes commands in the file pointed to by *filename*
428 line by line and thus functions very similar to the :doc:`include
429 <include>` command. The function returns when the end of the file is
430 reached and the commands have completed.
431 
432 The actual work is done by the functions
433 :cpp:func:`Input::file(const char *)<void LAMMPS_NS::Input::file(const char *)>`
434 and :cpp:func:`Input::file()<void LAMMPS_NS::Input::file()>`.
435 
436 \endverbatim
437  *
438  * \param  handle    pointer to a previously created LAMMPS instance
439  * \param  filename  name of a file with LAMMPS input */
440 
lammps_file(void * handle,const char * filename)441 void lammps_file(void *handle, const char *filename)
442 {
443   LAMMPS *lmp = (LAMMPS *) handle;
444 
445   BEGIN_CAPTURE
446   {
447     if (lmp->update->whichflag != 0)
448       lmp->error->all(FLERR,"Library error: issuing LAMMPS commands "
449                       "during a run is not allowed.");
450     else
451       lmp->input->file(filename);
452   }
453   END_CAPTURE
454 }
455 
456 /* ---------------------------------------------------------------------- */
457 
458 /** Process a single LAMMPS input command from a string.
459  *
460 \verbatim embed:rst
461 
462 This function tells LAMMPS to execute the single command in the string
463 *cmd*.  The entire string is considered as command and need not have a
464 (final) newline character.  Newline characters in the body of the
465 string, however, will be treated as part of the command and will **not**
466 start a second command.  The function :cpp:func:`lammps_commands_string`
467 processes a string with multiple command lines.
468 
469 The function returns the name of the command on success or ``NULL`` when
470 passing a string without a command.
471 
472 \endverbatim
473  *
474  * \param  handle  pointer to a previously created LAMMPS instance
475  * \param  cmd     string with a single LAMMPS command
476  * \return         string with parsed command name or ``NULL`` */
477 
lammps_command(void * handle,const char * cmd)478 char *lammps_command(void *handle, const char *cmd)
479 {
480   LAMMPS *lmp = (LAMMPS *) handle;
481   char *result = nullptr;
482 
483   BEGIN_CAPTURE
484   {
485     if (lmp->update->whichflag != 0)
486       lmp->error->all(FLERR,"Library error: issuing LAMMPS commands "
487                       "during a run is not allowed.");
488     else
489       result = lmp->input->one(cmd);
490   }
491   END_CAPTURE
492 
493   return result;
494 }
495 
496 /* ---------------------------------------------------------------------- */
497 
498 /** Process multiple LAMMPS input commands from list of strings.
499  *
500 \verbatim embed:rst
501 
502 This function processes multiple commands from a list of strings by
503 first concatenating the individual strings in *cmds* into a single
504 string, inserting newline characters as needed.  The combined string
505 is passed to :cpp:func:`lammps_commands_string` for processing.
506 
507 \endverbatim
508  *
509  * \param  handle  pointer to a previously created LAMMPS instance
510  * \param  ncmd    number of lines in *cmds*
511  * \param  cmds    list of strings with LAMMPS commands */
512 
lammps_commands_list(void * handle,int ncmd,const char ** cmds)513 void lammps_commands_list(void *handle, int ncmd, const char **cmds)
514 {
515   std::string allcmds;
516 
517   for (int i = 0; i < ncmd; i++) {
518     allcmds.append(cmds[i]);
519     if (allcmds.empty() || (allcmds.back() != '\n')) allcmds.append(1,'\n');
520   }
521 
522   lammps_commands_string(handle,allcmds.c_str());
523 }
524 
525 /* ---------------------------------------------------------------------- */
526 
527 /** Process a block of LAMMPS input commands from a single string.
528  *
529 \verbatim embed:rst
530 
531 This function processes a multi-line string similar to a block of
532 commands from a file.  The string may have multiple lines (separated by
533 newline characters) and also single commands may be distributed over
534 multiple lines with continuation characters ('&').  Those lines are
535 combined by removing the '&' and the following newline character.  After
536 this processing the string is handed to LAMMPS for parsing and
537 executing.
538 
539 .. note::
540 
541    Multi-line commands enabled by triple quotes will NOT work with
542    this function.
543 
544 \endverbatim
545  *
546  * \param  handle  pointer to a previously created LAMMPS instance
547  * \param  str     string with block of LAMMPS input commands */
548 
lammps_commands_string(void * handle,const char * str)549 void lammps_commands_string(void *handle, const char *str)
550 {
551   LAMMPS *lmp = (LAMMPS *) handle;
552 
553   // copy str and convert from CR-LF (DOS-style) to LF (Unix style) line
554   int n = strlen(str);
555   char *ptr, *copy = new char[n+1];
556 
557   for (ptr = copy; *str != '\0'; ++str) {
558     if ((str[0] == '\r') && (str[1] == '\n')) continue;
559     *ptr++ = *str;
560   }
561   *ptr = '\0';
562 
563   BEGIN_CAPTURE
564   {
565     if (lmp->update->whichflag != 0) {
566       lmp->error->all(FLERR,"Library error: issuing LAMMPS command during run");
567     }
568 
569     n = strlen(copy);
570     ptr = copy;
571     for (int i=0; i < n; ++i) {
572 
573       // handle continuation character as last character in line or string
574       if ((copy[i] == '&') && (copy[i+1] == '\n'))
575         copy[i+1] = copy[i] = ' ';
576       else if ((copy[i] == '&') && (copy[i+1] == '\0'))
577         copy[i] = ' ';
578 
579       if (copy[i] == '\n') {
580         copy[i] = '\0';
581         lmp->input->one(ptr);
582         ptr = copy + i+1;
583       } else if (copy[i+1] == '\0')
584         lmp->input->one(ptr);
585     }
586   }
587   END_CAPTURE
588 
589   delete[] copy;
590 }
591 
592 // -----------------------------------------------------------------------
593 // Library functions to extract info from LAMMPS or set data in LAMMPS
594 // -----------------------------------------------------------------------
595 
596 /** Return the total number of atoms in the system.
597  *
598 \verbatim embed:rst
599 
600 This number may be very large when running large simulations across
601 multiple processors.  Depending on compile time choices, LAMMPS may be
602 using either 32-bit or a 64-bit integer to store this number. For
603 portability this function returns thus a double precision
604 floating point number, which can represent up to a 53-bit signed
605 integer exactly (:math:`\approx 10^{16}`).
606 
607 As an alternative, you can use :cpp:func:`lammps_extract_global`
608 and cast the resulting pointer to an integer pointer of the correct
609 size and dereference it.  The size of that integer (in bytes) can be
610 queried by calling :cpp:func:`lammps_extract_setting` to return
611 the size of a ``bigint`` integer.
612 
613 .. versionchanged:: 18Sep2020
614 
615    The type of the return value was changed from ``int`` to ``double``
616    to accommodate reporting atom counts for larger systems that would
617    overflow a 32-bit int without having to depend on a 64-bit bit
618    integer type definition.
619 
620 \endverbatim
621  *
622  * \param  handle  pointer to a previously created LAMMPS instance
623  * \return         total number of atoms or 0 if value is too large */
624 
lammps_get_natoms(void * handle)625 double lammps_get_natoms(void *handle)
626 {
627   LAMMPS *lmp = (LAMMPS *) handle;
628 
629   double natoms = static_cast<double>(lmp->atom->natoms);
630   if (natoms > 9.0e15) return 0; // TODO:XXX why not -1?
631   return natoms;
632 }
633 
634 /* ---------------------------------------------------------------------- */
635 
636 /** Get current value of a thermo keyword.
637  *
638 \verbatim embed:rst
639 
640 This function returns the current value of a :doc:`thermo keyword
641 <thermo_style>`.  Unlike :cpp:func:`lammps_extract_global` it does not
642 give access to the storage of the desired data but returns its value as
643 a ``double``, so it can also return information that is computed on-the-fly.
644 
645 \endverbatim
646  *
647  * \param  handle   pointer to a previously created LAMMPS instance
648  * \param  keyword  string with the name of the thermo keyword
649  * \return          value of the requested thermo property or 0.0 */
650 
lammps_get_thermo(void * handle,const char * keyword)651 double lammps_get_thermo(void *handle, const char *keyword)
652 {
653   LAMMPS *lmp = (LAMMPS *) handle;
654   double dval = 0.0;
655 
656   BEGIN_CAPTURE
657   {
658     lmp->output->thermo->evaluate_keyword(keyword,&dval);
659   }
660   END_CAPTURE
661 
662   return dval;
663 }
664 
665 /* ---------------------------------------------------------------------- */
666 
667 /** Extract simulation box parameters.
668  *
669 \verbatim embed:rst
670 
671 This function (re-)initializes the simulation box and boundary
672 information and then assign the designated data to the locations in the
673 pointers passed as arguments. Any argument (except the first) may be
674 a NULL pointer and then will not be assigned.
675 
676 \endverbatim
677  *
678  * \param  handle   pointer to a previously created LAMMPS instance
679  * \param  boxlo    pointer to 3 doubles where the lower box boundary is stored
680  * \param  boxhi    pointer to 3 doubles where the upper box boundary is stored
681  * \param  xy       pointer to a double where the xy tilt factor is stored
682  * \param  yz       pointer to a double where the yz tilt factor is stored
683  * \param  xz       pointer to a double where the xz tilt factor is stored
684  * \param  pflags   pointer to 3 ints, set to 1 for periodic boundaries
685                     and 0 for non-periodic
686  * \param  boxflag  pointer to an int, which is set to 1 if the box will be
687  *                  changed during a simulation by a fix and 0 if not. */
688 
lammps_extract_box(void * handle,double * boxlo,double * boxhi,double * xy,double * yz,double * xz,int * pflags,int * boxflag)689 void lammps_extract_box(void *handle, double *boxlo, double *boxhi,
690                         double *xy, double *yz, double *xz,
691                         int *pflags, int *boxflag)
692 {
693   LAMMPS *lmp = (LAMMPS *) handle;
694   Domain *domain = lmp->domain;
695 
696   BEGIN_CAPTURE
697   {
698     // do nothing if box does not yet exist
699     if ((lmp->domain->box_exist == 0)
700         && (lmp->comm->me == 0)) {
701       lmp->error->warning(FLERR,"Calling lammps_extract_box without a box");
702       return;
703     }
704 
705     // domain->init() is needed to update domain->box_change
706     domain->init();
707 
708     if (boxlo) {
709       boxlo[0] = domain->boxlo[0];
710       boxlo[1] = domain->boxlo[1];
711       boxlo[2] = domain->boxlo[2];
712     }
713     if (boxhi) {
714       boxhi[0] = domain->boxhi[0];
715       boxhi[1] = domain->boxhi[1];
716       boxhi[2] = domain->boxhi[2];
717     }
718     if (xy) *xy = domain->xy;
719     if (yz) *yz = domain->yz;
720     if (xz) *xz = domain->xz;
721 
722     if (pflags) {
723       pflags[0] = domain->periodicity[0];
724       pflags[1] = domain->periodicity[1];
725       pflags[2] = domain->periodicity[2];
726     }
727     if (boxflag) *boxflag = domain->box_change;
728   }
729   END_CAPTURE
730 }
731 
732 /* ---------------------------------------------------------------------- */
733 
734 /** Reset simulation box parameters.
735  *
736 \verbatim embed:rst
737 
738 This function sets the simulation box dimensions (upper and lower bounds
739 and tilt factors) from the provided data and then re-initializes the box
740 information and all derived settings. It may only be called before atoms
741 are created.
742 
743 \endverbatim
744  *
745  * \param  handle   pointer to a previously created LAMMPS instance
746  * \param  boxlo    pointer to 3 doubles containing the lower box boundary
747  * \param  boxhi    pointer to 3 doubles containing the upper box boundary
748  * \param  xy       xy tilt factor
749  * \param  yz       yz tilt factor
750  * \param  xz       xz tilt factor */
751 
lammps_reset_box(void * handle,double * boxlo,double * boxhi,double xy,double yz,double xz)752 void lammps_reset_box(void *handle, double *boxlo, double *boxhi,
753                       double xy, double yz, double xz)
754 {
755   LAMMPS *lmp = (LAMMPS *) handle;
756   Domain *domain = lmp->domain;
757 
758   BEGIN_CAPTURE
759   {
760     if (lmp->atom->natoms > 0)
761       lmp->error->all(FLERR,"Calling lammps_reset_box not supported when atoms exist");
762 
763     // warn and do nothing if no box exists
764     if (lmp->domain->box_exist == 0) {
765       if (lmp->comm->me == 0)
766         lmp->error->warning(FLERR,"Ignoring call to lammps_reset_box without a box");
767       return;
768     }
769 
770     domain->boxlo[0] = boxlo[0];
771     domain->boxlo[1] = boxlo[1];
772     domain->boxlo[2] = boxlo[2];
773     domain->boxhi[0] = boxhi[0];
774     domain->boxhi[1] = boxhi[1];
775     domain->boxhi[2] = boxhi[2];
776 
777     domain->xy = xy;
778     domain->yz = yz;
779     domain->xz = xz;
780 
781     domain->set_global_box();
782     lmp->comm->set_proc_grid();
783     domain->set_local_box();
784   }
785   END_CAPTURE
786 }
787 
788 /* ---------------------------------------------------------------------- */
789 
790 /** Get memory usage information
791  *
792 \verbatim embed:rst
793 
794 This function will retrieve memory usage information for the current
795 LAMMPS instance or process.  The *meminfo* buffer will be filled with
796 3 different numbers (if supported by the operating system).  The first
797 is the tally (in MBytes) of all large memory allocations made by LAMMPS.
798 This is a lower boundary of how much memory is requested and does not
799 account for memory allocated on the stack or allocations via ``new``.
800 The second number is the current memory allocation of the current process
801 as returned by a memory allocation reporting in the system library.  The
802 third number is the maximum amount of RAM (not swap) used by the process
803 so far. If any of the two latter parameters is not supported by the operating
804 system it will be set to zero.
805 
806 .. versionadded:: 18Sep2020
807 
808 \endverbatim
809  *
810  * \param  handle   pointer to a previously created LAMMPS instance
811  * \param  meminfo  buffer with space for at least 3 double to store
812  * data in. */
813 
lammps_memory_usage(void * handle,double * meminfo)814 void lammps_memory_usage(void *handle, double *meminfo)
815 {
816   LAMMPS *lmp = (LAMMPS *) handle;
817   Info info(lmp);
818   info.get_memory_info(meminfo);
819 }
820 
821 /* ---------------------------------------------------------------------- */
822 
823 /** Return current LAMMPS world communicator as integer
824  *
825 \verbatim embed:rst
826 
827 This will take the LAMMPS "world" communicator and convert it to an
828 integer using ``MPI_Comm_c2f()``, so it is equivalent to the
829 corresponding MPI communicator in Fortran. This way it can be safely
830 passed around between different programming languages.  To convert it
831 to the C language representation use ``MPI_Comm_f2c()``.
832 
833 If LAMMPS was compiled with MPI_STUBS, this function returns -1.
834 
835 .. versionadded:: 18Sep2020
836 
837 *See also*
838    :cpp:func:`lammps_open_fortran`
839 
840 \endverbatim
841  *
842  * \param  handle  pointer to a previously created LAMMPS instance
843  * \return         Fortran representation of the LAMMPS world communicator */
844 
lammps_get_mpi_comm(void * handle)845 int lammps_get_mpi_comm(void *handle)
846 {
847 #ifdef MPI_STUBS
848   return -1;
849 #else
850   LAMMPS *lmp = (LAMMPS *) handle;
851   MPI_Fint f_comm = MPI_Comm_c2f(lmp->world);
852   return f_comm;
853 #endif
854 }
855 
856 /* ---------------------------------------------------------------------- */
857 
858 /** Query LAMMPS about global settings.
859  *
860 \verbatim embed:rst
861 
862 This function will retrieve or compute global properties. In contrast to
863 :cpp:func:`lammps_get_thermo` this function returns an ``int``.  The
864 following tables list the currently supported keyword.  If a keyword is
865 not recognized, the function returns -1.
866 
867 * :ref:`Integer sizes <extract_integer_sizes>`
868 * :ref:`System status <extract_system_status>`
869 * :ref:`System sizes <extract_system_sizes>`
870 * :ref:`Atom style flags <extract_atom_flags>`
871 
872 .. _extract_integer_sizes:
873 
874 **Integer sizes**
875 
876 .. list-table::
877    :header-rows: 1
878    :widths: auto
879 
880    * - Keyword
881      - Description / Return value
882    * - bigint
883      - size of the ``bigint`` integer type, 4 or 8 bytes.
884        Set at :ref:`compile time <size>`.
885    * - tagint
886      - size of the ``tagint`` integer type, 4 or 8 bytes.
887        Set at :ref:`compile time <size>`.
888    * - imageint
889      - size of the ``imageint`` integer type, 4 or 8 bytes.
890        Set at :ref:`compile time <size>`.
891 
892 .. _extract_system_status:
893 
894 **System status**
895 
896 .. list-table::
897    :header-rows: 1
898    :widths: auto
899 
900    * - Keyword
901      - Description / Return value
902    * - dimension
903      - Number of dimensions: 2 or 3. See :doc:`dimension`.
904    * - box_exist
905      - 1 if the simulation box is defined, 0 if not.
906        See :doc:`create_box`.
907    * - nthreads
908      - Number of requested OpenMP threads for LAMMPS' execution
909    * - newton_bond
910      - 1 if Newton's 3rd law is applied to bonded interactions, 0 if not.
911    * - newton_pair
912      - 1 if Newton's 3rd law is applied to non-bonded interactions, 0 if not.
913    * - triclinic
914      - 1 if the the simulation box is triclinic, 0 if orthogonal.
915        See :doc:`change_box`.
916    * - universe_rank
917      - MPI rank on LAMMPS' universe communicator (0 <= universe_rank < universe_size)
918    * - universe_size
919      - Number of ranks on LAMMPS' universe communicator (world_size <= universe_size)
920    * - world_rank
921      - MPI rank on LAMMPS' world communicator (0 <= world_rank < world_size)
922    * - world_size
923      - Number of ranks on LAMMPS' world communicator
924 
925 .. _extract_system_sizes:
926 
927 **System sizes**
928 
929 .. list-table::
930    :header-rows: 1
931    :widths: auto
932 
933    * - Keyword
934      - Description / Return value
935    * - nlocal
936      - number of "owned" atoms of the current MPI rank.
937    * - nghost
938      - number of "ghost" atoms of the current MPI rank.
939    * - nall
940      - number of all "owned" and "ghost" atoms of the current MPI rank.
941    * - nmax
942      - maximum of nlocal+nghost across all MPI ranks (for per-atom data array size).
943    * - ntypes
944      - number of atom types
945    * - nbondtypes
946      - number of bond types
947    * - nangletypes
948      - number of angle types
949    * - ndihedraltypes
950      - number of dihedral types
951    * - nimpropertypes
952      - number of improper types
953 
954 .. _extract_atom_flags:
955 
956 **Atom style flags**
957 
958 .. list-table::
959    :header-rows: 1
960    :widths: auto
961 
962    * - Keyword
963      - Description / Return value
964    * - molecule_flag
965      - 1 if the atom style includes molecular topology data. See :doc:`atom_style`.
966    * - q_flag
967      - 1 if the atom style includes point charges. See :doc:`atom_style`.
968    * - mu_flag
969      - 1 if the atom style includes point dipoles. See :doc:`atom_style`.
970    * - rmass_flag
971      - 1 if the atom style includes per-atom masses, 0 if there are per-type masses. See :doc:`atom_style`.
972    * - radius_flag
973      - 1 if the atom style includes a per-atom radius. See :doc:`atom_style`.
974    * - sphere_flag
975      - 1 if the atom style describes extended particles that can rotate. See :doc:`atom_style`.
976    * - ellipsoid_flag
977      - 1 if the atom style describes extended particles that may be ellipsoidal. See :doc:`atom_style`.
978    * - omega_flag
979      - 1 if the atom style can store per-atom rotational velocities. See :doc:`atom_style`.
980    * - torque_flag
981      - 1 if the atom style can store per-atom torques. See :doc:`atom_style`.
982    * - angmom_flag
983      - 1 if the atom style can store per-atom angular momentum. See :doc:`atom_style`.
984 
985 *See also*
986    :cpp:func:`lammps_extract_global`
987 
988 \endverbatim
989  *
990  * \param  handle   pointer to a previously created LAMMPS instance
991  * \param  keyword  string with the name of the thermo keyword
992  * \return          value of the queried setting or -1 if unknown */
993 
lammps_extract_setting(void * handle,const char * keyword)994 int lammps_extract_setting(void *handle, const char *keyword)
995 {
996   LAMMPS *lmp = (LAMMPS *) handle;
997 
998 // This can be customized by adding keywords and documenting them in the section above.
999   if (strcmp(keyword,"bigint") == 0) return sizeof(bigint);
1000   if (strcmp(keyword,"tagint") == 0) return sizeof(tagint);
1001   if (strcmp(keyword,"imageint") == 0) return sizeof(imageint);
1002 
1003   if (strcmp(keyword,"dimension") == 0) return lmp->domain->dimension;
1004   if (strcmp(keyword,"box_exist") == 0) return lmp->domain->box_exist;
1005   if (strcmp(keyword,"newton_bond") == 0) return lmp->force->newton_bond;
1006   if (strcmp(keyword,"newton_pair") == 0) return lmp->force->newton_pair;
1007   if (strcmp(keyword,"triclinic") == 0) return lmp->domain->triclinic;
1008 
1009   if (strcmp(keyword,"universe_rank") == 0) return lmp->universe->me;
1010   if (strcmp(keyword,"universe_size") == 0) return lmp->universe->nprocs;
1011   if (strcmp(keyword,"world_rank") == 0) return lmp->comm->me;
1012   if (strcmp(keyword,"world_size") == 0) return lmp->comm->nprocs;
1013   if (strcmp(keyword,"nthreads") == 0) return lmp->comm->nthreads;
1014 
1015   if (strcmp(keyword,"nlocal") == 0) return lmp->atom->nlocal;
1016   if (strcmp(keyword,"nghost") == 0) return lmp->atom->nghost;
1017   if (strcmp(keyword,"nall") == 0) return lmp->atom->nlocal+lmp->atom->nghost;
1018   if (strcmp(keyword,"nmax") == 0) return lmp->atom->nmax;
1019   if (strcmp(keyword,"ntypes") == 0) return lmp->atom->ntypes;
1020   if (strcmp(keyword,"nbondtypes") == 0) return lmp->atom->nbondtypes;
1021   if (strcmp(keyword,"nangletypes") == 0) return lmp->atom->nangletypes;
1022   if (strcmp(keyword,"ndihedraltypes") == 0) return lmp->atom->ndihedraltypes;
1023   if (strcmp(keyword,"nimpropertypes") == 0) return lmp->atom->nimpropertypes;
1024 
1025   if (strcmp(keyword,"molecule_flag") == 0) return lmp->atom->molecule_flag;
1026   if (strcmp(keyword,"q_flag") == 0) return lmp->atom->q_flag;
1027   if (strcmp(keyword,"mu_flag") == 0) return lmp->atom->mu_flag;
1028   if (strcmp(keyword,"rmass_flag") == 0) return lmp->atom->rmass_flag;
1029   if (strcmp(keyword,"radius_flag") == 0) return lmp->atom->radius_flag;
1030   if (strcmp(keyword,"sphere_flag") == 0) return lmp->atom->sphere_flag;
1031   if (strcmp(keyword,"ellipsoid_flag") == 0) return lmp->atom->ellipsoid_flag;
1032   if (strcmp(keyword,"omega_flag") == 0) return lmp->atom->omega_flag;
1033   if (strcmp(keyword,"torque_flag") == 0) return lmp->atom->torque_flag;
1034   if (strcmp(keyword,"angmom_flag") == 0) return lmp->atom->angmom_flag;
1035   if (strcmp(keyword,"peri_flag") == 0) return lmp->atom->peri_flag;
1036 
1037   return -1;
1038 }
1039 
1040 /* ---------------------------------------------------------------------- */
1041 
1042 /** Get data type of internal global LAMMPS variables or arrays.
1043  *
1044 \verbatim embed:rst
1045 
1046 This function returns an integer that encodes the data type of the global
1047 property with the specified name. See :cpp:enum:`_LMP_DATATYPE_CONST` for valid
1048 values. Callers of :cpp:func:`lammps_extract_global` can use this information
1049 to then decide how to cast the (void*) pointer and access the data.
1050 
1051 .. versionadded:: 18Sep2020
1052 
1053 \endverbatim
1054  *
1055  * \param  handle   pointer to a previously created LAMMPS instance (unused)
1056  * \param  name     string with the name of the extracted property
1057  * \return          integer constant encoding the data type of the property
1058  *                  or -1 if not found. */
1059 
lammps_extract_global_datatype(void *,const char * name)1060 int lammps_extract_global_datatype(void * /*handle*/, const char *name)
1061 {
1062   if (strcmp(name,"dt") == 0) return LAMMPS_DOUBLE;
1063   if (strcmp(name,"ntimestep") == 0) return LAMMPS_BIGINT;
1064   if (strcmp(name,"atime") == 0) return LAMMPS_DOUBLE;
1065   if (strcmp(name,"atimestep") == 0) return LAMMPS_BIGINT;
1066   if (strcmp(name,"respa_levels") == 0) return LAMMPS_INT;
1067   if (strcmp(name,"respa_dt") == 0) return LAMMPS_DOUBLE;
1068 
1069   if (strcmp(name,"boxlo") == 0) return LAMMPS_DOUBLE;
1070   if (strcmp(name,"boxhi") == 0) return LAMMPS_DOUBLE;
1071   if (strcmp(name,"sublo") == 0) return LAMMPS_DOUBLE;
1072   if (strcmp(name,"subhi") == 0) return LAMMPS_DOUBLE;
1073   if (strcmp(name,"sublo_lambda") == 0) return LAMMPS_DOUBLE;
1074   if (strcmp(name,"subhi_lambda") == 0) return LAMMPS_DOUBLE;
1075   if (strcmp(name,"boxxlo") == 0) return LAMMPS_DOUBLE;
1076   if (strcmp(name,"boxxhi") == 0) return LAMMPS_DOUBLE;
1077   if (strcmp(name,"boxylo") == 0) return LAMMPS_DOUBLE;
1078   if (strcmp(name,"boxyhi") == 0) return LAMMPS_DOUBLE;
1079   if (strcmp(name,"boxzlo") == 0) return LAMMPS_DOUBLE;
1080   if (strcmp(name,"boxzhi") == 0) return LAMMPS_DOUBLE;
1081   if (strcmp(name,"periodicity") == 0) return LAMMPS_INT;
1082   if (strcmp(name,"triclinic") == 0) return LAMMPS_INT;
1083   if (strcmp(name,"xy") == 0) return LAMMPS_DOUBLE;
1084   if (strcmp(name,"xz") == 0) return LAMMPS_DOUBLE;
1085   if (strcmp(name,"yz") == 0) return LAMMPS_DOUBLE;
1086 
1087   if (strcmp(name,"natoms") == 0) return LAMMPS_BIGINT;
1088   if (strcmp(name,"nbonds") == 0) return LAMMPS_BIGINT;
1089   if (strcmp(name,"nangles") == 0) return LAMMPS_BIGINT;
1090   if (strcmp(name,"ndihedrals") == 0) return LAMMPS_BIGINT;
1091   if (strcmp(name,"nimpropers") == 0) return LAMMPS_BIGINT;
1092   if (strcmp(name,"nlocal") == 0) return LAMMPS_INT;
1093   if (strcmp(name,"nghost") == 0) return LAMMPS_INT;
1094   if (strcmp(name,"nmax") == 0) return LAMMPS_INT;
1095   if (strcmp(name,"ntypes") == 0) return LAMMPS_INT;
1096 
1097   if (strcmp(name,"q_flag") == 0) return LAMMPS_INT;
1098 
1099   if (strcmp(name,"units") == 0) return LAMMPS_STRING;
1100   if (strcmp(name,"boltz") == 0) return LAMMPS_DOUBLE;
1101   if (strcmp(name,"hplanck") == 0) return LAMMPS_DOUBLE;
1102   if (strcmp(name,"mvv2e") == 0) return LAMMPS_DOUBLE;
1103   if (strcmp(name,"ftm2v") == 0) return LAMMPS_DOUBLE;
1104   if (strcmp(name,"mv2d") == 0) return LAMMPS_DOUBLE;
1105   if (strcmp(name,"nktv2p") == 0) return LAMMPS_DOUBLE;
1106   if (strcmp(name,"qqr2e") == 0) return LAMMPS_DOUBLE;
1107   if (strcmp(name,"qe2f") == 0) return LAMMPS_DOUBLE;
1108   if (strcmp(name,"vxmu2f") == 0) return LAMMPS_DOUBLE;
1109   if (strcmp(name,"xxt2kmu") == 0) return LAMMPS_DOUBLE;
1110   if (strcmp(name,"dielectric") == 0) return LAMMPS_DOUBLE;
1111   if (strcmp(name,"qqrd2e") == 0) return LAMMPS_DOUBLE;
1112   if (strcmp(name,"e_mass") == 0) return LAMMPS_DOUBLE;
1113   if (strcmp(name,"hhmrr2e") == 0) return LAMMPS_DOUBLE;
1114   if (strcmp(name,"mvh2r") == 0) return LAMMPS_DOUBLE;
1115 
1116   if (strcmp(name,"angstrom") == 0) return LAMMPS_DOUBLE;
1117   if (strcmp(name,"femtosecond") == 0) return LAMMPS_DOUBLE;
1118   if (strcmp(name,"qelectron") == 0) return LAMMPS_DOUBLE;
1119 
1120   return -1;
1121 }
1122 
1123 /* ---------------------------------------------------------------------- */
1124 
1125 /** Get pointer to internal global LAMMPS variables or arrays.
1126  *
1127 \verbatim embed:rst
1128 
1129 This function returns a pointer to the location of some global property
1130 stored in one of the constituent classes of a LAMMPS instance.  The
1131 returned pointer is cast to ``void *`` and needs to be cast to a pointer
1132 of the type that the entity represents. The pointers returned by this
1133 function are generally persistent; therefore it is not necessary to call
1134 the function again, unless a :doc:`clear` command is issued which wipes
1135 out and recreates the contents of the :cpp:class:`LAMMPS
1136 <LAMMPS_NS::LAMMPS>` class.
1137 
1138 Please also see :cpp:func:`lammps_extract_setting`,
1139 :cpp:func:`lammps_get_thermo`, and :cpp:func:`lammps_extract_box`.
1140 
1141 .. warning::
1142 
1143    Modifying the data in the location pointed to by the returned pointer
1144    may lead to inconsistent internal data and thus may cause failures or
1145    crashes or bogus simulations.  In general it is thus usually better
1146    to use a LAMMPS input command that sets or changes these parameters.
1147    Those will takes care of all side effects and necessary updates of
1148    settings derived from such settings.  Where possible a reference to
1149    such a command or a relevant section of the manual is given below.
1150 
1151 The following tables list the supported names, their data types, length
1152 of the data area, and a short description.  The data type can also be
1153 queried through calling :cpp:func:`lammps_extract_global_datatype`.
1154 The ``bigint`` type may be defined to be either an ``int`` or an
1155 ``int64_t``.  This is set at :ref:`compile time <size>` of the LAMMPS
1156 library and can be queried through calling
1157 :cpp:func:`lammps_extract_setting`.
1158 The function :cpp:func:`lammps_extract_global_datatype` will directly
1159 report the "native" data type.  The following tables are provided:
1160 
1161 * :ref:`Timestep settings <extract_timestep_settings>`
1162 * :ref:`Simulation box settings <extract_box_settings>`
1163 * :ref:`System property settings <extract_system_settings>`
1164 * :ref:`Unit settings <extract_unit_settings>`
1165 
1166 .. _extract_timestep_settings:
1167 
1168 **Timestep settings**
1169 
1170 .. list-table::
1171    :header-rows: 1
1172    :widths: auto
1173 
1174    * - Name
1175      - Type
1176      - Length
1177      - Description
1178    * - dt
1179      - double
1180      - 1
1181      - length of the time step. See :doc:`timestep`.
1182    * - ntimestep
1183      - bigint
1184      - 1
1185      - current time step number. See :doc:`reset_timestep`.
1186    * - atime
1187      - double
1188      - 1
1189      - accumulated simulation time in time units.
1190    * - atimestep
1191      - bigint
1192      - 1
1193      - the number of the timestep when "atime" was last updated.
1194    * - respa_levels
1195      - int
1196      - 1
1197      - number of r-RESPA levels. See :doc:`run_style`.
1198    * - respa_dt
1199      - double
1200      - number of r-RESPA levels
1201      - length of the time steps with r-RESPA. See :doc:`run_style`.
1202 
1203 .. _extract_box_settings:
1204 
1205 **Simulation box settings**
1206 
1207 .. list-table::
1208    :header-rows: 1
1209    :widths: auto
1210 
1211    * - Name
1212      - Type
1213      - Length
1214      - Description
1215    * - boxlo
1216      - double
1217      - 3
1218      - lower box boundaries. See :doc:`create_box`.
1219    * - boxhi
1220      - double
1221      - 3
1222      - upper box boundaries. See :doc:`create_box`.
1223    * - boxxlo
1224      - double
1225      - 1
1226      - lower box boundary in x-direction. See :doc:`create_box`.
1227    * - boxxhi
1228      - double
1229      - 1
1230      - upper box boundary in x-direction. See :doc:`create_box`.
1231    * - boxylo
1232      - double
1233      - 1
1234      - lower box boundary in y-direction. See :doc:`create_box`.
1235    * - boxyhi
1236      - double
1237      - 1
1238      - upper box boundary in y-direction. See :doc:`create_box`.
1239    * - boxzlo
1240      - double
1241      - 1
1242      - lower box boundary in z-direction. See :doc:`create_box`.
1243    * - boxzhi
1244      - double
1245      - 1
1246      - upper box boundary in z-direction. See :doc:`create_box`.
1247    * - sublo
1248      - double
1249      - 3
1250      - subbox lower boundaries
1251    * - subhi
1252      - double
1253      - 3
1254      - subbox upper boundaries
1255    * - sublo_lambda
1256      - double
1257      - 3
1258      - subbox lower boundaries in fractional coordinates (for triclinic cells)
1259    * - subhi_lambda
1260      - double
1261      - 3
1262      - subbox upper boundaries in fractional coordinates (for triclinic cells)
1263    * - periodicity
1264      - int
1265      - 3
1266      - 0 if non-periodic, 1 if periodic for x, y, and z;
1267        See :doc:`boundary`.
1268    * - triclinic
1269      - int
1270      - 1
1271      - 1 if the the simulation box is triclinic, 0 if orthogonal;
1272        See :doc:`change_box`.
1273    * - xy
1274      - double
1275      - 1
1276      - triclinic tilt factor. See :doc:`Howto_triclinic`.
1277    * - yz
1278      - double
1279      - 1
1280      - triclinic tilt factor. See :doc:`Howto_triclinic`.
1281    * - xz
1282      - double
1283      - 1
1284      - triclinic tilt factor. See :doc:`Howto_triclinic`.
1285 
1286 .. _extract_system_settings:
1287 
1288 **System property settings**
1289 
1290 .. list-table::
1291    :header-rows: 1
1292    :widths: auto
1293 
1294    * - Name
1295      - Type
1296      - Length
1297      - Description
1298    * - ntypes
1299      - int
1300      - 1
1301      - number of atom types
1302    * - nbonds
1303      - bigint
1304      - 1
1305      - total number of bonds in the simulation.
1306    * - nangles
1307      - bigint
1308      - 1
1309      - total number of angles in the simulation.
1310    * - ndihedrals
1311      - bigint
1312      - 1
1313      - total number of dihedrals in the simulation.
1314    * - nimpropers
1315      - bigint
1316      - 1
1317      - total number of impropers in the simulation.
1318    * - natoms
1319      - bigint
1320      - 1
1321      - total number of atoms in the simulation.
1322    * - nlocal
1323      - int
1324      - 1
1325      - number of "owned" atoms of the current MPI rank.
1326    * - nghost
1327      - int
1328      - 1
1329      - number of "ghost" atoms of the current MPI rank.
1330    * - nmax
1331      - int
1332      - 1
1333      - maximum of nlocal+nghost across all MPI ranks (for per-atom data array size).
1334    * - q_flag
1335      - int
1336      - 1
1337      - **deprecated**. Use :cpp:func:`lammps_extract_setting` instead.
1338 
1339 .. _extract_unit_settings:
1340 
1341 **Unit settings**
1342 
1343 .. list-table::
1344    :header-rows: 1
1345    :widths: auto
1346 
1347    * - Name
1348      - Type
1349      - Length
1350      - Description
1351    * - units
1352      - char \*
1353      - 1
1354      - string with the current unit style. See :doc:`units`.
1355    * - boltz
1356      - double
1357      - 1
1358      - value of the "boltz" constant. See :doc:`units`.
1359    * - hplanck
1360      - double
1361      - 1
1362      - value of the "hplanck" constant. See :doc:`units`.
1363    * - mvv2e
1364      - double
1365      - 1
1366      - factor to convert :math:`\frac{1}{2}mv^2` for a particle to
1367        the current energy unit; See :doc:`units`.
1368    * - ftm2v
1369      - double
1370      - 1
1371      - (description missing) See :doc:`units`.
1372    * - mv2d
1373      - double
1374      - 1
1375      - (description missing) See :doc:`units`.
1376    * - nktv2p
1377      - double
1378      - 1
1379      - (description missing) See :doc:`units`.
1380    * - qqr2e
1381      - double
1382      - 1
1383      - factor to convert :math:`\frac{q_i q_j}{r}` to energy units;
1384        See :doc:`units`.
1385    * - qe2f
1386      - double
1387      - 1
1388      - (description missing) See :doc:`units`.
1389    * - vxmu2f
1390      - double
1391      - 1
1392      - (description missing) See :doc:`units`.
1393    * - xxt2kmu
1394      - double
1395      - 1
1396      - (description missing) See :doc:`units`.
1397    * - dielectric
1398      - double
1399      - 1
1400      - value of the dielectric constant. See :doc:`dielectric`.
1401    * - qqrd2e
1402      - double
1403      - 1
1404      - (description missing) See :doc:`units`.
1405    * - e_mass
1406      - double
1407      - 1
1408      - (description missing) See :doc:`units`.
1409    * - hhmrr2e
1410      - double
1411      - 1
1412      - (description missing) See :doc:`units`.
1413    * - mvh2r
1414      - double
1415      - 1
1416      - (description missing) See :doc:`units`.
1417    * - angstrom
1418      - double
1419      - 1
1420      - constant to convert current length unit to angstroms;
1421        1.0 for reduced (aka "lj") units. See :doc:`units`.
1422    * - femtosecond
1423      - double
1424      - 1
1425      - constant to convert current time unit to femtoseconds;
1426        1.0 for reduced (aka "lj") units
1427    * - qelectron
1428      - double
1429      - 1
1430      - (description missing) See :doc:`units`.
1431 
1432 \endverbatim
1433  *
1434  * \param  handle   pointer to a previously created LAMMPS instance
1435  * \param  name     string with the name of the extracted property
1436  * \return          pointer (cast to ``void *``) to the location of the
1437                     requested property. NULL if name is not known. */
1438 
lammps_extract_global(void * handle,const char * name)1439 void *lammps_extract_global(void *handle, const char *name)
1440 {
1441   LAMMPS *lmp = (LAMMPS *) handle;
1442 
1443   if (strcmp(name,"units") == 0) return (void *) lmp->update->unit_style;
1444   if (strcmp(name,"dt") == 0) return (void *) &lmp->update->dt;
1445   if (strcmp(name,"ntimestep") == 0) return (void *) &lmp->update->ntimestep;
1446   // update->atime can be referenced as a pointer
1447   // thermo "timer" data cannot be, since it is computed on request
1448   // lammps_get_thermo() can access all thermo keywords by value
1449   if (strcmp(name,"atime") == 0) return (void *) &lmp->update->atime;
1450   if (strcmp(name,"atimestep") == 0) return (void *) &lmp->update->atimestep;
1451 
1452   if (utils::strmatch(lmp->update->integrate_style,"^respa")) {
1453     Respa *respa = (Respa *)lmp->update->integrate;
1454     if (strcmp(name,"respa_levels") == 0) return (void *) &respa->nlevels;
1455     if (strcmp(name,"respa_dt") == 0) return (void *) respa->step;
1456   }
1457   if (strcmp(name,"boxlo") == 0) return (void *) lmp->domain->boxlo;
1458   if (strcmp(name,"boxhi") == 0) return (void *) lmp->domain->boxhi;
1459   if (strcmp(name,"sublo") == 0) return (void *) lmp->domain->sublo;
1460   if (strcmp(name,"subhi") == 0) return (void *) lmp->domain->subhi;
1461   // these are only valid for a triclinic cell
1462   if (lmp->domain->triclinic) {
1463     if (strcmp(name,"sublo_lambda") == 0)
1464       return (void *) lmp->domain->sublo_lamda;
1465     if (strcmp(name,"subhi_lambda") == 0)
1466       return (void *) lmp->domain->subhi_lamda;
1467   }
1468   if (strcmp(name,"boxxlo") == 0) return (void *) &lmp->domain->boxlo[0];
1469   if (strcmp(name,"boxxhi") == 0) return (void *) &lmp->domain->boxhi[0];
1470   if (strcmp(name,"boxylo") == 0) return (void *) &lmp->domain->boxlo[1];
1471   if (strcmp(name,"boxyhi") == 0) return (void *) &lmp->domain->boxhi[1];
1472   if (strcmp(name,"boxzlo") == 0) return (void *) &lmp->domain->boxlo[2];
1473   if (strcmp(name,"boxzhi") == 0) return (void *) &lmp->domain->boxhi[2];
1474   if (strcmp(name,"periodicity") == 0) return (void *) lmp->domain->periodicity;
1475   if (strcmp(name,"triclinic") == 0) return (void *) &lmp->domain->triclinic;
1476   if (strcmp(name,"xy") == 0) return (void *) &lmp->domain->xy;
1477   if (strcmp(name,"xz") == 0) return (void *) &lmp->domain->xz;
1478   if (strcmp(name,"yz") == 0) return (void *) &lmp->domain->yz;
1479 
1480   if (strcmp(name,"natoms") == 0) return (void *) &lmp->atom->natoms;
1481   if (strcmp(name,"ntypes") == 0) return (void *) &lmp->atom->ntypes;
1482   if (strcmp(name,"nbonds") == 0) return (void *) &lmp->atom->nbonds;
1483   if (strcmp(name,"nangles") == 0) return (void *) &lmp->atom->nangles;
1484   if (strcmp(name,"ndihedrals") == 0) return (void *) &lmp->atom->ndihedrals;
1485   if (strcmp(name,"nimpropers") == 0) return (void *) &lmp->atom->nimpropers;
1486   if (strcmp(name,"nlocal") == 0) return (void *) &lmp->atom->nlocal;
1487   if (strcmp(name,"nghost") == 0) return (void *) &lmp->atom->nghost;
1488   if (strcmp(name,"nmax") == 0) return (void *) &lmp->atom->nmax;
1489 
1490   if (strcmp(name,"q_flag") == 0) return (void *) &lmp->atom->q_flag;
1491 
1492   // global constants defined by units
1493 
1494   if (strcmp(name,"boltz") == 0) return (void *) &lmp->force->boltz;
1495   if (strcmp(name,"hplanck") == 0) return (void *) &lmp->force->hplanck;
1496   if (strcmp(name,"mvv2e") == 0) return (void *) &lmp->force->mvv2e;
1497   if (strcmp(name,"ftm2v") == 0) return (void *) &lmp->force->ftm2v;
1498   if (strcmp(name,"mv2d") == 0) return (void *) &lmp->force->mv2d;
1499   if (strcmp(name,"nktv2p") == 0) return (void *) &lmp->force->nktv2p;
1500   if (strcmp(name,"qqr2e") == 0) return (void *) &lmp->force->qqr2e;
1501   if (strcmp(name,"qe2f") == 0) return (void *) &lmp->force->qe2f;
1502   if (strcmp(name,"vxmu2f") == 0) return (void *) &lmp->force->vxmu2f;
1503   if (strcmp(name,"xxt2kmu") == 0) return (void *) &lmp->force->xxt2kmu;
1504   if (strcmp(name,"dielectric") == 0) return (void *) &lmp->force->dielectric;
1505   if (strcmp(name,"qqrd2e") == 0) return (void *) &lmp->force->qqrd2e;
1506   if (strcmp(name,"e_mass") == 0) return (void *) &lmp->force->e_mass;
1507   if (strcmp(name,"hhmrr2e") == 0) return (void *) &lmp->force->hhmrr2e;
1508   if (strcmp(name,"mvh2r") == 0) return (void *) &lmp->force->mvh2r;
1509 
1510   if (strcmp(name,"angstrom") == 0) return (void *) &lmp->force->angstrom;
1511   if (strcmp(name,"femtosecond") == 0) return (void *) &lmp->force->femtosecond;
1512   if (strcmp(name,"qelectron") == 0) return (void *) &lmp->force->qelectron;
1513 
1514   return nullptr;
1515 }
1516 
1517 /* ---------------------------------------------------------------------- */
1518 
1519 /** Get data type of a LAMMPS per-atom property
1520  *
1521 \verbatim embed:rst
1522 
1523 This function returns an integer that encodes the data type of the per-atom
1524 property with the specified name. See :cpp:enum:`_LMP_DATATYPE_CONST` for valid
1525 values. Callers of :cpp:func:`lammps_extract_atom` can use this information
1526 to then decide how to cast the (void*) pointer and access the data.
1527 
1528 .. versionadded:: 18Sep2020
1529 
1530 \endverbatim
1531  *
1532  * \param  handle  pointer to a previously created LAMMPS instance
1533  * \param  name    string with the name of the extracted property
1534  * \return         integer constant encoding the data type of the property
1535  *                 or -1 if not found.
1536  * */
1537 
lammps_extract_atom_datatype(void * handle,const char * name)1538 int lammps_extract_atom_datatype(void *handle, const char *name)
1539 {
1540   LAMMPS *lmp = (LAMMPS *) handle;
1541   return lmp->atom->extract_datatype(name);
1542 }
1543 
1544 /* ---------------------------------------------------------------------- */
1545 
1546 /** Get pointer to a LAMMPS per-atom property.
1547  *
1548 \verbatim embed:rst
1549 
1550 This function returns a pointer to the location of per-atom properties
1551 (and per-atom-type properties in the case of the 'mass' keyword).
1552 Per-atom data is distributed across sub-domains and thus MPI ranks.  The
1553 returned pointer is cast to ``void *`` and needs to be cast to a pointer
1554 of data type that the entity represents.
1555 
1556 A table with supported keywords is included in the documentation
1557 of the :cpp:func:`Atom::extract() <LAMMPS_NS::Atom::extract>` function.
1558 
1559 .. warning::
1560 
1561    The pointers returned by this function are generally not persistent
1562    since per-atom data may be re-distributed, re-allocated, and
1563    re-ordered at every re-neighboring operation.
1564 
1565 \endverbatim
1566  *
1567  * \param  handle  pointer to a previously created LAMMPS instance
1568  * \param  name    string with the name of the extracted property
1569  * \return         pointer (cast to ``void *``) to the location of the
1570  *                 requested data or ``NULL`` if not found. */
1571 
lammps_extract_atom(void * handle,const char * name)1572 void *lammps_extract_atom(void *handle, const char *name)
1573 {
1574   LAMMPS *lmp = (LAMMPS *) handle;
1575   return lmp->atom->extract(name);
1576 }
1577 
1578 // ----------------------------------------------------------------------
1579 // Library functions to access data from computes, fixes, variables in LAMMPS
1580 // ----------------------------------------------------------------------
1581 
1582 /** Get pointer to data from a LAMMPS compute.
1583  *
1584 \verbatim embed:rst
1585 
1586 This function returns a pointer to the location of data provided by a
1587 :doc:`compute` instance identified by the compute-ID.  Computes may
1588 provide global, per-atom, or local data, and those may be a scalar, a
1589 vector, or an array or they may provide the information about the
1590 dimensions of the respective data.  Since computes may provide multiple
1591 kinds of data, it is required to set style and type flags representing
1592 what specific data is desired.  This also determines to what kind of
1593 pointer the returned pointer needs to be cast to access the data
1594 correctly.  The function returns ``NULL`` if the compute ID is not found
1595 or the requested data is not available or current. The following table
1596 lists the available options.
1597 
1598 .. list-table::
1599    :header-rows: 1
1600    :widths: auto
1601 
1602    * - Style (see :cpp:enum:`_LMP_STYLE_CONST`)
1603      - Type (see :cpp:enum:`_LMP_TYPE_CONST`)
1604      - Returned type
1605      - Returned data
1606    * - LMP_STYLE_GLOBAL
1607      - LMP_TYPE_SCALAR
1608      - ``double *``
1609      - Global scalar
1610    * - LMP_STYLE_GLOBAL
1611      - LMP_TYPE_VECTOR
1612      - ``double *``
1613      - Global vector
1614    * - LMP_STYLE_GLOBAL
1615      - LMP_TYPE_ARRAY
1616      - ``double **``
1617      - Global array
1618    * - LMP_STYLE_GLOBAL
1619      - LMP_SIZE_VECTOR
1620      - ``int *``
1621      - Length of global vector
1622    * - LMP_STYLE_GLOBAL
1623      - LMP_SIZE_ROWS
1624      - ``int *``
1625      - Rows of global array
1626    * - LMP_STYLE_GLOBAL
1627      - LMP_SIZE_COLS
1628      - ``int *``
1629      - Columns of global array
1630    * - LMP_STYLE_ATOM
1631      - LMP_TYPE_VECTOR
1632      - ``double *``
1633      - Per-atom value
1634    * - LMP_STYLE_ATOM
1635      - LMP_TYPE_ARRAY
1636      - ``double **``
1637      - Per-atom vector
1638    * - LMP_STYLE_ATOM
1639      - LMP_SIZE_COLS
1640      - ``int *``
1641      - Columns in per-atom array, 0 if vector
1642    * - LMP_STYLE_LOCAL
1643      - LMP_TYPE_VECTOR
1644      - ``double *``
1645      - Local data vector
1646    * - LMP_STYLE_LOCAL
1647      - LMP_TYPE_ARRAY
1648      - ``double **``
1649      - Local data array
1650    * - LMP_STYLE_LOCAL
1651      - LMP_SIZE_ROWS
1652      - ``int *``
1653      - Number of local data rows
1654    * - LMP_STYLE_LOCAL
1655      - LMP_SIZE_COLS
1656      - ``int *``
1657      - Number of local data columns
1658 
1659 .. warning::
1660 
1661    The pointers returned by this function are generally not persistent
1662    since the computed data may be re-distributed, re-allocated, and
1663    re-ordered at every invocation. It is advisable to re-invoke this
1664    function before the data is accessed, or make a copy if the data shall
1665    be used after other LAMMPS commands have been issued.
1666 
1667 .. note::
1668 
1669    If the compute's data is not computed for the current step, the
1670    compute will be invoked.  LAMMPS cannot easily check at that time, if
1671    it is valid to invoke a compute, so it may fail with an error.  The
1672    caller has to check to avoid such an error.
1673 
1674 
1675 \endverbatim
1676  *
1677  * \param  handle  pointer to a previously created LAMMPS instance
1678  * \param  id      string with ID of the compute
1679  * \param  style   constant indicating the style of data requested
1680                    (global, per-atom, or local)
1681  * \param  type    constant indicating type of data (scalar, vector,
1682                    or array) or size of rows or columns
1683  * \return         pointer (cast to ``void *``) to the location of the
1684  *                 requested data or ``NULL`` if not found. */
1685 
lammps_extract_compute(void * handle,const char * id,int style,int type)1686 void *lammps_extract_compute(void *handle, const char *id, int style, int type)
1687 {
1688   LAMMPS *lmp = (LAMMPS *) handle;
1689 
1690   BEGIN_CAPTURE
1691   {
1692     int icompute = lmp->modify->find_compute(id);
1693     if (icompute < 0) return nullptr;
1694     Compute *compute = lmp->modify->compute[icompute];
1695 
1696     if (style == LMP_STYLE_GLOBAL) {
1697       if (type == LMP_TYPE_SCALAR) {
1698         if (!compute->scalar_flag) return nullptr;
1699         if (compute->invoked_scalar != lmp->update->ntimestep)
1700           compute->compute_scalar();
1701         return (void *) &compute->scalar;
1702       }
1703       if ((type == LMP_TYPE_VECTOR) || (type == LMP_SIZE_VECTOR)) {
1704         if (!compute->vector_flag) return nullptr;
1705         if (compute->invoked_vector != lmp->update->ntimestep)
1706           compute->compute_vector();
1707         if (type == LMP_TYPE_VECTOR)
1708           return (void *) compute->vector;
1709         else
1710           return (void *) &compute->size_vector;
1711       }
1712       if ((type == LMP_TYPE_ARRAY) || (type == LMP_SIZE_ROWS) || (type == LMP_SIZE_COLS)) {
1713         if (!compute->array_flag) return nullptr;
1714         if (compute->invoked_array != lmp->update->ntimestep)
1715           compute->compute_array();
1716         if (type == LMP_TYPE_ARRAY)
1717           return (void *) compute->array;
1718         else if (type == LMP_SIZE_ROWS)
1719           return (void *) &compute->size_array_rows;
1720         else
1721           return (void *) &compute->size_array_cols;
1722       }
1723     }
1724 
1725     if (style == LMP_STYLE_ATOM) {
1726       if (!compute->peratom_flag) return nullptr;
1727       if (compute->invoked_peratom != lmp->update->ntimestep)
1728         compute->compute_peratom();
1729       if (type == LMP_TYPE_VECTOR) return (void *) compute->vector_atom;
1730       if (type == LMP_TYPE_ARRAY) return (void *) compute->array_atom;
1731       if (type == LMP_SIZE_COLS) return (void *) &compute->size_peratom_cols;
1732     }
1733 
1734     if (style == LMP_STYLE_LOCAL) {
1735       if (!compute->local_flag) return nullptr;
1736       if (compute->invoked_local != lmp->update->ntimestep)
1737         compute->compute_local();
1738       if (type == LMP_TYPE_SCALAR) return (void *) &compute->size_local_rows;  /* for backward compatibility */
1739       if (type == LMP_TYPE_VECTOR) return (void *) compute->vector_local;
1740       if (type == LMP_TYPE_ARRAY) return (void *) compute->array_local;
1741       if (type == LMP_SIZE_ROWS) return (void *) &compute->size_local_rows;
1742       if (type == LMP_SIZE_COLS) return (void *) &compute->size_local_cols;
1743     }
1744   }
1745   END_CAPTURE
1746 
1747   return nullptr;
1748 }
1749 
1750 /* ---------------------------------------------------------------------- */
1751 
1752 /** Get pointer to data from a LAMMPS fix.
1753  *
1754 \verbatim embed:rst
1755 
1756 This function returns a pointer to data provided by a :doc:`fix`
1757 instance identified by its fix-ID.  Fixes may provide global, per-atom,
1758 or local data, and those may be a scalar, a vector, or an array, or they
1759 may provide the information about the dimensions of the respective data.
1760 Since individual fixes may provide multiple kinds of data, it is
1761 required to set style and type flags representing what specific data is
1762 desired.  This also determines to what kind of pointer the returned
1763 pointer needs to be cast to access the data correctly.  The function
1764 returns ``NULL`` if the fix ID is not found or the requested data is not
1765 available.
1766 
1767 .. note::
1768 
1769    When requesting global data, the fix data can only be accessed one
1770    item at a time without access to the pointer itself.  Thus this
1771    function will allocate storage for a single double value, copy the
1772    returned value to it, and returns a pointer to the location of the
1773    copy.  Therefore the allocated storage needs to be freed after its
1774    use to avoid a memory leak. Example:
1775 
1776    .. code-block:: c
1777 
1778       double *dptr = (double *) lammps_extract_fix(handle,name,0,1,0,0);
1779       double value = *dptr;
1780       lammps_free((void *)dptr);
1781 
1782 The following table lists the available options.
1783 
1784 .. list-table::
1785    :header-rows: 1
1786    :widths: auto
1787 
1788    * - Style (see :cpp:enum:`_LMP_STYLE_CONST`)
1789      - Type (see :cpp:enum:`_LMP_TYPE_CONST`)
1790      - Returned type
1791      - Returned data
1792    * - LMP_STYLE_GLOBAL
1793      - LMP_TYPE_SCALAR
1794      - ``double *``
1795      - Copy of global scalar
1796    * - LMP_STYLE_GLOBAL
1797      - LMP_TYPE_VECTOR
1798      - ``double *``
1799      - Copy of global vector element at index nrow
1800    * - LMP_STYLE_GLOBAL
1801      - LMP_TYPE_ARRAY
1802      - ``double *``
1803      - Copy of global array element at nrow, ncol
1804    * - LMP_STYLE_GLOBAL
1805      - LMP_SIZE_VECTOR
1806      - ``int *``
1807      - Length of global vector
1808    * - LMP_STYLE_GLOBAL
1809      - LMP_SIZE_ROWS
1810      - ``int *``
1811      - Rows in global array
1812    * - LMP_STYLE_GLOBAL
1813      - LMP_SIZE_COLS
1814      - ``int *``
1815      - Columns in global array
1816    * - LMP_STYLE_ATOM
1817      - LMP_TYPE_VECTOR
1818      - ``double *``
1819      - Per-atom value
1820    * - LMP_STYLE_ATOM
1821      - LMP_TYPE_ARRAY
1822      - ``double **``
1823      - Per-atom vector
1824    * - LMP_STYLE_ATOM
1825      - LMP_SIZE_COLS
1826      - ``int *``
1827      - Columns of per-atom array, 0 if vector
1828    * - LMP_STYLE_LOCAL
1829      - LMP_TYPE_VECTOR
1830      - ``double *``
1831      - Local data vector
1832    * - LMP_STYLE_LOCAL
1833      - LMP_TYPE_ARRAY
1834      - ``double **``
1835      - Local data array
1836    * - LMP_STYLE_LOCAL
1837      - LMP_SIZE_ROWS
1838      - ``int *``
1839      - Number of local data rows
1840    * - LMP_STYLE_LOCAL
1841      - LMP_SIZE_COLS
1842      - ``int *``
1843      - Number of local data columns
1844 
1845 .. warning::
1846 
1847    The pointers returned by this function for per-atom or local data are
1848    generally not persistent, since the computed data may be re-distributed,
1849    re-allocated, and re-ordered at every invocation of the fix.  It is thus
1850    advisable to re-invoke this function before the data is accessed, or
1851    make a copy, if the data shall be used after other LAMMPS commands have
1852    been issued.
1853 
1854 .. note::
1855 
1856    LAMMPS cannot easily check if it is valid to access the data, so it
1857    may fail with an error.  The caller has to avoid such an error.
1858 
1859 \endverbatim
1860  *
1861  * \param  handle  pointer to a previously created LAMMPS instance
1862  * \param  id      string with ID of the fix
1863  * \param  style   constant indicating the style of data requested
1864                    (global, per-atom, or local)
1865  * \param  type    constant indicating type of data (scalar, vector,
1866                    or array) or size of rows or columns
1867  * \param  nrow    row index (only used for global vectors and arrays)
1868  * \param  ncol    column index (only used for global arrays)
1869  * \return         pointer (cast to ``void *``) to the location of the
1870  *                 requested data or ``NULL`` if not found. */
1871 
lammps_extract_fix(void * handle,const char * id,int style,int type,int nrow,int ncol)1872 void *lammps_extract_fix(void *handle, const char *id, int style, int type,
1873                          int nrow, int ncol)
1874 {
1875   LAMMPS *lmp = (LAMMPS *) handle;
1876 
1877   BEGIN_CAPTURE
1878   {
1879     int ifix = lmp->modify->find_fix(id);
1880     if (ifix < 0) return nullptr;
1881     Fix *fix = lmp->modify->fix[ifix];
1882 
1883     if (style == LMP_STYLE_GLOBAL) {
1884       if (type == LMP_TYPE_SCALAR) {
1885         if (!fix->scalar_flag) return nullptr;
1886         double *dptr = (double *) malloc(sizeof(double));
1887         *dptr = fix->compute_scalar();
1888         return (void *) dptr;
1889       }
1890       if (type == LMP_TYPE_VECTOR) {
1891         if (!fix->vector_flag) return nullptr;
1892         double *dptr = (double *) malloc(sizeof(double));
1893         *dptr = fix->compute_vector(nrow);
1894         return (void *) dptr;
1895       }
1896       if (type == LMP_TYPE_ARRAY) {
1897         if (!fix->array_flag) return nullptr;
1898         double *dptr = (double *) malloc(sizeof(double));
1899         *dptr = fix->compute_array(nrow,ncol);
1900         return (void *) dptr;
1901       }
1902       if (type == LMP_SIZE_VECTOR) {
1903         if (!fix->vector_flag) return nullptr;
1904         return (void *) &fix->size_vector;
1905       }
1906       if ((type == LMP_SIZE_ROWS) || (type == LMP_SIZE_COLS)) {
1907         if (!fix->array_flag) return nullptr;
1908         if (type == LMP_SIZE_ROWS)
1909           return (void *) &fix->size_array_rows;
1910         else
1911           return (void *) &fix->size_array_cols;
1912       }
1913     }
1914 
1915     if (style == LMP_STYLE_ATOM) {
1916       if (!fix->peratom_flag) return nullptr;
1917       if (type == LMP_TYPE_VECTOR) return (void *) fix->vector_atom;
1918       if (type == LMP_TYPE_ARRAY) return (void *) fix->array_atom;
1919       if (type == LMP_SIZE_COLS) return (void *) &fix->size_peratom_cols;
1920     }
1921 
1922     if (style == LMP_STYLE_LOCAL) {
1923       if (!fix->local_flag) return nullptr;
1924       if (type == LMP_TYPE_SCALAR) return (void *) &fix->size_local_rows;
1925       if (type == LMP_TYPE_VECTOR) return (void *) fix->vector_local;
1926       if (type == LMP_TYPE_ARRAY) return (void *) fix->array_local;
1927       if (type == LMP_SIZE_ROWS) return (void *) &fix->size_local_rows;
1928       if (type == LMP_SIZE_COLS) return (void *) &fix->size_local_cols;
1929     }
1930   }
1931   END_CAPTURE
1932 
1933   return nullptr;
1934 }
1935 
1936 /* ---------------------------------------------------------------------- */
1937 
1938 /** Get pointer to data from a LAMMPS variable.
1939  *
1940 \verbatim embed:rst
1941 
1942 This function returns a pointer to data from a LAMMPS :doc:`variable`
1943 identified by its name.  When the variable is either an *equal*\ -style
1944 compatible or an *atom*\ -style variable the variable is evaluated and
1945 the corresponding value(s) returned.  Variables of style *internal*
1946 are compatible with *equal*\ -style variables and so are *python*\
1947 -style variables, if they return a numeric value.  For other
1948 variable styles their string value is returned.  The function returns
1949 ``NULL`` when a variable of the provided *name* is not found or of an
1950 incompatible style.  The *group* argument is only used for *atom*\
1951 -style variables and ignored otherwise.  If set to ``NULL`` when
1952 extracting data from and *atom*\ -style variable, the group is assumed
1953 to be "all".
1954 
1955 When requesting data from an *equal*\ -style or compatible variable
1956 this function allocates storage for a single double value, copies the
1957 returned value to it, and returns a pointer to the location of the
1958 copy.  Therefore the allocated storage needs to be freed after its
1959 use to avoid a memory leak. Example:
1960 
1961 .. code-block:: c
1962 
1963    double *dptr = (double *) lammps_extract_variable(handle,name,NULL);
1964    double value = *dptr;
1965    lammps_free((void *)dptr);
1966 
1967 For *atom*\ -style variables the data returned is a pointer to an
1968 allocated block of storage of double of the length ``atom->nlocal``.
1969 Since the data is returned a copy, the location will persist, but its
1970 content will not be updated, in case the variable is re-evaluated.
1971 To avoid a memory leak this pointer needs to be freed after use in
1972 the calling program.
1973 
1974 For other variable styles the returned pointer needs to be cast to
1975 a char pointer.
1976 
1977 .. code-block:: c
1978 
1979    const char *cptr = (const char *) lammps_extract_variable(handle,name,NULL);
1980    printf("The value of variable %s is %s\n", name, cptr);
1981 
1982 .. note::
1983 
1984    LAMMPS cannot easily check if it is valid to access the data
1985    referenced by the variables, e.g. computes or fixes or thermodynamic
1986    info, so it may fail with an error.  The caller has to make certain,
1987    that the data is extracted only when it safe to evaluate the variable
1988    and thus an error and crash is avoided.
1989 
1990 \endverbatim
1991  *
1992  * \param  handle  pointer to a previously created LAMMPS instance
1993  * \param  name    name of the variable
1994  * \param  group   group-ID for atom style variable or ``NULL``
1995  * \return         pointer (cast to ``void *``) to the location of the
1996  *                 requested data or ``NULL`` if not found. */
1997 
lammps_extract_variable(void * handle,const char * name,const char * group)1998 void *lammps_extract_variable(void *handle, const char *name, const char *group)
1999 {
2000   LAMMPS *lmp = (LAMMPS *) handle;
2001 
2002   BEGIN_CAPTURE
2003   {
2004     int ivar = lmp->input->variable->find(name);
2005     if (ivar < 0) return nullptr;
2006 
2007     if (lmp->input->variable->equalstyle(ivar)) {
2008       double *dptr = (double *) malloc(sizeof(double));
2009       *dptr = lmp->input->variable->compute_equal(ivar);
2010       return (void *) dptr;
2011     } else if (lmp->input->variable->atomstyle(ivar)) {
2012       if (group == nullptr) group = (char *)"all";
2013       int igroup = lmp->group->find(group);
2014       if (igroup < 0) return nullptr;
2015       int nlocal = lmp->atom->nlocal;
2016       double *vector = (double *) malloc(nlocal*sizeof(double));
2017       lmp->input->variable->compute_atom(ivar,igroup,vector,1,0);
2018       return (void *) vector;
2019     } else {
2020       return lmp->input->variable->retrieve(name);
2021     }
2022   }
2023   END_CAPTURE
2024 #if defined(LAMMPS_EXCEPTIONS)
2025   return nullptr;
2026 #endif
2027 }
2028 
2029 /* ---------------------------------------------------------------------- */
2030 
2031 /** Set the value of a string-style variable.
2032  *
2033  * This function assigns a new value from the string str to the
2034  * string-style variable name. Returns -1 if a variable of that
2035  * name does not exist or is not a string-style variable, otherwise 0.
2036  *
2037  * \param  handle  pointer to a previously created LAMMPS instance
2038  * \param  name    name of the variable
2039  * \param  str     new value of the variable
2040  * \return         0 on success or -1 on failure
2041  */
lammps_set_variable(void * handle,char * name,char * str)2042 int lammps_set_variable(void *handle, char *name, char *str)
2043 {
2044   LAMMPS *lmp = (LAMMPS *) handle;
2045   int err = -1;
2046 
2047   BEGIN_CAPTURE
2048   {
2049     err = lmp->input->variable->set_string(name,str);
2050   }
2051   END_CAPTURE
2052 
2053   return err;
2054 }
2055 
2056 // ----------------------------------------------------------------------
2057 // Library functions for scatter/gather operations of data
2058 // ----------------------------------------------------------------------
2059 
2060 /* ----------------------------------------------------------------------
2061    gather the named atom-based entity for all atoms
2062      return it in user-allocated data
2063    data will be ordered by atom ID
2064      requirement for consecutive atom IDs (1 to N)
2065    see gather_atoms_concat() to return data for all atoms, unordered
2066    see gather_atoms_subset() to return data for only a subset of atoms
2067    name = desired quantity, e.g. x or charge
2068    type = 0 for integer values, 1 for double values
2069    count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
2070      use count = 3 with "image" if want single image flag unpacked into xyz
2071    return atom-based values in 1d data, ordered by count, then by atom ID
2072      e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
2073      data must be pre-allocated by caller to correct length
2074      correct length = count*Natoms, as queried by get_natoms()
2075    method:
2076      alloc and zero count*Natom length vector
2077      loop over Nlocal to fill vector with my values
2078      Allreduce to sum vector into data across all procs
2079 ------------------------------------------------------------------------- */
2080 
lammps_gather_atoms(void * handle,char * name,int type,int count,void * data)2081 void lammps_gather_atoms(void *handle, char *name, int type, int count, void *data)
2082 {
2083   LAMMPS *lmp = (LAMMPS *) handle;
2084 
2085   BEGIN_CAPTURE
2086   {
2087 #if defined(LAMMPS_BIGBIG)
2088     lmp->error->all(FLERR,"Library function lammps_gather_atoms() "
2089                     "is not compatible with -DLAMMPS_BIGBIG");
2090 #else
2091     int i,j,offset;
2092 
2093     // error if tags are not defined or not consecutive
2094     // NOTE: test that name = image or ids is not a 64-bit int in code?
2095 
2096     int flag = 0;
2097     if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0)
2098       flag = 1;
2099     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
2100     if (flag) {
2101       if (lmp->comm->me == 0)
2102         lmp->error->warning(FLERR,"Library error in lammps_gather_atoms");
2103       return;
2104     }
2105 
2106     int natoms = static_cast<int> (lmp->atom->natoms);
2107 
2108     void *vptr = lmp->atom->extract(name);
2109     if (vptr == nullptr) {
2110       if (lmp->comm->me == 0)
2111         lmp->error->warning(FLERR,"lammps_gather_atoms: unknown property name");
2112       return;
2113     }
2114 
2115     // copy = Natom length vector of per-atom values
2116     // use atom ID to insert each atom's values into copy
2117     // MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
2118 
2119     if (type == 0) {
2120       int *vector = nullptr;
2121       int **array = nullptr;
2122       const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
2123 
2124       if ((count == 1) || imgunpack) vector = (int *) vptr;
2125       else array = (int **) vptr;
2126 
2127       int *copy;
2128       lmp->memory->create(copy,count*natoms,"lib/gather:copy");
2129       for (i = 0; i < count*natoms; i++) copy[i] = 0;
2130 
2131       tagint *tag = lmp->atom->tag;
2132       int nlocal = lmp->atom->nlocal;
2133 
2134       if (count == 1) {
2135         for (i = 0; i < nlocal; i++)
2136           copy[tag[i]-1] = vector[i];
2137 
2138       } else if (imgunpack) {
2139         for (i = 0; i < nlocal; i++) {
2140           offset = count*(tag[i]-1);
2141           const int image = vector[i];
2142           copy[offset++] = (image & IMGMASK) - IMGMAX;
2143           copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
2144           copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
2145         }
2146 
2147       } else {
2148         for (i = 0; i < nlocal; i++) {
2149           offset = count*(tag[i]-1);
2150           for (j = 0; j < count; j++)
2151             copy[offset++] = array[i][j];
2152         }
2153       }
2154 
2155       MPI_Allreduce(copy,data,count*natoms,MPI_INT,MPI_SUM,lmp->world);
2156       lmp->memory->destroy(copy);
2157 
2158     } else if (type == 1) {
2159       double *vector = nullptr;
2160       double **array = nullptr;
2161       if (count == 1) vector = (double *) vptr;
2162       else array = (double **) vptr;
2163 
2164       double *copy;
2165       lmp->memory->create(copy,count*natoms,"lib/gather:copy");
2166       for (i = 0; i < count*natoms; i++) copy[i] = 0.0;
2167 
2168       tagint *tag = lmp->atom->tag;
2169       int nlocal = lmp->atom->nlocal;
2170 
2171       if (count == 1) {
2172         for (i = 0; i < nlocal; i++)
2173           copy[tag[i]-1] = vector[i];
2174 
2175       } else {
2176         for (i = 0; i < nlocal; i++) {
2177           offset = count*(tag[i]-1);
2178           for (j = 0; j < count; j++)
2179             copy[offset++] = array[i][j];
2180         }
2181       }
2182 
2183       MPI_Allreduce(copy,data,count*natoms,MPI_DOUBLE,MPI_SUM,lmp->world);
2184       lmp->memory->destroy(copy);
2185     } else {
2186       if (lmp->comm->me == 0)
2187         lmp->error->warning(FLERR,"lammps_gather_atoms: unsupported data type");
2188       return;
2189     }
2190 #endif
2191   }
2192   END_CAPTURE
2193 }
2194 
2195 /* ----------------------------------------------------------------------
2196    gather the named atom-based entity for all atoms
2197      return it in user-allocated data
2198    data will be a concatenation of chunks of each proc's atoms,
2199      in whatever order the atoms are on each proc
2200      no requirement for consecutive atom IDs (1 to N)
2201      can do a gather_atoms_concat for "id" if need to know atom IDs
2202    see gather_atoms() to return data ordered by consecutive atom IDs
2203    see gather_atoms_subset() to return data for only a subset of atoms
2204    name = desired quantity, e.g. x or charge
2205    type = 0 for integer values, 1 for double values
2206    count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
2207      use count = 3 with "image" if want single image flag unpacked into xyz
2208    return atom-based values in 1d data, ordered by count, then by atom
2209      e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
2210      data must be pre-allocated by caller to correct length
2211      correct length = count*Natoms, as queried by get_natoms()
2212    method:
2213      Allgather Nlocal atoms from each proc into data
2214 ------------------------------------------------------------------------- */
2215 
lammps_gather_atoms_concat(void * handle,char * name,int type,int count,void * data)2216 void lammps_gather_atoms_concat(void *handle, char *name, int type, int count, void *data)
2217 {
2218   LAMMPS *lmp = (LAMMPS *) handle;
2219 
2220   BEGIN_CAPTURE
2221   {
2222 #if defined(LAMMPS_BIGBIG)
2223     lmp->error->all(FLERR,"Library function lammps_gather_atoms_concat() "
2224                     "is not compatible with -DLAMMPS_BIGBIG");
2225 #else
2226     int i,offset;
2227 
2228     // error if tags are not defined
2229     // NOTE: test that name = image or ids is not a 64-bit int in code?
2230 
2231     int flag = 0;
2232     if (lmp->atom->tag_enable == 0) flag = 1;
2233     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
2234     if (flag) {
2235       if (lmp->comm->me == 0)
2236         lmp->error->warning(FLERR,"Library error in lammps_gather_atoms");
2237       return;
2238     }
2239 
2240     int natoms = static_cast<int> (lmp->atom->natoms);
2241 
2242     void *vptr = lmp->atom->extract(name);
2243     if (vptr == nullptr) {
2244       if (lmp->comm->me == 0)
2245         lmp->error->warning(FLERR,"lammps_gather_atoms: unknown property name");
2246       return;
2247     }
2248 
2249     // perform MPI_Allgatherv on each proc's chunk of Nlocal atoms
2250 
2251     int nprocs = lmp->comm->nprocs;
2252 
2253     int *recvcounts,*displs;
2254     lmp->memory->create(recvcounts,nprocs,"lib/gather:recvcounts");
2255     lmp->memory->create(displs,nprocs,"lib/gather:displs");
2256 
2257     if (type == 0) {
2258       int *vector = nullptr;
2259       int **array = nullptr;
2260       const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
2261 
2262       if ((count == 1) || imgunpack) vector = (int *) vptr;
2263       else array = (int **) vptr;
2264 
2265       int *copy;
2266       lmp->memory->create(copy,count*natoms,"lib/gather:copy");
2267       for (i = 0; i < count*natoms; i++) copy[i] = 0;
2268 
2269       int nlocal = lmp->atom->nlocal;
2270 
2271       if (count == 1) {
2272         MPI_Allgather(&nlocal,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
2273         displs[0] = 0;
2274         for (i = 1; i < nprocs; i++)
2275           displs[i] = displs[i-1] + recvcounts[i-1];
2276         MPI_Allgatherv(vector,nlocal,MPI_INT,data,recvcounts,displs,
2277                        MPI_INT,lmp->world);
2278 
2279       } else if (imgunpack) {
2280         lmp->memory->create(copy,count*nlocal,"lib/gather:copy");
2281         offset = 0;
2282         for (i = 0; i < nlocal; i++) {
2283           const int image = vector[i];
2284           copy[offset++] = (image & IMGMASK) - IMGMAX;
2285           copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
2286           copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
2287         }
2288         int n = count*nlocal;
2289         MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
2290         displs[0] = 0;
2291         for (i = 1; i < nprocs; i++)
2292           displs[i] = displs[i-1] + recvcounts[i-1];
2293         MPI_Allgatherv(copy,count*nlocal,MPI_INT,
2294                        data,recvcounts,displs,MPI_INT,lmp->world);
2295         lmp->memory->destroy(copy);
2296 
2297       } else {
2298         int n = count*nlocal;
2299         MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
2300         displs[0] = 0;
2301         for (i = 1; i < nprocs; i++)
2302           displs[i] = displs[i-1] + recvcounts[i-1];
2303         MPI_Allgatherv(&array[0][0],count*nlocal,MPI_INT,
2304                        data,recvcounts,displs,MPI_INT,lmp->world);
2305       }
2306 
2307     } else {
2308       double *vector = nullptr;
2309       double **array = nullptr;
2310       if (count == 1) vector = (double *) vptr;
2311       else array = (double **) vptr;
2312 
2313       int nlocal = lmp->atom->nlocal;
2314 
2315       if (count == 1) {
2316         MPI_Allgather(&nlocal,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
2317         displs[0] = 0;
2318         for (i = 1; i < nprocs; i++)
2319           displs[i] = displs[i-1] + recvcounts[i-1];
2320         MPI_Allgatherv(vector,nlocal,MPI_DOUBLE,data,recvcounts,displs,
2321                        MPI_DOUBLE,lmp->world);
2322 
2323       } else {
2324         int n = count*nlocal;
2325         MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
2326         displs[0] = 0;
2327         for (i = 1; i < nprocs; i++)
2328           displs[i] = displs[i-1] + recvcounts[i-1];
2329         MPI_Allgatherv(&array[0][0],count*nlocal,MPI_DOUBLE,
2330                        data,recvcounts,displs,MPI_DOUBLE,lmp->world);
2331       }
2332     }
2333 
2334     lmp->memory->destroy(recvcounts);
2335     lmp->memory->destroy(displs);
2336 #endif
2337   }
2338   END_CAPTURE
2339 }
2340 
2341 /* ----------------------------------------------------------------------
2342    gather the named atom-based entity for a subset of atoms
2343      return it in user-allocated data
2344    data will be ordered by requested atom IDs
2345      no requirement for consecutive atom IDs (1 to N)
2346    see gather_atoms() to return data for all atoms, ordered by consecutive IDs
2347    see gather_atoms_concat() to return data for all atoms, unordered
2348    name = desired quantity, e.g. x or charge
2349    type = 0 for integer values, 1 for double values
2350    count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
2351      use count = 3 with "image" if want single image flag unpacked into xyz
2352    ndata = # of atoms to return data for (could be all atoms)
2353    ids = list of Ndata atom IDs to return data for
2354    return atom-based values in 1d data, ordered by count, then by atom
2355      e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
2356      data must be pre-allocated by caller to correct length
2357      correct length = count*Ndata
2358    method:
2359      alloc and zero count*Ndata length vector
2360      loop over Ndata to fill vector with my values
2361      Allreduce to sum vector into data across all procs
2362 ------------------------------------------------------------------------- */
2363 
lammps_gather_atoms_subset(void * handle,char * name,int type,int count,int ndata,int * ids,void * data)2364 void lammps_gather_atoms_subset(void *handle, char *name, int type, int count,
2365                                 int ndata, int *ids, void *data)
2366 {
2367   LAMMPS *lmp = (LAMMPS *) handle;
2368 
2369   BEGIN_CAPTURE
2370   {
2371 #if defined(LAMMPS_BIGBIG)
2372     lmp->error->all(FLERR,"Library function lammps_gather_atoms_subset() "
2373                     "is not compatible with -DLAMMPS_BIGBIG");
2374 #else
2375     int i,j,m,offset;
2376     tagint id;
2377 
2378     // error if tags are not defined
2379     // NOTE: test that name = image or ids is not a 64-bit int in code?
2380 
2381     int flag = 0;
2382     if (lmp->atom->tag_enable == 0) flag = 1;
2383     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
2384     if (flag) {
2385       if (lmp->comm->me == 0)
2386         lmp->error->warning(FLERR,"Library error in lammps_gather_atoms_subset");
2387       return;
2388     }
2389 
2390     void *vptr = lmp->atom->extract(name);
2391     if (vptr == nullptr) {
2392       if (lmp->comm->me == 0)
2393         lmp->error->warning(FLERR,"lammps_gather_atoms_subset: "
2394                             "unknown property name");
2395       return;
2396     }
2397 
2398     // copy = Ndata length vector of per-atom values
2399     // use atom ID to insert each atom's values into copy
2400     // MPI_Allreduce with MPI_SUM to merge into data
2401 
2402     if (type == 0) {
2403       int *vector = nullptr;
2404       int **array = nullptr;
2405       const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
2406 
2407       if ((count == 1) || imgunpack) vector = (int *) vptr;
2408       else array = (int **) vptr;
2409 
2410       int *copy;
2411       lmp->memory->create(copy,count*ndata,"lib/gather:copy");
2412       for (i = 0; i < count*ndata; i++) copy[i] = 0;
2413 
2414       int nlocal = lmp->atom->nlocal;
2415 
2416       if (count == 1) {
2417         for (i = 0; i < ndata; i++) {
2418           id = ids[i];
2419           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal)
2420             copy[i] = vector[m];
2421         }
2422 
2423       } else if (imgunpack) {
2424         for (i = 0; i < ndata; i++) {
2425           id = ids[i];
2426           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
2427             offset = count*i;
2428             const int image = vector[m];
2429             copy[offset++] = (image & IMGMASK) - IMGMAX;
2430             copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
2431             copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
2432           }
2433         }
2434 
2435       } else {
2436         for (i = 0; i < ndata; i++) {
2437           id = ids[i];
2438           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
2439             offset = count*i;
2440             for (j = 0; j < count; j++)
2441               copy[offset++] = array[m][j];
2442           }
2443         }
2444       }
2445 
2446       MPI_Allreduce(copy,data,count*ndata,MPI_INT,MPI_SUM,lmp->world);
2447       lmp->memory->destroy(copy);
2448 
2449     } else {
2450       double *vector = nullptr;
2451       double **array = nullptr;
2452       if (count == 1) vector = (double *) vptr;
2453       else array = (double **) vptr;
2454 
2455       double *copy;
2456       lmp->memory->create(copy,count*ndata,"lib/gather:copy");
2457       for (i = 0; i < count*ndata; i++) copy[i] = 0.0;
2458 
2459       int nlocal = lmp->atom->nlocal;
2460 
2461       if (count == 1) {
2462         for (i = 0; i < ndata; i++) {
2463           id = ids[i];
2464           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal)
2465             copy[i] = vector[m];
2466         }
2467 
2468       } else {
2469         for (i = 0; i < ndata; i++) {
2470           id = ids[i];
2471           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
2472             offset = count*i;
2473             for (j = 0; j < count; j++)
2474               copy[offset++] = array[m][j];
2475           }
2476         }
2477       }
2478 
2479       MPI_Allreduce(copy,data,count*ndata,MPI_DOUBLE,MPI_SUM,lmp->world);
2480       lmp->memory->destroy(copy);
2481     }
2482 #endif
2483   }
2484   END_CAPTURE
2485 }
2486 
2487 /* ----------------------------------------------------------------------
2488    scatter the named atom-based entity in data to all atoms
2489    data is ordered by atom ID
2490      requirement for consecutive atom IDs (1 to N)
2491    see scatter_atoms_subset() to scatter data for some (or all) atoms, unordered
2492    name = desired quantity, e.g. x or charge
2493    type = 0 for integer values, 1 for double values
2494    count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
2495      use count = 3 with "image" for xyz to be packed into single image flag
2496    data = atom-based values in 1d data, ordered by count, then by atom ID
2497      e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
2498      data must be correct length = count*Natoms, as queried by get_natoms()
2499    method:
2500      loop over Natoms, if I own atom ID, set its values from data
2501 ------------------------------------------------------------------------- */
2502 
lammps_scatter_atoms(void * handle,char * name,int type,int count,void * data)2503 void lammps_scatter_atoms(void *handle, char *name, int type, int count, void *data)
2504 {
2505   LAMMPS *lmp = (LAMMPS *) handle;
2506 
2507   BEGIN_CAPTURE
2508   {
2509 #if defined(LAMMPS_BIGBIG)
2510     lmp->error->all(FLERR,"Library function lammps_scatter_atoms() "
2511                     "is not compatible with -DLAMMPS_BIGBIG");
2512 #else
2513     int i,j,m,offset;
2514 
2515     // error if tags are not defined or not consecutive or no atom map
2516     // NOTE: test that name = image or ids is not a 64-bit int in code?
2517 
2518     int flag = 0;
2519     if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0)
2520       flag = 1;
2521     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
2522     if (lmp->atom->map_style == Atom::MAP_NONE) flag = 1;
2523     if (flag) {
2524       if (lmp->comm->me == 0)
2525         lmp->error->warning(FLERR,"Library error in lammps_scatter_atoms");
2526       return;
2527     }
2528 
2529     int natoms = static_cast<int> (lmp->atom->natoms);
2530 
2531     void *vptr = lmp->atom->extract(name);
2532     if (vptr == nullptr) {
2533       if (lmp->comm->me == 0)
2534         lmp->error->warning(FLERR,
2535                             "lammps_scatter_atoms: unknown property name");
2536       return;
2537     }
2538 
2539     // copy = Natom length vector of per-atom values
2540     // use atom ID to insert each atom's values into copy
2541     // MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
2542 
2543     if (type == 0) {
2544       int *vector = nullptr;
2545       int **array = nullptr;
2546       const int imgpack = (count == 3) && (strcmp(name,"image") == 0);
2547 
2548       if ((count == 1) || imgpack) vector = (int *) vptr;
2549       else array = (int **) vptr;
2550       int *dptr = (int *) data;
2551 
2552       if (count == 1) {
2553         for (i = 0; i < natoms; i++)
2554           if ((m = lmp->atom->map(i+1)) >= 0)
2555             vector[m] = dptr[i];
2556 
2557       } else if (imgpack) {
2558         for (i = 0; i < natoms; i++)
2559           if ((m = lmp->atom->map(i+1)) >= 0) {
2560             offset = count*i;
2561             int image = dptr[offset++] + IMGMAX;
2562             image += (dptr[offset++] + IMGMAX) << IMGBITS;
2563             image += (dptr[offset++] + IMGMAX) << IMG2BITS;
2564             vector[m] = image;
2565           }
2566 
2567       } else {
2568         for (i = 0; i < natoms; i++)
2569           if ((m = lmp->atom->map(i+1)) >= 0) {
2570             offset = count*i;
2571             for (j = 0; j < count; j++)
2572               array[m][j] = dptr[offset++];
2573           }
2574       }
2575 
2576     } else {
2577       double *vector = nullptr;
2578       double **array = nullptr;
2579       if (count == 1) vector = (double *) vptr;
2580       else array = (double **) vptr;
2581       double *dptr = (double *) data;
2582 
2583       if (count == 1) {
2584         for (i = 0; i < natoms; i++)
2585           if ((m = lmp->atom->map(i+1)) >= 0)
2586             vector[m] = dptr[i];
2587 
2588       } else {
2589         for (i = 0; i < natoms; i++) {
2590           if ((m = lmp->atom->map(i+1)) >= 0) {
2591             offset = count*i;
2592             for (j = 0; j < count; j++)
2593               array[m][j] = dptr[offset++];
2594           }
2595         }
2596       }
2597     }
2598 #endif
2599   }
2600   END_CAPTURE
2601 }
2602 
2603 /* ----------------------------------------------------------------------
2604    scatter the named atom-based entity in data to a subset of atoms
2605    data is ordered by provided atom IDs
2606      no requirement for consecutive atom IDs (1 to N)
2607    see scatter_atoms() to scatter data for all atoms, ordered by consecutive IDs
2608    name = desired quantity, e.g. x or charge
2609    type = 0 for integer values, 1 for double values
2610    count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
2611      use count = 3 with "image" for xyz to be packed into single image flag
2612    ndata = # of atoms in ids and data (could be all atoms)
2613    ids = list of Ndata atom IDs to scatter data to
2614    data = atom-based values in 1d data, ordered by count, then by atom ID
2615      e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
2616      data must be correct length = count*Ndata
2617    method:
2618      loop over Ndata, if I own atom ID, set its values from data
2619 ------------------------------------------------------------------------- */
2620 
lammps_scatter_atoms_subset(void * handle,char * name,int type,int count,int ndata,int * ids,void * data)2621 void lammps_scatter_atoms_subset(void *handle, char *name, int type, int count,
2622                                  int ndata, int *ids, void *data)
2623 {
2624   LAMMPS *lmp = (LAMMPS *) handle;
2625 
2626   BEGIN_CAPTURE
2627   {
2628 #if defined(LAMMPS_BIGBIG)
2629     lmp->error->all(FLERR,"Library function lammps_scatter_atoms_subset() "
2630                     "is not compatible with -DLAMMPS_BIGBIG");
2631 #else
2632     int i,j,m,offset;
2633     tagint id;
2634 
2635     // error if tags are not defined or no atom map
2636     // NOTE: test that name = image or ids is not a 64-bit int in code?
2637 
2638     int flag = 0;
2639     if (lmp->atom->tag_enable == 0) flag = 1;
2640     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
2641     if (lmp->atom->map_style == Atom::MAP_NONE) flag = 1;
2642     if (flag) {
2643       if (lmp->comm->me == 0)
2644         lmp->error->warning(FLERR,"Library error in lammps_scatter_atoms_subset");
2645       return;
2646     }
2647 
2648     void *vptr = lmp->atom->extract(name);
2649     if (vptr == nullptr) {
2650       if (lmp->comm->me == 0)
2651         lmp->error->warning(FLERR,
2652                             "lammps_scatter_atoms_subset: unknown property name");
2653       return;
2654     }
2655 
2656     // copy = Natom length vector of per-atom values
2657     // use atom ID to insert each atom's values into copy
2658     // MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
2659 
2660     if (type == 0) {
2661       int *vector = nullptr;
2662       int **array = nullptr;
2663       const int imgpack = (count == 3) && (strcmp(name,"image") == 0);
2664 
2665       if ((count == 1) || imgpack) vector = (int *) vptr;
2666       else array = (int **) vptr;
2667       int *dptr = (int *) data;
2668 
2669       if (count == 1) {
2670         for (i = 0; i < ndata; i++) {
2671           id = ids[i];
2672           if ((m = lmp->atom->map(id)) >= 0)
2673             vector[m] = dptr[i];
2674         }
2675 
2676       } else if (imgpack) {
2677         for (i = 0; i < ndata; i++) {
2678           id = ids[i];
2679           if ((m = lmp->atom->map(id)) >= 0) {
2680             offset = count*i;
2681             int image = dptr[offset++] + IMGMAX;
2682             image += (dptr[offset++] + IMGMAX) << IMGBITS;
2683             image += (dptr[offset++] + IMGMAX) << IMG2BITS;
2684             vector[m] = image;
2685           }
2686         }
2687 
2688       } else {
2689         for (i = 0; i < ndata; i++) {
2690           id = ids[i];
2691           if ((m = lmp->atom->map(id)) >= 0) {
2692             offset = count*i;
2693             for (j = 0; j < count; j++)
2694               array[m][j] = dptr[offset++];
2695           }
2696         }
2697       }
2698 
2699     } else {
2700       double *vector = nullptr;
2701       double **array = nullptr;
2702       if (count == 1) vector = (double *) vptr;
2703       else array = (double **) vptr;
2704       double *dptr = (double *) data;
2705 
2706       if (count == 1) {
2707         for (i = 0; i < ndata; i++) {
2708           id = ids[i];
2709           if ((m = lmp->atom->map(id)) >= 0)
2710             vector[m] = dptr[i];
2711         }
2712 
2713       } else {
2714         for (i = 0; i < ndata; i++) {
2715           id = ids[i];
2716           if ((m = lmp->atom->map(id)) >= 0) {
2717             offset = count*i;
2718             for (j = 0; j < count; j++)
2719               array[m][j] = dptr[offset++];
2720           }
2721         }
2722       }
2723     }
2724 #endif
2725   }
2726   END_CAPTURE
2727 }
2728 
2729 /** Gather type and constituent atom info for all bonds
2730  *
2731 \verbatim embed:rst
2732 
2733 This function copies the list of all bonds into a buffer provided by
2734 the calling code. The buffer will be filled with bond type, bond atom 1,
2735 bond atom 2 for each bond. Thus the buffer has to be allocated to the
2736 dimension of 3 times the **total** number of bonds times the size of
2737 the LAMMPS "tagint" type, which is either 4 or 8 bytes depending on
2738 whether they are stored in 32-bit or 64-bit integers, respectively.
2739 This size depends on the compile time settings used when compiling
2740 the LAMMPS library and can be queried by calling
2741 :cpp:func:`lammps_extract_setting()` with the keyword "tagint".
2742 
2743 When running in parallel, the data buffer must be allocated on **all**
2744 MPI ranks and will be filled with the information for **all** bonds
2745 in the system.
2746 
2747 .. versionadded:: 28Jul2021
2748 
2749 Below is a brief C code demonstrating accessing this collected bond information.
2750 
2751 .. code-block:: c
2752 
2753    #include <stdio.h>
2754    #include <stdlib.h>
2755    #include <stdint.h>
2756    #include "library.h"
2757 
2758    int main(int argc, char **argv)
2759    {
2760        int tagintsize;
2761        int64_t i, nbonds;
2762        void *handle, *bonds;
2763 
2764        handle = lammps_open_no_mpi(0, NULL, NULL);
2765        lammps_file(handle, "in.some_input");
2766 
2767        tagintsize = lammps_extract_setting(handle, "tagint");
2768        if (tagintsize == 4)
2769            nbonds = *(int32_t *)lammps_extract_global(handle, "nbonds");
2770         else
2771            nbonds = *(int64_t *)lammps_extract_global(handle, "nbonds");
2772        bonds = malloc(nbonds * 3 * tagintsize);
2773 
2774        lammps_gather_bonds(handle, bonds);
2775 
2776        if (lammps_extract_setting(handle, "world_rank") == 0) {
2777            if (tagintsize == 4) {
2778                int32_t *bonds_real = (int32_t *)bonds;
2779                for (i = 0; i < nbonds; ++i) {
2780                    printf("bond % 4ld: type = %d, atoms: % 4d  % 4d\n",i,
2781                           bonds_real[3*i], bonds_real[3*i+1], bonds_real[3*i+2]);
2782                }
2783            } else {
2784                int64_t *bonds_real = (int64_t *)bonds;
2785                for (i = 0; i < nbonds; ++i) {
2786                    printf("bond % 4ld: type = %ld, atoms: % 4ld  % 4ld\n",i,
2787                           bonds_real[3*i], bonds_real[3*i+1], bonds_real[3*i+2]);
2788                }
2789            }
2790        }
2791 
2792        lammps_close(handle);
2793        lammps_mpi_finalize();
2794        free(bonds);
2795        return 0;
2796    }
2797 
2798 \endverbatim
2799  *
2800  * \param  handle  pointer to a previously created LAMMPS instance
2801  * \param  data    pointer to data to copy the result to */
2802 
lammps_gather_bonds(void * handle,void * data)2803 void lammps_gather_bonds(void *handle, void *data)
2804 {
2805   LAMMPS *lmp = (LAMMPS *)handle;
2806   BEGIN_CAPTURE {
2807     void *val = lammps_extract_global(handle,"nbonds");
2808     bigint nbonds = *(bigint *)val;
2809 
2810     // no bonds
2811     if (nbonds == 0) return;
2812 
2813     // count per MPI rank bonds, determine offsets and allocate local buffers
2814     int localbonds = lmp->atom->avec->pack_bond(nullptr);
2815     int nprocs = lmp->comm->nprocs;
2816     int *bufsizes = new int[nprocs];
2817     int *bufoffsets = new int[nprocs];
2818     MPI_Allgather(&localbonds, 1, MPI_INT, bufsizes, 1, MPI_INT, lmp->world);
2819     bufoffsets[0] = 0;
2820     bufsizes[0] *= 3;           // 3 items per bond: type, atom1, atom2
2821     for (int i = 1; i < nprocs; ++i) {
2822       bufoffsets[i] = bufoffsets[i-1] + bufsizes[i-1];
2823       bufsizes[i] *= 3;         // 3 items per bond: type, atom1, atom2
2824     }
2825 
2826     tagint **bonds;
2827     lmp->memory->create(bonds, localbonds, 3, "library:gather_bonds:localbonds");
2828     lmp->atom->avec->pack_bond(bonds);
2829     MPI_Allgatherv(&bonds[0][0], 3*localbonds, MPI_LMP_TAGINT, data, bufsizes,
2830                    bufoffsets, MPI_LMP_TAGINT, lmp->world);
2831     lmp->memory->destroy(bonds);
2832     delete[] bufsizes;
2833     delete[] bufoffsets;
2834   }
2835   END_CAPTURE
2836 }
2837 
2838 /* ----------------------------------------------------------------------
2839   Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France)
2840   gather the named atom-based entity for all atoms
2841     return it in user-allocated data
2842   data will be ordered by atom ID
2843     requirement for consecutive atom IDs (1 to N)
2844   see gather_concat() to return data for all atoms, unordered
2845   see gather_subset() to return data for only a subset of atoms
2846   name = "x" , "f" or other atom properties
2847          "f_fix", "c_compute" for fixes / computes
2848          "d_name" or "i_name" for fix property/atom vectors with count = 1
2849          "d2_name" or "i2_name" for fix property/atom arrays with count > 1
2850          will return error if fix/compute isn't atom-based
2851   type = 0 for integer values, 1 for double values
2852   count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
2853     use count = 3 with "image" if want single image flag unpacked into xyz
2854   return atom-based values in 1d data, ordered by count, then by atom ID
2855     e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
2856     data must be pre-allocated by caller to correct length
2857     correct length = count*Natoms, as queried by get_natoms()
2858   method:
2859     alloc and zero count*Natom length vector
2860     loop over Nlocal to fill vector with my values
2861     Allreduce to sum vector into data across all procs
2862 ------------------------------------------------------------------------- */
2863 
lammps_gather(void * handle,char * name,int type,int count,void * data)2864 void lammps_gather(void *handle, char *name, int type, int count, void *data)
2865 {
2866   LAMMPS *lmp = (LAMMPS *) handle;
2867 
2868   BEGIN_CAPTURE
2869   {
2870 #if defined(LAMMPS_BIGBIG)
2871     lmp->error->all(FLERR,"Library function lammps_gather"
2872                     " not compatible with -DLAMMPS_BIGBIG");
2873 #else
2874     int i,j,offset,fcid,ltype,icol;
2875 
2876     // error if tags are not defined or not consecutive
2877 
2878     int flag = 0;
2879     if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0)
2880       flag = 1;
2881     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
2882     if (flag) {
2883       if (lmp->comm->me == 0)
2884         lmp->error->warning(FLERR,"Library error in lammps_gather");
2885       return;
2886     }
2887 
2888     int natoms = static_cast<int> (lmp->atom->natoms);
2889     void *vptr = lmp->atom->extract(name);
2890 
2891     // fix
2892 
2893     if (vptr==nullptr && utils::strmatch(name,"^f_")) {
2894 
2895       fcid = lmp->modify->find_fix(&name[2]);
2896       if (fcid < 0) {
2897         if (lmp->comm->me == 0)
2898           lmp->error->warning(FLERR,"lammps_gather: unknown fix id");
2899         return;
2900       }
2901 
2902       if (lmp->modify->fix[fcid]->peratom_flag == 0) {
2903         if (lmp->comm->me == 0)
2904           lmp->error->warning(FLERR,"lammps_gather:"
2905                               " fix does not return peratom data");
2906         return;
2907       }
2908       if (count>1 && lmp->modify->fix[fcid]->size_peratom_cols != count) {
2909         if (lmp->comm->me == 0)
2910           lmp->error->warning(FLERR,"lammps_gather:"
2911                               " count != values peratom for fix");
2912         return;
2913       }
2914 
2915       if (lmp->update->ntimestep % lmp->modify->fix[fcid]->peratom_freq) {
2916         if (lmp->comm->me == 0)
2917           lmp->error->all(FLERR,"lammps_gather:"
2918                           " fix not computed at compatible time");
2919         return;
2920       }
2921 
2922       if (count==1) vptr = (void *) lmp->modify->fix[fcid]->vector_atom;
2923       else vptr = (void *) lmp->modify->fix[fcid]->array_atom;
2924     }
2925 
2926     // compute
2927 
2928     if (vptr==nullptr && utils::strmatch(name,"^c_")) {
2929 
2930       fcid = lmp->modify->find_compute(&name[2]);
2931       if (fcid < 0) {
2932         if (lmp->comm->me == 0)
2933           lmp->error->warning(FLERR,"lammps_gather: unknown compute id");
2934         return;
2935       }
2936 
2937       if (lmp->modify->compute[fcid]->peratom_flag == 0) {
2938         if (lmp->comm->me == 0)
2939           lmp->error->warning(FLERR,"lammps_gather:"
2940                               " compute does not return peratom data");
2941         return;
2942       }
2943       if (count>1 && lmp->modify->compute[fcid]->size_peratom_cols != count) {
2944         if (lmp->comm->me == 0)
2945           lmp->error->warning(FLERR,"lammps_gather:"
2946                               " count != values peratom for compute");
2947         return;
2948       }
2949 
2950       if (lmp->modify->compute[fcid]->invoked_peratom != lmp->update->ntimestep)
2951         lmp->modify->compute[fcid]->compute_peratom();
2952 
2953       if (count==1) vptr = (void *) lmp->modify->compute[fcid]->vector_atom;
2954       else vptr = (void *) lmp->modify->compute[fcid]->array_atom;
2955     }
2956 
2957     // custom fix property/atom vector or array
2958 
2959     if ((vptr == nullptr) && utils::strmatch(name,"^[id]2?_")) {
2960 
2961       if (utils::strmatch(name,"^[id]_")) fcid = lmp->atom->find_custom(&name[2],ltype,icol);
2962       else fcid = lmp->atom->find_custom(&name[3],ltype,icol);
2963 
2964       if (fcid < 0) {
2965         if (lmp->comm->me == 0)
2966           lmp->error->warning(FLERR,"lammps_gather: unknown property/atom id");
2967         return;
2968       }
2969 
2970       if (ltype != type) {
2971         if (lmp->comm->me == 0)
2972           lmp->error->warning(FLERR,"lammps_gather: mismatch property/atom type");
2973         return;
2974       }
2975       if (count == 1 && icol != 0) {
2976         if (lmp->comm->me == 0)
2977           lmp->error->warning(FLERR,"lammps_gather: mismatch property/atom count");
2978         return;
2979       }
2980       if (count > 1 && icol != count) {
2981         if (lmp->comm->me == 0)
2982           lmp->error->warning(FLERR,"lammps_gather: mismatch property/atom count");
2983         return;
2984       }
2985 
2986       if (count == 1) {
2987         if (ltype==0) vptr = (void *) lmp->atom->ivector[fcid];
2988         else vptr = (void *) lmp->atom->dvector[fcid];
2989       } else {
2990         if (ltype==0) vptr = (void *) lmp->atom->iarray[fcid];
2991         else vptr = (void *) lmp->atom->darray[fcid];
2992       }
2993     }
2994 
2995     // no match
2996 
2997     if (vptr == nullptr) {
2998       if (lmp->comm->me == 0)
2999         lmp->error->warning(FLERR,"lammps_gather: undefined property name");
3000       return;
3001     }
3002 
3003     // copy = Natom length vector of per-atom values
3004     // use atom ID to insert each atom's values into copy
3005     // MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
3006 
3007     if (type==0) {
3008       int *vector = nullptr;
3009       int **array = nullptr;
3010 
3011       const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
3012 
3013       if ((count == 1) || imgunpack) vector = (int *) vptr;
3014       else array = (int **) vptr;
3015 
3016       int *copy;
3017       lmp->memory->create(copy,count*natoms,"lib/gather:copy");
3018       for (i = 0; i < count*natoms; i++) copy[i] = 0;
3019 
3020       tagint *tag = lmp->atom->tag;
3021       int nlocal = lmp->atom->nlocal;
3022 
3023       if (count == 1) {
3024         for (i = 0; i < nlocal; i++)
3025           copy[tag[i]-1] = vector[i];
3026 
3027       } else if (imgunpack) {
3028         for (i = 0; i < nlocal; i++) {
3029           offset = count*(tag[i]-1);
3030           const int image = vector[i];
3031           copy[offset++] = (image & IMGMASK) - IMGMAX;
3032           copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
3033           copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
3034         }
3035 
3036       } else {
3037         for (i = 0; i < nlocal; i++) {
3038           offset = count*(tag[i]-1);
3039           for (j = 0; j < count; j++)
3040             copy[offset++] = array[i][j];
3041         }
3042       }
3043 
3044       MPI_Allreduce(copy,data,count*natoms,MPI_INT,MPI_SUM,lmp->world);
3045       lmp->memory->destroy(copy);
3046 
3047     } else {
3048       double *vector = nullptr;
3049       double **array = nullptr;
3050       if (count == 1) vector = (double *) vptr;
3051       else array = (double **) vptr;
3052 
3053       double *copy;
3054       lmp->memory->create(copy,count*natoms,"lib/gather:copy");
3055       for (i = 0; i < count*natoms; i++) copy[i] = 0.0;
3056 
3057       tagint *tag = lmp->atom->tag;
3058       int nlocal = lmp->atom->nlocal;
3059 
3060       if (count == 1) {
3061         for (i = 0; i < nlocal; i++)
3062           copy[tag[i]-1] = vector[i];
3063       } else {
3064         for (i = 0; i < nlocal; i++) {
3065           offset = count*(tag[i]-1);
3066           for (j = 0; j < count; j++)
3067             copy[offset++] = array[i][j];
3068         }
3069       }
3070       MPI_Allreduce(copy,data,count*natoms,MPI_DOUBLE,MPI_SUM,lmp->world);
3071       lmp->memory->destroy(copy);
3072     }
3073 #endif
3074   }
3075   END_CAPTURE
3076 }
3077 
3078 /* ----------------------------------------------------------------------
3079   Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France)
3080   gather the named atom-based entity for all atoms
3081     return it in user-allocated data
3082   data will be ordered by atom ID
3083     requirement for consecutive atom IDs (1 to N)
3084   see gather() to return data ordered by consecutive atom IDs
3085   see gather_subset() to return data for only a subset of atoms
3086   name = "x" , "f" or other atom properties
3087          "f_fix", "c_compute" for fixes / computes
3088          "d_name" or "i_name" for fix property/atom vectors with count = 1
3089          "d2_name" or "i2_name" for fix property/atom arrays with count > 1
3090          will return error if fix/compute isn't atom-based
3091   type = 0 for integer values, 1 for double values
3092   count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
3093     use count = 3 with "image" if want single image flag unpacked into xyz
3094   return atom-based values in 1d data, ordered by count, then by atom ID
3095     e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
3096     data must be pre-allocated by caller to correct length
3097     correct length = count*Natoms, as queried by get_natoms()
3098   method:
3099     alloc and zero count*Natom length vector
3100     loop over Nlocal to fill vector with my values
3101     Allreduce to sum vector into data across all procs
3102 ------------------------------------------------------------------------- */
3103 
lammps_gather_concat(void * handle,char * name,int type,int count,void * data)3104 void lammps_gather_concat(void *handle, char *name, int type, int count, void *data)
3105 {
3106   LAMMPS *lmp = (LAMMPS *) handle;
3107 
3108   BEGIN_CAPTURE
3109   {
3110 #if defined(LAMMPS_BIGBIG)
3111     lmp->error->all(FLERR,"Library function lammps_gather_concat"
3112                           " not compatible with -DLAMMPS_BIGBIG");
3113 #else
3114     int i,offset,fcid,ltype,icol;
3115 
3116     // error if tags are not defined or not consecutive
3117 
3118     int flag = 0;
3119     if (lmp->atom->tag_enable == 0) flag = 1;
3120     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
3121     if (flag) {
3122       if (lmp->comm->me == 0)
3123         lmp->error->warning(FLERR,"Library error in lammps_gather_concat");
3124       return;
3125     }
3126 
3127     int natoms = static_cast<int> (lmp->atom->natoms);
3128     void *vptr = lmp->atom->extract(name);
3129 
3130     // fix
3131 
3132     if (vptr==nullptr && utils::strmatch(name,"^f_")) {
3133 
3134       fcid = lmp->modify->find_fix(&name[2]);
3135       if (fcid < 0) {
3136         if (lmp->comm->me == 0)
3137           lmp->error->warning(FLERR,"lammps_gather_concat: unknown fix id");
3138         return;
3139       }
3140 
3141       if (lmp->modify->fix[fcid]->peratom_flag == 0) {
3142         if (lmp->comm->me == 0)
3143           lmp->error->warning(FLERR,"lammps_gather_concat: fix does not return peratom data");
3144         return;
3145       }
3146       if (count>1 && lmp->modify->fix[fcid]->size_peratom_cols != count) {
3147         if (lmp->comm->me == 0)
3148           lmp->error->warning(FLERR,"lammps_gather_concat: count != values peratom for fix");
3149         return;
3150       }
3151       if (lmp->update->ntimestep % lmp->modify->fix[fcid]->peratom_freq) {
3152         if (lmp->comm->me == 0)
3153           lmp->error->all(FLERR,"lammps_gather_concat: fix not computed at compatible time");
3154         return;
3155       }
3156 
3157       if (count==1) vptr = (void *) lmp->modify->fix[fcid]->vector_atom;
3158       else vptr = (void *) lmp->modify->fix[fcid]->array_atom;
3159     }
3160 
3161     // compute
3162 
3163     if (vptr==nullptr && utils::strmatch(name,"^c_")) {
3164 
3165       fcid = lmp->modify->find_compute(&name[2]);
3166       if (fcid < 0) {
3167         if (lmp->comm->me == 0)
3168           lmp->error->warning(FLERR,"lammps_gather_concat: unknown compute id");
3169         return;
3170       }
3171 
3172       if (lmp->modify->compute[fcid]->peratom_flag == 0) {
3173         if (lmp->comm->me == 0)
3174           lmp->error->warning(FLERR,"lammps_gather_concat: compute does not return peratom data");
3175         return;
3176       }
3177       if (count>1 && lmp->modify->compute[fcid]->size_peratom_cols != count) {
3178         if (lmp->comm->me == 0)
3179           lmp->error->warning(FLERR,"lammps_gather_concat: count != values peratom for compute");
3180         return;
3181       }
3182 
3183       if (lmp->modify->compute[fcid]->invoked_peratom != lmp->update->ntimestep)
3184         lmp->modify->compute[fcid]->compute_peratom();
3185 
3186       if (count==1) vptr = (void *) lmp->modify->compute[fcid]->vector_atom;
3187       else vptr = (void *) lmp->modify->compute[fcid]->array_atom;
3188     }
3189 
3190     // custom per-atom vector or array
3191 
3192     if ((vptr==nullptr) && utils::strmatch(name,"^[id]2?_")) {
3193 
3194       if (utils::strmatch(name,"^[id]_")) fcid = lmp->atom->find_custom(&name[2],ltype,icol);
3195       else fcid = lmp->atom->find_custom(&name[3],ltype,icol);
3196 
3197       if (fcid < 0) {
3198         if (lmp->comm->me == 0)
3199           lmp->error->warning(FLERR,"lammps_gather_concat: unknown property/atom id");
3200         return;
3201       }
3202 
3203       if (ltype != type) {
3204         if (lmp->comm->me == 0)
3205           lmp->error->warning(FLERR,"lammps_gather_concat: mismatch property/atom type");
3206         return;
3207       }
3208       if (count == 1 && icol != 0) {
3209         if (lmp->comm->me == 0)
3210           lmp->error->warning(FLERR,"lammps_gather_concat: mismatch property/atom count");
3211         return;
3212       }
3213       if (count > 1 && icol != count) {
3214         if (lmp->comm->me == 0)
3215           lmp->error->warning(FLERR,"lammps_gather_concat: mismatch property/atom count");
3216         return;
3217       }
3218 
3219       if (count == 1) {
3220         if (ltype==0) vptr = (void *) lmp->atom->ivector[fcid];
3221         else vptr = (void *) lmp->atom->dvector[fcid];
3222       } else {
3223         if (ltype==0) vptr = (void *) lmp->atom->iarray[fcid];
3224         else vptr = (void *) lmp->atom->darray[fcid];
3225       }
3226     }
3227 
3228     // no match
3229 
3230     if (vptr == nullptr) {
3231       if (lmp->comm->me == 0)
3232         lmp->error->warning(FLERR,"lammps_gather_concat: undefined property name");
3233       return;
3234     }
3235 
3236     // perform MPI_Allgatherv on each proc's chunk of Nlocal atoms
3237 
3238     int nprocs = lmp->comm->nprocs;
3239 
3240     int *recvcounts,*displs;
3241     lmp->memory->create(recvcounts,nprocs,"lib/gather:recvcounts");
3242     lmp->memory->create(displs,nprocs,"lib/gather:displs");
3243 
3244     if (type == 0) {
3245       int *vector = nullptr;
3246       int **array = nullptr;
3247 
3248       const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
3249 
3250       if ((count == 1) || imgunpack) vector = (int *) vptr;
3251       else array = (int **) vptr;
3252 
3253       int *copy;
3254       lmp->memory->create(copy,count*natoms,"lib/gather:copy");
3255       for (i = 0; i < count*natoms; i++) copy[i] = 0;
3256 
3257       int nlocal = lmp->atom->nlocal;
3258 
3259       if (count == 1) {
3260         MPI_Allgather(&nlocal,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
3261         displs[0] = 0;
3262         for (i = 1; i < nprocs; i++)
3263           displs[i] = displs[i-1] + recvcounts[i-1];
3264         MPI_Allgatherv(vector,nlocal,MPI_INT,data,recvcounts,displs,
3265                        MPI_INT,lmp->world);
3266 
3267       } else if (imgunpack) {
3268         lmp->memory->create(copy,count*nlocal,"lib/gather:copy");
3269         offset = 0;
3270         for (i = 0; i < nlocal; i++) {
3271           const int image = vector[i];
3272           copy[offset++] = (image & IMGMASK) - IMGMAX;
3273           copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
3274           copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
3275         }
3276         int n = count*nlocal;
3277         MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
3278         displs[0] = 0;
3279         for (i = 1; i < nprocs; i++)
3280           displs[i] = displs[i-1] + recvcounts[i-1];
3281         MPI_Allgatherv(copy,count*nlocal,MPI_INT,
3282                        data,recvcounts,displs,MPI_INT,lmp->world);
3283         lmp->memory->destroy(copy);
3284 
3285       } else {
3286         int n = count*nlocal;
3287         MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
3288         displs[0] = 0;
3289         for (i = 1; i < nprocs; i++)
3290           displs[i] = displs[i-1] + recvcounts[i-1];
3291         MPI_Allgatherv(&array[0][0],count*nlocal,MPI_INT,
3292                        data,recvcounts,displs,MPI_INT,lmp->world);
3293       }
3294 
3295     } else {
3296       double *vector = nullptr;
3297       double **array = nullptr;
3298       if (count == 1) vector = (double *) vptr;
3299       else array = (double **) vptr;
3300 
3301       int nlocal = lmp->atom->nlocal;
3302 
3303       if (count == 1) {
3304         MPI_Allgather(&nlocal,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
3305         displs[0] = 0;
3306         for (i = 1; i < nprocs; i++)
3307           displs[i] = displs[i-1] + recvcounts[i-1];
3308         MPI_Allgatherv(vector,nlocal,MPI_DOUBLE,data,recvcounts,displs,
3309                        MPI_DOUBLE,lmp->world);
3310 
3311       } else {
3312         int n = count*nlocal;
3313         MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
3314         displs[0] = 0;
3315         for (i = 1; i < nprocs; i++)
3316           displs[i] = displs[i-1] + recvcounts[i-1];
3317         MPI_Allgatherv(&array[0][0],count*nlocal,MPI_DOUBLE,
3318                        data,recvcounts,displs,MPI_DOUBLE,lmp->world);
3319       }
3320     }
3321 
3322     lmp->memory->destroy(recvcounts);
3323     lmp->memory->destroy(displs);
3324 #endif
3325   }
3326   END_CAPTURE
3327 }
3328 
3329 /* ----------------------------------------------------------------------
3330   Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France)
3331   gather the named atom-based entity for all atoms
3332     return it in user-allocated data
3333   data will be ordered by atom ID
3334     requirement for consecutive atom IDs (1 to N)
3335   see gather() to return data ordered by consecutive atom IDs
3336   see gather_concat() to return data for all atoms, unordered
3337   name = "x" , "f" or other atom properties
3338          "f_fix", "c_compute" for fixes / computes
3339          "d_name" or "i_name" for fix property/atom vectors with count = 1
3340          "d2_name" or "i2_name" for fix property/atom arrays with count > 1
3341          will return error if fix/compute isn't atom-based
3342   type = 0 for integer values, 1 for double values
3343   count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
3344     use count = 3 with "image" if want single image flag unpacked into xyz
3345   return atom-based values in 1d data, ordered by count, then by atom ID
3346     e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
3347     data must be pre-allocated by caller to correct length
3348     correct length = count*Natoms, as queried by get_natoms()
3349   method:
3350     alloc and zero count*Natom length vector
3351     loop over Nlocal to fill vector with my values
3352     Allreduce to sum vector into data across all procs
3353 ------------------------------------------------------------------------- */
3354 
lammps_gather_subset(void * handle,char * name,int type,int count,int ndata,int * ids,void * data)3355 void lammps_gather_subset(void *handle, char *name,
3356                                 int type, int count,
3357                                 int ndata, int *ids, void *data)
3358 {
3359   LAMMPS *lmp = (LAMMPS *) handle;
3360 
3361   BEGIN_CAPTURE
3362   {
3363 #if defined(LAMMPS_BIGBIG)
3364     lmp->error->all(FLERR,"Library function lammps_gather_subset() "
3365                     "is not compatible with -DLAMMPS_BIGBIG");
3366 #else
3367     int i,j,m,offset,fcid,ltype,icol;
3368     tagint id;
3369 
3370     // error if tags are not defined or not consecutive
3371 
3372     int flag = 0;
3373     if (lmp->atom->tag_enable == 0) flag = 1;
3374     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
3375     if (flag) {
3376       if (lmp->comm->me == 0)
3377         lmp->error->warning(FLERR,"Library error in lammps_gather_subset");
3378       return;
3379     }
3380 
3381     void *vptr = lmp->atom->extract(name);
3382 
3383     // fix
3384 
3385     if (vptr==nullptr && utils::strmatch(name,"^f_")) {
3386 
3387       fcid = lmp->modify->find_fix(&name[2]);
3388       if (fcid < 0) {
3389         if (lmp->comm->me == 0)
3390           lmp->error->warning(FLERR,"lammps_gather_subset: unknown fix id");
3391         return;
3392       }
3393 
3394       if (lmp->modify->fix[fcid]->peratom_flag == 0) {
3395         if (lmp->comm->me == 0)
3396           lmp->error->warning(FLERR,"lammps_gather_subset:"
3397                               " fix does not return peratom data");
3398         return;
3399       }
3400       if (count>1 && lmp->modify->fix[fcid]->size_peratom_cols != count) {
3401         lmp->error->warning(FLERR,"lammps_gather_subset: count != values peratom for fix");
3402         return;
3403       }
3404       if (lmp->update->ntimestep % lmp->modify->fix[fcid]->peratom_freq) {
3405         if (lmp->comm->me == 0)
3406           lmp->error->all(FLERR,"lammps_gather_subset: fix not computed at compatible time");
3407         return;
3408       }
3409 
3410       if (count==1) vptr = (void *) lmp->modify->fix[fcid]->vector_atom;
3411       else vptr = (void *) lmp->modify->fix[fcid]->array_atom;
3412     }
3413 
3414     // compute
3415 
3416     if (vptr==nullptr && utils::strmatch(name,"^c_")) {
3417 
3418       fcid = lmp->modify->find_compute(&name[2]);
3419       if (fcid < 0) {
3420         if (lmp->comm->me == 0)
3421           lmp->error->warning(FLERR,"lammps_gather_subset: unknown compute id");
3422         return;
3423       }
3424 
3425       if (lmp->modify->compute[fcid]->peratom_flag == 0) {
3426         if (lmp->comm->me == 0)
3427           lmp->error->warning(FLERR,"lammps_gather_subset: compute does not return peratom data");
3428         return;
3429       }
3430       if (count>1 && lmp->modify->compute[fcid]->size_peratom_cols != count) {
3431         if (lmp->comm->me == 0)
3432           lmp->error->warning(FLERR,"lammps_gather_subset: count != values peratom for compute");
3433         return;
3434       }
3435 
3436       if (lmp->modify->compute[fcid]->invoked_peratom != lmp->update->ntimestep)
3437         lmp->modify->compute[fcid]->compute_peratom();
3438 
3439       if (count==1) vptr = (void *) lmp->modify->compute[fcid]->vector_atom;
3440       else vptr = (void *) lmp->modify->compute[fcid]->array_atom;
3441     }
3442 
3443     // custom fix property/atom vector or array
3444 
3445     if ((vptr == nullptr) && utils::strmatch(name,"^[id]2?_")) {
3446 
3447       if (utils::strmatch(name,"^[id]_"))
3448         fcid = lmp->atom->find_custom(&name[2],ltype,icol);
3449       else fcid = lmp->atom->find_custom(&name[3],ltype,icol);
3450 
3451       if (fcid < 0) {
3452         if (lmp->comm->me == 0)
3453           lmp->error->warning(FLERR,"lammps_gather_subset: unknown property/atom id");
3454         return;
3455       }
3456 
3457       if (ltype != type) {
3458         if (lmp->comm->me == 0)
3459           lmp->error->warning(FLERR,"lammps_gather_subset: mismatch property/atom type");
3460         return;
3461       }
3462       if (count == 1 && icol != 0) {
3463         if (lmp->comm->me == 0)
3464           lmp->error->warning(FLERR,"lammps_gather_subset: mismatch property/atom count");
3465         return;
3466       }
3467       if (count > 1 && icol != count) {
3468         if (lmp->comm->me == 0)
3469           lmp->error->warning(FLERR,"lammps_gather_subset: mismatch property/atom count");
3470         return;
3471       }
3472 
3473       if (count == 1) {
3474         if (ltype==0) vptr = (void *) lmp->atom->ivector[fcid];
3475         else vptr = (void *) lmp->atom->dvector[fcid];
3476       } else {
3477         if (ltype==0) vptr = (void *) lmp->atom->iarray[fcid];
3478         else vptr = (void *) lmp->atom->darray[fcid];
3479       }
3480     }
3481 
3482     // no match
3483 
3484     if (vptr == nullptr) {
3485       if (lmp->comm->me == 0)
3486         lmp->error->warning(FLERR,"lammps_gather_subset: undefined property name");
3487       return;
3488     }
3489 
3490     // copy = Ndata length vector of per-atom values
3491     // use atom ID to insert each atom's values into copy
3492     // MPI_Allreduce with MPI_SUM to merge into data
3493 
3494     if (type == 0) {
3495       int *vector = nullptr;
3496       int **array = nullptr;
3497       const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
3498 
3499       if ((count == 1) || imgunpack) vector = (int *) vptr;
3500       else array = (int **) vptr;
3501 
3502       int *copy;
3503       lmp->memory->create(copy,count*ndata,"lib/gather:copy");
3504       for (i = 0; i < count*ndata; i++) copy[i] = 0;
3505 
3506       int nlocal = lmp->atom->nlocal;
3507 
3508       if (count == 1) {
3509         for (i = 0; i < ndata; i++) {
3510           id = ids[i];
3511           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal)
3512             copy[i] = vector[m];
3513         }
3514 
3515       } else if (imgunpack) {
3516         for (i = 0; i < ndata; i++) {
3517           id = ids[i];
3518           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
3519             offset = count*i;
3520             const int image = vector[m];
3521             copy[offset++] = (image & IMGMASK) - IMGMAX;
3522             copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
3523             copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
3524           }
3525         }
3526 
3527       } else {
3528         for (i = 0; i < ndata; i++) {
3529           id = ids[i];
3530           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
3531             offset = count*i;
3532             for (j = 0; j < count; j++)
3533               copy[offset++] = array[m][j];
3534           }
3535         }
3536       }
3537 
3538       MPI_Allreduce(copy,data,count*ndata,MPI_INT,MPI_SUM,lmp->world);
3539       lmp->memory->destroy(copy);
3540 
3541     } else {
3542       double *vector = nullptr;
3543       double **array = nullptr;
3544 
3545       if (count == 1) vector = (double *) vptr;
3546       else array = (double **) vptr;
3547 
3548       double *copy;
3549       lmp->memory->create(copy,count*ndata,"lib/gather:copy");
3550       for (i = 0; i < count*ndata; i++) copy[i] = 0.0;
3551 
3552       int nlocal = lmp->atom->nlocal;
3553 
3554       if (count == 1) {
3555         for (i = 0; i < ndata; i++) {
3556           id = ids[i];
3557           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal)
3558             copy[i] = vector[m];
3559         }
3560 
3561       } else {
3562         for (i = 0; i < ndata; i++) {
3563           id = ids[i];
3564           if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
3565             offset = count*i;
3566             for (j = 0; j < count; j++)
3567               copy[offset++] = array[m][j];
3568           }
3569         }
3570       }
3571 
3572       MPI_Allreduce(copy,data,count*ndata,MPI_DOUBLE,MPI_SUM,lmp->world);
3573       lmp->memory->destroy(copy);
3574     }
3575 #endif
3576   }
3577   END_CAPTURE
3578 }
3579 
3580 /* ----------------------------------------------------------------------
3581   Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France)
3582   scatter the named atom-based entity in data to all atoms
3583   data will be ordered by atom ID
3584     requirement for consecutive atom IDs (1 to N)
3585   see scatter_subset() to scatter data for some (or all) atoms, unordered
3586   name = "x" , "f" or other atom properties
3587          "f_fix", "c_compute" for fixes / computes
3588          "d_name" or "i_name" for fix property/atom vectors with count = 1
3589          "d2_name" or "i2_name" for fix property/atom arrays with count > 1
3590          will return error if fix/compute isn't atom-based
3591   type = 0 for integer values, 1 for double values
3592   count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
3593     use count = 3 with "image" if want single image flag unpacked into xyz
3594   return atom-based values in 1d data, ordered by count, then by atom ID
3595     e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
3596     data must be pre-allocated by caller to correct length
3597     correct length = count*Natoms, as queried by get_natoms()
3598   method:
3599     alloc and zero count*Natom length vector
3600     loop over Nlocal to fill vector with my values
3601     Allreduce to sum vector into data across all procs
3602 ------------------------------------------------------------------------- */
3603 
lammps_scatter(void * handle,char * name,int type,int count,void * data)3604 void lammps_scatter(void *handle, char *name, int type, int count, void *data)
3605 {
3606   LAMMPS *lmp = (LAMMPS *) handle;
3607 
3608   BEGIN_CAPTURE
3609   {
3610 #if defined(LAMMPS_BIGBIG)
3611     lmp->error->all(FLERR,"Library function lammps_scatter() "
3612                     "is not compatible with -DLAMMPS_BIGBIG");
3613 #else
3614     int i,j,m,offset,fcid,ltype,icol;
3615 
3616     // error if tags are not defined or not consecutive or no atom map
3617     // NOTE: test that name = image or ids is not a 64-bit int in code?
3618 
3619     int flag = 0;
3620     if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0)
3621       flag = 1;
3622     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
3623     if (lmp->atom->map_style == Atom::MAP_NONE) flag = 1;
3624     if (flag) {
3625       if (lmp->comm->me == 0)
3626         lmp->error->warning(FLERR,"Library error in lammps_scatter");
3627       return;
3628     }
3629 
3630     int natoms = static_cast<int> (lmp->atom->natoms);
3631     void *vptr = lmp->atom->extract(name);
3632 
3633     // fix
3634 
3635     if (vptr==nullptr && utils::strmatch(name,"^f_")) {
3636 
3637       fcid = lmp->modify->find_fix(&name[2]);
3638       if (fcid < 0) {
3639         if (lmp->comm->me == 0)
3640           lmp->error->warning(FLERR,"lammps_scatter: unknown fix id");
3641         return;
3642       }
3643 
3644       if (lmp->modify->fix[fcid]->peratom_flag == 0) {
3645         if (lmp->comm->me == 0)
3646           lmp->error->warning(FLERR,"lammps_scatter:"
3647                               " fix does not return peratom data");
3648         return;
3649       }
3650       if (count>1 && lmp->modify->fix[fcid]->size_peratom_cols != count) {
3651         if (lmp->comm->me == 0)
3652           lmp->error->warning(FLERR,"lammps_scatter:"
3653                               " count != values peratom for fix");
3654         return;
3655       }
3656 
3657       if (count==1) vptr = (void *) lmp->modify->fix[fcid]->vector_atom;
3658       else vptr = (void *) lmp->modify->fix[fcid]->array_atom;
3659     }
3660 
3661     // compute
3662 
3663     if (vptr==nullptr && utils::strmatch(name,"^c_")) {
3664 
3665       fcid = lmp->modify->find_compute(&name[2]);
3666       if (fcid < 0) {
3667         if (lmp->comm->me == 0)
3668           lmp->error->warning(FLERR,"lammps_scatter: unknown compute id");
3669         return;
3670       }
3671 
3672       if (lmp->modify->compute[fcid]->peratom_flag == 0) {
3673         if (lmp->comm->me == 0)
3674           lmp->error->warning(FLERR,"lammps_scatter:"
3675                               " compute does not return peratom data");
3676         return;
3677       }
3678       if (count>1 && lmp->modify->compute[fcid]->size_peratom_cols != count) {
3679         if (lmp->comm->me == 0)
3680           lmp->error->warning(FLERR,"lammps_scatter:"
3681                               " count != values peratom for compute");
3682         return;
3683       }
3684 
3685       if (lmp->modify->compute[fcid]->invoked_peratom != lmp->update->ntimestep)
3686         lmp->modify->compute[fcid]->compute_peratom();
3687 
3688       if (count==1) vptr = (void *) lmp->modify->compute[fcid]->vector_atom;
3689       else vptr = (void *) lmp->modify->compute[fcid]->array_atom;
3690     }
3691 
3692     // custom fix property/atom vector or array
3693 
3694     if ((vptr == nullptr) && utils::strmatch(name,"^[id]2?_")) {
3695 
3696       if (utils::strmatch(name,"^[id]_"))
3697         fcid = lmp->atom->find_custom(&name[2],ltype,icol);
3698       else fcid = lmp->atom->find_custom(&name[3],ltype,icol);
3699 
3700       if (fcid < 0) {
3701         if (lmp->comm->me == 0)
3702           lmp->error->warning(FLERR,"lammps_scatter: unknown property/atom id");
3703         return;
3704       }
3705 
3706       if (ltype != type) {
3707         if (lmp->comm->me == 0)
3708           lmp->error->warning(FLERR,"lammps_scatter: mismatch property/atom type");
3709         return;
3710       }
3711       if (count == 1 && icol != 0) {
3712         if (lmp->comm->me == 0)
3713           lmp->error->warning(FLERR,"lammps_scatter: mismatch property/atom count");
3714         return;
3715       }
3716       if (count > 1 && icol != count) {
3717         if (lmp->comm->me == 0)
3718           lmp->error->warning(FLERR,"lammps_scatter: mismatch property/atom count");
3719         return;
3720       }
3721 
3722       if (count == 1) {
3723         if (ltype==0) vptr = (void *) lmp->atom->ivector[fcid];
3724         else vptr = (void *) lmp->atom->dvector[fcid];
3725       } else {
3726         if (ltype==0) vptr = (void *) lmp->atom->iarray[fcid];
3727         else vptr = (void *) lmp->atom->darray[fcid];
3728       }
3729     }
3730 
3731     // no match
3732 
3733     if (vptr == nullptr) {
3734       if (lmp->comm->me == 0)
3735         lmp->error->warning(FLERR,"lammps_scatter: unknown property name");
3736       return;
3737     }
3738 
3739     // copy = Natom length vector of per-atom values
3740     // use atom ID to insert each atom's values into copy
3741     // MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
3742 
3743     if (type == 0) {
3744       int *vector = nullptr;
3745       int **array = nullptr;
3746       const int imgpack = (count == 3) && (strcmp(name,"image") == 0);
3747 
3748       if ((count == 1) || imgpack) vector = (int *) vptr;
3749       else array = (int **) vptr;
3750       int *dptr = (int *) data;
3751 
3752       if (count == 1) {
3753         for (i = 0; i < natoms; i++)
3754           if ((m = lmp->atom->map(i+1)) >= 0)
3755             vector[m] = dptr[i];
3756 
3757       } else if (imgpack) {
3758         for (i = 0; i < natoms; i++)
3759           if ((m = lmp->atom->map(i+1)) >= 0) {
3760             offset = count*i;
3761             int image = dptr[offset++] + IMGMAX;
3762             image += (dptr[offset++] + IMGMAX) << IMGBITS;
3763             image += (dptr[offset++] + IMGMAX) << IMG2BITS;
3764             vector[m] = image;
3765           }
3766 
3767       } else {
3768         for (i = 0; i < natoms; i++)
3769           if ((m = lmp->atom->map(i+1)) >= 0) {
3770             offset = count*i;
3771             for (j = 0; j < count; j++)
3772               array[m][j] = dptr[offset++];
3773           }
3774       }
3775 
3776     } else {
3777       double *vector = nullptr;
3778       double **array = nullptr;
3779       if (count == 1) vector = (double *) vptr;
3780       else array = (double **) vptr;
3781       double *dptr = (double *) data;
3782 
3783       if (count == 1) {
3784         for (i = 0; i < natoms; i++)
3785           if ((m = lmp->atom->map(i+1)) >= 0)
3786             vector[m] = dptr[i];
3787 
3788       } else {
3789         for (i = 0; i < natoms; i++) {
3790           if ((m = lmp->atom->map(i+1)) >= 0) {
3791             offset = count*i;
3792             for (j = 0; j < count; j++)
3793               array[m][j] = dptr[offset++];
3794           }
3795         }
3796       }
3797     }
3798 #endif
3799   }
3800   END_CAPTURE
3801 }
3802 
3803 /* ----------------------------------------------------------------------
3804   Contributing author: Thomas Swinburne (CNRS & CINaM, Marseille, France)
3805    scatter the named atom-based entity in data to a subset of atoms
3806    data is ordered by provided atom IDs
3807      no requirement for consecutive atom IDs (1 to N)
3808    see scatter_atoms() to scatter data for all atoms, ordered by consecutive IDs
3809    name = "x" , "f" or other atom properties
3810           "d_name" or "i_name" for fix property/atom quantities
3811           "f_fix", "c_compute" for fixes / computes
3812           will return error if fix/compute doesn't isn't atom-based
3813    type = 0 for integer values, 1 for double values
3814    count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
3815      use count = 3 with "image" for xyz to be packed into single image flag
3816    ndata = # of atoms in ids and data (could be all atoms)
3817    ids = list of Ndata atom IDs to scatter data to
3818    data = atom-based values in 1d data, ordered by count, then by atom ID
3819      e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
3820      data must be correct length = count*Ndata
3821    method:
3822      loop over Ndata, if I own atom ID, set its values from data
3823 ------------------------------------------------------------------------- */
3824 
lammps_scatter_subset(void * handle,char * name,int type,int count,int ndata,int * ids,void * data)3825 void lammps_scatter_subset(void *handle, char *name,int type, int count,
3826                                  int ndata, int *ids, void *data)
3827 {
3828   LAMMPS *lmp = (LAMMPS *) handle;
3829 
3830   BEGIN_CAPTURE
3831   {
3832 #if defined(LAMMPS_BIGBIG)
3833     lmp->error->all(FLERR,"Library function lammps_scatter_subset() "
3834                     "is not compatible with -DLAMMPS_BIGBIG");
3835 #else
3836     int i,j,m,offset,fcid,ltype,icol;
3837     tagint id;
3838 
3839     // error if tags are not defined or no atom map
3840     // NOTE: test that name = image or ids is not a 64-bit int in code?
3841 
3842     int flag = 0;
3843     if (lmp->atom->tag_enable == 0) flag = 1;
3844     if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
3845     if (lmp->atom->map_style == Atom::MAP_NONE) flag = 1;
3846     if (flag) {
3847       if (lmp->comm->me == 0)
3848         lmp->error->warning(FLERR,"Library error in lammps_scatter_atoms_subset");
3849       return;
3850     }
3851 
3852     void *vptr = lmp->atom->extract(name);
3853 
3854     // fix
3855 
3856     if (vptr==nullptr && utils::strmatch(name,"^f_")) {
3857 
3858       fcid = lmp->modify->find_fix(&name[2]);
3859       if (fcid < 0) {
3860         if (lmp->comm->me == 0)
3861           lmp->error->warning(FLERR,"lammps_scatter_subset: unknown fix id");
3862         return;
3863       }
3864 
3865       if (lmp->modify->fix[fcid]->peratom_flag == 0) {
3866         if (lmp->comm->me == 0)
3867           lmp->error->warning(FLERR,"lammps_scatter_subset:"
3868                               " fix does not return peratom data");
3869         return;
3870       }
3871       if (count>1 && lmp->modify->fix[fcid]->size_peratom_cols != count) {
3872         if (lmp->comm->me == 0)
3873           lmp->error->warning(FLERR,"lammps_scatter_subset:"
3874                               " count != values peratom for fix");
3875         return;
3876       }
3877 
3878       if (count==1) vptr = (void *) lmp->modify->fix[fcid]->vector_atom;
3879       else vptr = (void *) lmp->modify->fix[fcid]->array_atom;
3880     }
3881 
3882     // compute
3883 
3884     if (vptr==nullptr && utils::strmatch(name,"^c_")) {
3885 
3886       fcid = lmp->modify->find_compute(&name[2]);
3887       if (fcid < 0) {
3888         if (lmp->comm->me == 0)
3889           lmp->error->warning(FLERR,"lammps_scatter_subset: unknown compute id");
3890         return;
3891       }
3892 
3893       if (lmp->modify->compute[fcid]->peratom_flag == 0) {
3894         if (lmp->comm->me == 0)
3895           lmp->error->warning(FLERR,"lammps_scatter_subset:"
3896                               " compute does not return peratom data");
3897         return;
3898       }
3899       if (count>1 && lmp->modify->compute[fcid]->size_peratom_cols != count) {
3900         if (lmp->comm->me == 0)
3901           lmp->error->warning(FLERR,"lammps_scatter_subset:"
3902                               " count != values peratom for compute");
3903         return;
3904       }
3905 
3906       if (lmp->modify->compute[fcid]->invoked_peratom != lmp->update->ntimestep)
3907         lmp->modify->compute[fcid]->compute_peratom();
3908 
3909       if (count==1) vptr = (void *) lmp->modify->compute[fcid]->vector_atom;
3910       else vptr = (void *) lmp->modify->compute[fcid]->array_atom;
3911     }
3912 
3913     // custom fix property/atom vector or array
3914 
3915     if ((vptr == nullptr) && utils::strmatch(name,"^[id]2?_")) {
3916 
3917       if (utils::strmatch(name,"^[id]_"))
3918         fcid = lmp->atom->find_custom(&name[2],ltype,icol);
3919       else fcid = lmp->atom->find_custom(&name[3],ltype,icol);
3920 
3921       if (fcid < 0) {
3922         if (lmp->comm->me == 0)
3923           lmp->error->warning(FLERR,"lammps_scatter_subset: unknown property/atom id");
3924         return;
3925       }
3926 
3927       if (ltype != type) {
3928         if (lmp->comm->me == 0)
3929           lmp->error->warning(FLERR,"lammps_scatter_subset: mismatch property/atom type");
3930         return;
3931       }
3932       if (count == 1 && icol != 0) {
3933         if (lmp->comm->me == 0)
3934           lmp->error->warning(FLERR,"lammps_gather: mismatch property/atom count");
3935         return;
3936       }
3937       if (count > 1 && icol != count) {
3938         if (lmp->comm->me == 0)
3939           lmp->error->warning(FLERR,"lammps_gather: mismatch property/atom count");
3940         return;
3941       }
3942 
3943       if (count == 1) {
3944         if (ltype==0) vptr = (void *) lmp->atom->ivector[fcid];
3945         else vptr = (void *) lmp->atom->dvector[fcid];
3946       } else {
3947         if (ltype==0) vptr = (void *) lmp->atom->iarray[fcid];
3948         else vptr = (void *) lmp->atom->darray[fcid];
3949       }
3950     }
3951 
3952     // no match
3953 
3954     if (vptr == nullptr) {
3955       if (lmp->comm->me == 0)
3956         lmp->error->warning(FLERR,"lammps_scatter_atoms_subset: "
3957                                   "unknown property name");
3958       return;
3959     }
3960 
3961     // copy = Natom length vector of per-atom values
3962     // use atom ID to insert each atom's values into copy
3963     // MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
3964 
3965     if (type == 0) {
3966       int *vector = nullptr;
3967       int **array = nullptr;
3968       const int imgpack = (count == 3) && (strcmp(name,"image") == 0);
3969 
3970       if ((count == 1) || imgpack) vector = (int *) vptr;
3971       else array = (int **) vptr;
3972       int *dptr = (int *) data;
3973 
3974       if (count == 1) {
3975         for (i = 0; i < ndata; i++) {
3976           id = ids[i];
3977           if ((m = lmp->atom->map(id)) >= 0)
3978             vector[m] = dptr[i];
3979         }
3980 
3981       } else if (imgpack) {
3982         for (i = 0; i < ndata; i++) {
3983           id = ids[i];
3984           if ((m = lmp->atom->map(id)) >= 0) {
3985             offset = count*i;
3986             int image = dptr[offset++] + IMGMAX;
3987             image += (dptr[offset++] + IMGMAX) << IMGBITS;
3988             image += (dptr[offset++] + IMGMAX) << IMG2BITS;
3989             vector[m] = image;
3990           }
3991         }
3992 
3993       } else {
3994         for (i = 0; i < ndata; i++) {
3995           id = ids[i];
3996           if ((m = lmp->atom->map(id)) >= 0) {
3997             offset = count*i;
3998             for (j = 0; j < count; j++)
3999               array[m][j] = dptr[offset++];
4000           }
4001         }
4002       }
4003 
4004     } else {
4005       double *vector = nullptr;
4006       double **array = nullptr;
4007       if (count == 1) vector = (double *) vptr;
4008       else array = (double **) vptr;
4009       double *dptr = (double *) data;
4010 
4011       if (count == 1) {
4012         for (i = 0; i < ndata; i++) {
4013           id = ids[i];
4014           if ((m = lmp->atom->map(id)) >= 0)
4015             vector[m] = dptr[i];
4016         }
4017 
4018       } else {
4019         for (i = 0; i < ndata; i++) {
4020           id = ids[i];
4021           if ((m = lmp->atom->map(id)) >= 0) {
4022             offset = count*i;
4023             for (j = 0; j < count; j++)
4024               array[m][j] = dptr[offset++];
4025           }
4026         }
4027       }
4028     }
4029 #endif
4030   }
4031   END_CAPTURE
4032 }
4033 
4034 /* ---------------------------------------------------------------------- */
4035 
4036 /** Create N atoms from list of coordinates
4037  *
4038 \verbatim embed:rst
4039 
4040 The prototype for this function when compiling with ``-DLAMMPS_BIGBIG``
4041 is:
4042 
4043 .. code-block:: c
4044 
4045    int lammps_create_atoms(void *handle, int n, int64_t *id, int *type, double *x, double *v, int64_t *image, int bexpand);
4046 
4047 This function creates additional atoms from a given list of coordinates
4048 and a list of atom types.  Additionally the atom-IDs, velocities, and
4049 image flags may be provided.  If atom-IDs are not provided, they will be
4050 automatically created as a sequence following the largest existing
4051 atom-ID.
4052 
4053 This function is useful to add atoms to a simulation or - in tandem with
4054 :cpp:func:`lammps_reset_box` - to restore a previously extracted and
4055 saved state of a simulation.  Additional properties for the new atoms
4056 can then be assigned via the :cpp:func:`lammps_scatter_atoms`
4057 :cpp:func:`lammps_extract_atom` functions.
4058 
4059 For non-periodic boundaries, atoms will **not** be created that have
4060 coordinates outside the box unless it is a shrink-wrap boundary and the
4061 shrinkexceed flag has been set to a non-zero value.  For periodic
4062 boundaries atoms will be wrapped back into the simulation cell and its
4063 image flags adjusted accordingly, unless explicit image flags are
4064 provided.
4065 
4066 The function returns the number of atoms created or -1 on failure, e.g.
4067 when called before as box has been created.
4068 
4069 Coordinates and velocities have to be given in a 1d-array in the order
4070 X(1),Y(1),Z(1),X(2),Y(2),Z(2),...,X(N),Y(N),Z(N).
4071 
4072 \endverbatim
4073  *
4074  * \param  handle   pointer to a previously created LAMMPS instance
4075  * \param  n        number of atoms, N, to be added to the system
4076  * \param  id       pointer to N atom IDs; ``NULL`` will generate IDs
4077  * \param  type     pointer to N atom types (required)
4078  * \param  x        pointer to 3N doubles with x-,y-,z- positions
4079                     of the new atoms (required)
4080  * \param  v        pointer to 3N doubles with x-,y-,z- velocities
4081                     of the new atoms (set to 0.0 if ``NULL``)
4082  * \param  image    pointer to N imageint sets of image flags, or ``NULL``
4083  * \param  bexpand  if 1, atoms outside of shrink-wrap boundaries will
4084                     still be created and not dropped and the box extended
4085  * \return          number of atoms created on success;
4086                     -1 on failure (no box, no atom IDs, etc.) */
4087 
lammps_create_atoms(void * handle,int n,const tagint * id,const int * type,const double * x,const double * v,const imageint * image,int bexpand)4088 int lammps_create_atoms(void *handle, int n, const tagint *id, const int *type,
4089                         const double *x, const double *v, const imageint *image,
4090                         int bexpand)
4091 {
4092   LAMMPS *lmp = (LAMMPS *) handle;
4093   bigint natoms_prev = lmp->atom->natoms;
4094 
4095   BEGIN_CAPTURE
4096   {
4097     // error if box does not exist or tags not defined
4098 
4099     int flag = 0;
4100     std::string msg("Failure in lammps_create_atoms: ");
4101     if (lmp->domain->box_exist == 0) {
4102       flag = 1;
4103       msg += "trying to create atoms before before simulation box is defined";
4104     }
4105     if (lmp->atom->tag_enable == 0) {
4106       flag = 1;
4107       msg += "must have atom IDs to use this function";
4108     }
4109 
4110     if (flag) {
4111       if (lmp->comm->me == 0) lmp->error->warning(FLERR,msg);
4112       return -1;
4113     }
4114 
4115     // loop over all N atoms on all MPI ranks
4116     // if this proc would own it based on its coordinates, invoke create_atom()
4117     // optionally set atom tags and velocities
4118 
4119     Atom *atom = lmp->atom;
4120     Domain *domain = lmp->domain;
4121     int nlocal = atom->nlocal;
4122 
4123     int nlocal_prev = nlocal;
4124     double xdata[3];
4125     imageint idata, *img;
4126 
4127     for (int i = 0; i < n; i++) {
4128       xdata[0] = x[3*i];
4129       xdata[1] = x[3*i+1];
4130       xdata[2] = x[3*i+2];
4131       if (image) {
4132         idata = image[i];
4133         img = &idata;
4134       } else img = nullptr;
4135       const tagint tag = id ? id[i] : 0;
4136 
4137       // create atom only on MPI rank that would own it
4138 
4139       if (!domain->ownatom(tag, xdata, img, bexpand)) continue;
4140 
4141       atom->avec->create_atom(type[i],xdata);
4142       if (id) atom->tag[nlocal] = id[i];
4143       else atom->tag[nlocal] = 0;
4144       if (v) {
4145         atom->v[nlocal][0] = v[3*i];
4146         atom->v[nlocal][1] = v[3*i+1];
4147         atom->v[nlocal][2] = v[3*i+2];
4148       }
4149       if (image) atom->image[nlocal] = image[i];
4150       nlocal++;
4151     }
4152 
4153     // if no tags are given explicitly, create new and unique tags
4154 
4155     if (id == nullptr) atom->tag_extend();
4156 
4157     // reset box info, if extended when adding atoms.
4158 
4159     if (bexpand) domain->reset_box();
4160 
4161     // need to reset atom->natoms inside LAMMPS
4162 
4163     bigint ncurrent = nlocal;
4164     MPI_Allreduce(&ncurrent,&lmp->atom->natoms,1,MPI_LMP_BIGINT,
4165                   MPI_SUM,lmp->world);
4166 
4167     // init per-atom fix/compute/variable values for created atoms
4168 
4169     atom->data_fix_compute_variable(nlocal_prev,nlocal);
4170 
4171     // if global map exists, reset it
4172     // invoke map_init() b/c atom count has grown
4173 
4174     if (lmp->atom->map_style != Atom::MAP_NONE) {
4175       lmp->atom->map_init();
4176       lmp->atom->map_set();
4177     }
4178   }
4179   END_CAPTURE;
4180   return (int) lmp->atom->natoms - natoms_prev;
4181 }
4182 
4183 // ----------------------------------------------------------------------
4184 // Library functions for accessing neighbor lists
4185 // ----------------------------------------------------------------------
4186 
4187 /** Find index of a neighbor list requested by a pair style
4188  *
4189  * This function determines which of the available neighbor lists for
4190  * pair styles matches the given conditions.  It first matches the style
4191  * name. If exact is 1 the name must match exactly, if exact is 0, a
4192  * regular expression or sub-string match is done.  If the pair style is
4193  * hybrid or hybrid/overlay the style is matched against the sub styles
4194  * instead.
4195  * If a the same pair style is used multiple times as a sub-style, the
4196  * nsub argument must be > 0 and represents the nth instance of the sub-style
4197  * (same as for the pair_coeff command, for example).  In that case
4198  * nsub=0 will not produce a match and this function will return -1.
4199  *
4200  * The final condition to be checked is the request ID (reqid).  This
4201  * will normally be 0, but some pair styles request multiple neighbor
4202  * lists and set the request ID to a value > 0.
4203  *
4204  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4205  * \param  style    String used to search for pair style instance
4206  * \param  exact    Flag to control whether style should match exactly or only
4207  *                  a regular expression / sub-string match is applied.
4208  * \param  nsub     match nsub-th hybrid sub-style instance of the same style
4209  * \param  reqid    request id to identify neighbor list in case there are
4210  *                  multiple requests from the same pair style instance
4211  * \return          return neighbor list index if found, otherwise -1 */
4212 
lammps_find_pair_neighlist(void * handle,const char * style,int exact,int nsub,int reqid)4213 int lammps_find_pair_neighlist(void *handle, const char *style, int exact, int nsub, int reqid) {
4214   LAMMPS *lmp = (LAMMPS *) handle;
4215   Pair *pair = lmp->force->pair_match(style, exact, nsub);
4216 
4217   if (pair != nullptr) {
4218     // find neigh list
4219     for (int i = 0; i < lmp->neighbor->nlist; i++) {
4220       NeighList *list = lmp->neighbor->lists[i];
4221       if ( (list->requestor_type == NeighList::PAIR)
4222            && (pair == list->requestor)
4223            && (list->id == reqid) ) return i;
4224     }
4225   }
4226   return -1;
4227 }
4228 
4229 /* ---------------------------------------------------------------------- */
4230 
4231 /** Find index of a neighbor list requested by a fix
4232  *
4233  * The neighbor list request from a fix is identified by the fix ID and
4234  * the request ID.  The request ID is typically 0, but will be > 0 in
4235  * case a fix has multiple neighbor list requests.
4236  *
4237  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4238  * \param id       Identifier of fix instance
4239  * \param reqid    request id to identify neighbor list in case there are
4240  *                 multiple requests from the same fix
4241  * \return         return neighbor list index if found, otherwise -1  */
4242 
lammps_find_fix_neighlist(void * handle,const char * id,int reqid)4243 int lammps_find_fix_neighlist(void *handle, const char *id, int reqid) {
4244   LAMMPS *lmp = (LAMMPS *) handle;
4245   const int ifix = lmp->modify->find_fix(id);
4246   if (ifix < 0) return -1;
4247 
4248   Fix *fix = lmp->modify->fix[ifix];
4249   // find neigh list
4250   for (int i = 0; i < lmp->neighbor->nlist; i++) {
4251     NeighList *list = lmp->neighbor->lists[i];
4252     if ( (list->requestor_type == NeighList::FIX)
4253          && (fix == list->requestor)
4254          && (list->id == reqid) ) return i;
4255   }
4256   return -1;
4257 }
4258 
4259 /* ---------------------------------------------------------------------- */
4260 
4261 /** Find index of a neighbor list requested by a compute
4262  *
4263  * The neighbor list request from a compute is identified by the compute
4264  * ID and the request ID.  The request ID is typically 0, but will be
4265  * > 0 in case a compute has multiple neighbor list requests.
4266  *
4267  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4268  * \param id       Identifier of compute instance
4269  * \param reqid    request id to identify neighbor list in case there are
4270  *                 multiple requests from the same compute
4271  * \return         return neighbor list index if found, otherwise -1 */
4272 
lammps_find_compute_neighlist(void * handle,const char * id,int reqid)4273 int lammps_find_compute_neighlist(void* handle, const char *id, int reqid) {
4274   LAMMPS *lmp = (LAMMPS *) handle;
4275   const int icompute = lmp->modify->find_compute(id);
4276   if (icompute < 0) return -1;
4277 
4278   Compute *compute = lmp->modify->compute[icompute];
4279   // find neigh list
4280   for (int i = 0; i < lmp->neighbor->nlist; i++) {
4281     NeighList * list = lmp->neighbor->lists[i];
4282     if ( (list->requestor_type == NeighList::COMPUTE)
4283          && (compute == list->requestor)
4284          && (list->id == reqid) ) return i;
4285   }
4286   return -1;
4287 }
4288 
4289 /* ---------------------------------------------------------------------- */
4290 
4291 /** Return the number of entries in the neighbor list with given index
4292  *
4293  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4294  * \param idx      neighbor list index
4295  * \return         return number of entries in neighbor list, -1 if idx is
4296  *                 not a valid index
4297  */
lammps_neighlist_num_elements(void * handle,int idx)4298 int lammps_neighlist_num_elements(void *handle, int idx) {
4299   LAMMPS *  lmp = (LAMMPS *) handle;
4300   Neighbor * neighbor = lmp->neighbor;
4301 
4302   if (idx < 0 || idx >= neighbor->nlist) {
4303     return -1;
4304   }
4305 
4306   NeighList * list = neighbor->lists[idx];
4307   return list->inum;
4308 }
4309 
4310 /* ---------------------------------------------------------------------- */
4311 
4312 /** Return atom local index, number of neighbors, and array of neighbor local
4313  * atom indices of neighbor list entry
4314  *
4315  * \param handle          pointer to a previously created LAMMPS instance cast to ``void *``.
4316  * \param idx             index of this neighbor list in the list of all neighbor lists
4317  * \param element         index of this neighbor list entry
4318  * \param[out] iatom      local atom index (i.e. in the range [0, nlocal + nghost), -1 if
4319                           invalid idx or element value
4320  * \param[out] numneigh   number of neighbors of atom iatom or 0
4321  * \param[out] neighbors  pointer to array of neighbor atom local indices or NULL */
4322 
lammps_neighlist_element_neighbors(void * handle,int idx,int element,int * iatom,int * numneigh,int ** neighbors)4323 void lammps_neighlist_element_neighbors(void *handle, int idx, int element, int *iatom, int *numneigh, int **neighbors) {
4324   LAMMPS *  lmp = (LAMMPS *) handle;
4325   Neighbor * neighbor = lmp->neighbor;
4326   *iatom = -1;
4327   *numneigh = 0;
4328   *neighbors = nullptr;
4329 
4330   if (idx < 0 || idx >= neighbor->nlist) {
4331     return;
4332   }
4333 
4334   NeighList * list = neighbor->lists[idx];
4335 
4336   if (element < 0 || element >= list->inum) {
4337     return;
4338   }
4339 
4340   int i = list->ilist[element];
4341   *iatom     = i;
4342   *numneigh  = list->numneigh[i];
4343   *neighbors = list->firstneigh[i];
4344 }
4345 
4346 // ----------------------------------------------------------------------
4347 // Library functions for accessing LAMMPS configuration
4348 // ----------------------------------------------------------------------
4349 
4350 /** Get numerical representation of the LAMMPS version date.
4351  *
4352 \verbatim embed:rst
4353 
4354 The :cpp:func:`lammps_version` function returns an integer representing
4355 the version of the LAMMPS code in the format YYYYMMDD.  This can be used
4356 to implement backward compatibility in software using the LAMMPS library
4357 interface.  The specific format guarantees, that this version number is
4358 growing with every new LAMMPS release.
4359 
4360 \endverbatim
4361  *
4362  * \param  handle  pointer to a previously created LAMMPS instance
4363  * \return         an integer representing the version data in the
4364  *                 format YYYYMMDD */
4365 
lammps_version(void * handle)4366 int lammps_version(void *handle)
4367 {
4368   LAMMPS *lmp = (LAMMPS *) handle;
4369   return lmp->num_ver;
4370 }
4371 
4372 /** Get operating system and architecture information
4373  *
4374 \verbatim embed:rst
4375 
4376 The :cpp:func:`lammps_get_os_info` function can be used to retrieve
4377 detailed information about the hosting operating system and
4378 compiler/runtime.
4379 
4380 A suitable buffer for a C-style string has to be provided and its length.
4381 The assembled text will be truncated to not overflow this buffer. The
4382 string is typically a few hundred bytes long.
4383 
4384 .. versionadded:: 9Oct2020
4385 
4386 \endverbatim
4387  *
4388  * \param  buffer    string buffer to copy the information to
4389  * \param  buf_size  size of the provided string buffer */
4390 
4391 /* ---------------------------------------------------------------------- */
4392 
lammps_get_os_info(char * buffer,int buf_size)4393 void lammps_get_os_info(char *buffer, int buf_size)
4394 {
4395   if (buf_size <=0) return;
4396   buffer[0] = buffer[buf_size-1] = '\0';
4397   std::string txt = Info::get_os_info() + "\n";
4398   txt += Info::get_compiler_info();
4399   txt += " with " + Info::get_openmp_info() + "\n";
4400   strncpy(buffer, txt.c_str(), buf_size-1);
4401 }
4402 
4403 /* ---------------------------------------------------------------------- */
4404 
4405 /** This function is used to query whether LAMMPS was compiled with
4406  *  a real MPI library or in serial. For the real MPI library it
4407  *  reports the size of the MPI communicator in bytes (4 or 8),
4408  *  which allows to check for compatibility with a hosting code.
4409  *
4410  * \return 0 when compiled with MPI STUBS, otherwise the MPI_Comm size in bytes */
4411 
lammps_config_has_mpi_support()4412 int lammps_config_has_mpi_support()
4413 {
4414 #ifdef MPI_STUBS
4415   return 0;
4416 #else
4417   return sizeof(MPI_Comm);
4418 #endif
4419 }
4420 
4421 /* ---------------------------------------------------------------------- */
4422 
4423 /** Check if the LAMMPS library supports compressed files via a pipe to gzip
4424 
4425 \verbatim embed:rst
4426 Several LAMMPS commands (e.g. :doc:`read_data`, :doc:`write_data`,
4427 :doc:`dump styles atom, custom, and xyz <dump>`) support reading and
4428 writing compressed files via creating a pipe to the ``gzip`` program.
4429 This function checks whether this feature was :ref:`enabled at compile
4430 time <gzip>`. It does **not** check whether the ``gzip`` itself is
4431 installed and usable.
4432 \endverbatim
4433  *
4434  * \return 1 if yes, otherwise 0
4435  */
lammps_config_has_gzip_support()4436 int lammps_config_has_gzip_support() {
4437   return Info::has_gzip_support() ? 1 : 0;
4438 }
4439 
4440 /* ---------------------------------------------------------------------- */
4441 
4442 /** Check if the LAMMPS library supports writing PNG format images
4443 
4444 \verbatim embed:rst
4445 The LAMMPS :doc:`dump style image <dump_image>` supports writing multiple
4446 image file formats.  Most of them need, however, support from an external
4447 library and using that has to be :ref:`enabled at compile time <graphics>`.
4448 This function checks whether support for the `PNG image file format
4449 <https://en.wikipedia.org/wiki/Portable_Network_Graphics>`_ is available
4450 in the current LAMMPS library.
4451 \endverbatim
4452  *
4453  * \return 1 if yes, otherwise 0
4454  */
lammps_config_has_png_support()4455 int lammps_config_has_png_support() {
4456   return Info::has_png_support() ? 1 : 0;
4457 }
4458 
4459 /* ---------------------------------------------------------------------- */
4460 
4461 /** Check if the LAMMPS library supports writing JPEG format images
4462 
4463 \verbatim embed:rst
4464 The LAMMPS :doc:`dump style image <dump_image>` supports writing multiple
4465 image file formats.  Most of them need, however, support from an external
4466 library and using that has to be :ref:`enabled at compile time <graphics>`.
4467 This function checks whether support for the `JPEG image file format
4468 <https://jpeg.org/jpeg/>`_ is available in the current LAMMPS library.
4469 \endverbatim
4470  *
4471  * \return 1 if yes, otherwise 0
4472  */
lammps_config_has_jpeg_support()4473 int lammps_config_has_jpeg_support() {
4474   return Info::has_jpeg_support() ? 1 : 0;
4475 }
4476 
4477 /* ---------------------------------------------------------------------- */
4478 
4479 /** Check if the LAMMPS library supports creating movie files via a pipe to ffmpeg
4480 
4481 \verbatim embed:rst
4482 The LAMMPS :doc:`dump style movie <dump_image>` supports generating movies
4483 from images on-the-fly  via creating a pipe to the
4484 `ffmpeg <https://ffmpeg.org/ffmpeg/>`_ program.
4485 This function checks whether this feature was :ref:`enabled at compile time <graphics>`.
4486 It does **not** check whether the ``ffmpeg`` itself is installed and usable.
4487 \endverbatim
4488  *
4489  * \return 1 if yes, otherwise 0
4490  */
lammps_config_has_ffmpeg_support()4491 int lammps_config_has_ffmpeg_support() {
4492   return Info::has_ffmpeg_support() ? 1 : 0;
4493 }
4494 
4495 /* ---------------------------------------------------------------------- */
4496 
4497 /** Check whether LAMMPS errors will throw a C++ exception
4498  *
4499 \verbatim embed:rst
4500 In case of errors LAMMPS will either abort or throw a C++ exception.
4501 The latter has to be :ref:`enabled at compile time <exceptions>`.
4502 This function checks if exceptions were enabled.
4503 
4504 When using the library interface and C++ exceptions are enabled,
4505 the library interface functions will "catch" them and the
4506 error status can then be checked by calling
4507 :cpp:func:`lammps_has_error` and the most recent error message
4508 can be retrieved via :cpp:func:`lammps_get_last_error_message`.
4509 This can allow to restart a calculation or delete and recreate
4510 the LAMMPS instance when C++ exceptions are enabled.  One application
4511 of using exceptions this way is the :ref:`lammps_shell`.  If C++
4512 exceptions are disabled and an error happens during a call to
4513 LAMMPS, the application will terminate.
4514 \endverbatim
4515  * \return 1 if yes, otherwise 0
4516  */
lammps_config_has_exceptions()4517 int lammps_config_has_exceptions() {
4518   return Info::has_exceptions() ? 1 : 0;
4519 }
4520 
4521 /* ---------------------------------------------------------------------- */
4522 
4523 /** Check if a specific package has been included in LAMMPS
4524  *
4525 \verbatim embed:rst
4526 This function checks if the LAMMPS library in use includes the
4527 specific :doc:`LAMMPS package <Packages>` provided as argument.
4528 \endverbatim
4529  *
4530  * \param name string with the name of the package
4531  * \return 1 if included, 0 if not.
4532  */
lammps_config_has_package(const char * name)4533 int lammps_config_has_package(const char *name) {
4534   return Info::has_package(name) ? 1 : 0;
4535 }
4536 
4537 /* ---------------------------------------------------------------------- */
4538 
4539 /** Count the number of installed packages in the LAMMPS library.
4540  *
4541 \verbatim embed:rst
4542 This function counts how many :doc:`LAMMPS packages <Packages>` are
4543 included in the LAMMPS library in use.
4544 \endverbatim
4545  *
4546  * \return number of packages included
4547  */
lammps_config_package_count()4548 int lammps_config_package_count() {
4549   int i = 0;
4550   while (LAMMPS::installed_packages[i] != nullptr) {
4551     ++i;
4552   }
4553   return i;
4554 }
4555 
4556 /* ---------------------------------------------------------------------- */
4557 
4558 /** Get the name of a package in the list of installed packages in the LAMMPS library.
4559  *
4560 \verbatim embed:rst
4561 This function copies the name of the package with the index *idx* into the
4562 provided C-style string buffer.  The length of the buffer must be provided
4563 as *buf_size* argument.  If the name of the package exceeds the length of the
4564 buffer, it will be truncated accordingly.  If the index is out of range,
4565 the function returns 0 and *buffer* is set to an empty string, otherwise 1;
4566 \endverbatim
4567  *
4568  * \param idx index of the package in the list of included packages (0 <= idx < package count)
4569  * \param buffer string buffer to copy the name of the package to
4570  * \param buf_size size of the provided string buffer
4571  * \return 1 if successful, otherwise 0
4572  */
lammps_config_package_name(int idx,char * buffer,int buf_size)4573 int lammps_config_package_name(int idx, char *buffer, int buf_size) {
4574   int maxidx = lammps_config_package_count();
4575   if ((idx < 0) || (idx >= maxidx)) {
4576       buffer[0] = '\0';
4577       return 0;
4578   }
4579 
4580   strncpy(buffer, LAMMPS::installed_packages[idx], buf_size);
4581   return 1;
4582 }
4583 
4584 /** Check for compile time settings in accelerator packages included in LAMMPS.
4585  *
4586 \verbatim embed:rst
4587 This function checks availability of compile time settings of included
4588 :doc:`accelerator packages <Speed_packages>` in LAMMPS.
4589 Supported packages names are "GPU", "KOKKOS", "INTEL", and "OPENMP".
4590 Supported categories are "api" with possible settings "cuda", "hip", "phi",
4591 "pthreads", "opencl", "openmp", and "serial", and "precision" with
4592 possible settings "double", "mixed", and "single".  If the combination
4593 of package, category, and setting is available, the function returns 1,
4594 otherwise 0.
4595 \endverbatim
4596  *
4597  * \param  package   string with the name of the accelerator package
4598  * \param  category  string with the category name of the setting
4599  * \param  setting   string with the name of the specific setting
4600  * \return 1 if available, 0 if not.
4601  */
lammps_config_accelerator(const char * package,const char * category,const char * setting)4602 int lammps_config_accelerator(const char *package,
4603                               const char *category,
4604                               const char *setting)
4605 {
4606   return Info::has_accelerator_feature(package,category,setting) ? 1 : 0;
4607 }
4608 
4609 /** Check for presence of a viable GPU package device
4610  *
4611 \verbatim embed:rst
4612 
4613 The :cpp:func:`lammps_has_gpu_device` function checks at runtime if
4614 an accelerator device is present that can be used with the
4615 :doc:`GPU package <Speed_gpu>`. If at least one suitable device is
4616 present the function will return 1, otherwise 0.
4617 
4618 More detailed information about the available device or devices can
4619 be obtained by calling the
4620 :cpp:func:`lammps_get_gpu_device_info` function.
4621 
4622 .. versionadded:: 14May2021
4623 
4624 \endverbatim
4625  *
4626  * \return  1 if viable device is available, 0 if not.  */
4627 
lammps_has_gpu_device()4628 int lammps_has_gpu_device()
4629 {
4630   return Info::has_gpu_device() ? 1: 0;
4631 }
4632 
4633 /** Get GPU package device information
4634  *
4635 \verbatim embed:rst
4636 
4637 The :cpp:func:`lammps_get_gpu_device_info` function can be used to retrieve
4638 detailed information about any accelerator devices that are viable for use
4639 with the :doc:`GPU package <Speed_gpu>`.  It will produce a string that is
4640 equivalent to the output of the ``nvc_get_device`` or ``ocl_get_device`` or
4641 ``hip_get_device`` tools that are compiled alongside LAMMPS if the GPU
4642 package is enabled.
4643 
4644 A suitable buffer for a C-style string has to be provided and its length.
4645 The assembled text will be truncated to not overflow this buffer.  This
4646 string can be several kilobytes long, if multiple devices are present.
4647 
4648 .. versionadded:: 14May2021
4649 
4650 \endverbatim
4651  *
4652  * \param  buffer    string buffer to copy the information to
4653  * \param  buf_size  size of the provided string buffer */
4654 
lammps_get_gpu_device_info(char * buffer,int buf_size)4655 void lammps_get_gpu_device_info(char *buffer, int buf_size)
4656 {
4657   if (buf_size <= 0) return;
4658   buffer[0] = buffer[buf_size-1] = '\0';
4659   std::string devinfo = Info::get_gpu_device_info();
4660   strncpy(buffer, devinfo.c_str(), buf_size-1);
4661 }
4662 
4663 /* ---------------------------------------------------------------------- */
4664 
4665 /** Check if a specific style has been included in LAMMPS
4666  *
4667 \verbatim embed:rst
4668 This function checks if the LAMMPS library in use includes the
4669 specific *style* of a specific *category* provided as an argument.
4670 Valid categories are: *atom*\ , *integrate*\ , *minimize*\ ,
4671 *pair*\ , *bond*\ , *angle*\ , *dihedral*\ , *improper*\ , *kspace*\ ,
4672 *compute*\ , *fix*\ , *region*\ , *dump*\ , and *command*\ .
4673 \endverbatim
4674  *
4675  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4676  * \param  category  category of the style
4677  * \param  name      name of the style
4678  * \return           1 if included, 0 if not.
4679  */
lammps_has_style(void * handle,const char * category,const char * name)4680 int lammps_has_style(void *handle, const char *category, const char *name) {
4681   LAMMPS *lmp = (LAMMPS *) handle;
4682   Info info(lmp);
4683   return info.has_style(category, name) ? 1 : 0;
4684 }
4685 
4686 /* ---------------------------------------------------------------------- */
4687 
4688 /** Count the number of styles of category in the LAMMPS library.
4689  *
4690 \verbatim embed:rst
4691 This function counts how many styles in the provided *category*
4692 are included in the LAMMPS library in use.
4693 Please see :cpp:func:`lammps_has_style` for a list of valid
4694 categories.
4695 \endverbatim
4696  *
4697  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4698  * \param category category of styles
4699  * \return number of styles in category
4700  */
lammps_style_count(void * handle,const char * category)4701 int lammps_style_count(void *handle, const char *category) {
4702   LAMMPS *lmp = (LAMMPS *) handle;
4703   Info info(lmp);
4704   return info.get_available_styles(category).size();
4705 }
4706 
4707 /* ---------------------------------------------------------------------- */
4708 
4709 /** Look up the name of a style by index in the list of style of a given category in the LAMMPS library.
4710  *
4711  *
4712  * This function copies the name of the *category* style with the index
4713  * *idx* into the provided C-style string buffer.  The length of the buffer
4714  * must be provided as *buf_size* argument.  If the name of the style
4715  * exceeds the length of the buffer, it will be truncated accordingly.
4716  * If the index is out of range, the function returns 0 and *buffer* is
4717  * set to an empty string, otherwise 1.
4718  *
4719  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4720  * \param category category of styles
4721  * \param idx      index of the style in the list of *category* styles (0 <= idx < style count)
4722  * \param buffer   string buffer to copy the name of the style to
4723  * \param buf_size size of the provided string buffer
4724  * \return 1 if successful, otherwise 0
4725  */
lammps_style_name(void * handle,const char * category,int idx,char * buffer,int buf_size)4726 int lammps_style_name(void *handle, const char *category, int idx,
4727                       char *buffer, int buf_size) {
4728   LAMMPS *lmp = (LAMMPS *) handle;
4729   Info info(lmp);
4730   auto styles = info.get_available_styles(category);
4731 
4732   if ((idx >=0) && (idx < (int) styles.size())) {
4733     strncpy(buffer, styles[idx].c_str(), buf_size);
4734     return 1;
4735   }
4736 
4737   buffer[0] = '\0';
4738   return 0;
4739 }
4740 
4741 /* ---------------------------------------------------------------------- */
4742 
4743 /** Check if a specific ID exists in the current LAMMPS instance
4744  *
4745 \verbatim embed:rst
4746 This function checks if the current LAMMPS instance a *category* ID of
4747 the given *name* exists.  Valid categories are: *compute*\ , *dump*\ ,
4748 *fix*\ , *group*\ , *molecule*\ , *region*\ , and *variable*\ .
4749 
4750 .. versionadded:: 9Oct2020
4751 
4752 \endverbatim
4753  *
4754  * \param  handle    pointer to a previously created LAMMPS instance cast to ``void *``.
4755  * \param  category  category of the id
4756  * \param  name      name of the id
4757  * \return           1 if included, 0 if not.
4758  */
lammps_has_id(void * handle,const char * category,const char * name)4759 int lammps_has_id(void *handle, const char *category, const char *name) {
4760   LAMMPS *lmp = (LAMMPS *) handle;
4761 
4762   if (strcmp(category,"compute") == 0) {
4763     int ncompute = lmp->modify->ncompute;
4764     Compute **compute = lmp->modify->compute;
4765     for (int i=0; i < ncompute; ++i) {
4766       if (strcmp(name,compute[i]->id) == 0) return 1;
4767     }
4768   } else if (strcmp(category,"dump") == 0) {
4769     int ndump = lmp->output->ndump;
4770     Dump **dump = lmp->output->dump;
4771     for (int i=0; i < ndump; ++i) {
4772       if (strcmp(name,dump[i]->id) == 0) return 1;
4773     }
4774   } else if (strcmp(category,"fix") == 0) {
4775     int nfix = lmp->modify->nfix;
4776     Fix **fix = lmp->modify->fix;
4777     for (int i=0; i < nfix; ++i) {
4778       if (strcmp(name,fix[i]->id) == 0) return 1;
4779     }
4780   } else if (strcmp(category,"group") == 0) {
4781     int ngroup = lmp->group->ngroup;
4782     char **groups = lmp->group->names;
4783     for (int i=0; i < ngroup; ++i) {
4784       if (strcmp(groups[i],name) == 0) return 1;
4785     }
4786   } else if (strcmp(category,"molecule") == 0) {
4787     int nmolecule = lmp->atom->nmolecule;
4788     Molecule **molecule = lmp->atom->molecules;
4789     for (int i=0; i < nmolecule; ++i) {
4790       if (strcmp(name,molecule[i]->id) == 0) return 1;
4791     }
4792   } else if (strcmp(category,"region") == 0) {
4793     int nregion = lmp->domain->nregion;
4794     Region **region = lmp->domain->regions;
4795     for (int i=0; i < nregion; ++i) {
4796       if (strcmp(name,region[i]->id) == 0) return 1;
4797     }
4798   } else if (strcmp(category,"variable") == 0) {
4799     int nvariable = lmp->input->variable->nvar;
4800     char **varnames = lmp->input->variable->names;
4801     for (int i=0; i < nvariable; ++i) {
4802       if (strcmp(name,varnames[i]) == 0) return 1;
4803     }
4804   }
4805   return 0;
4806 }
4807 
4808 /* ---------------------------------------------------------------------- */
4809 
4810 /** Count the number of IDs of a category.
4811  *
4812 \verbatim embed:rst
4813 This function counts how many IDs in the provided *category*
4814 are defined in the current LAMMPS instance.
4815 Please see :cpp:func:`lammps_has_id` for a list of valid
4816 categories.
4817 
4818 .. versionadded:: 9Oct2020
4819 
4820 \endverbatim
4821  *
4822  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4823  * \param category category of IDs
4824  * \return number of IDs in category
4825  */
lammps_id_count(void * handle,const char * category)4826 int lammps_id_count(void *handle, const char *category) {
4827   LAMMPS *lmp = (LAMMPS *) handle;
4828   if (strcmp(category,"compute") == 0) {
4829     return lmp->modify->ncompute;
4830   } else if (strcmp(category,"dump") == 0) {
4831     return lmp->output->ndump;
4832   } else if (strcmp(category,"fix") == 0) {
4833     return lmp->modify->nfix;
4834   } else if (strcmp(category,"group") == 0) {
4835     return lmp->group->ngroup;
4836   } else if (strcmp(category,"molecule") == 0) {
4837     return lmp->atom->nmolecule;
4838   } else if (strcmp(category,"region") == 0) {
4839     return lmp->domain->nregion;
4840   } else if (strcmp(category,"variable") == 0) {
4841     return lmp->input->variable->nvar;
4842   }
4843   return 0;
4844 }
4845 
4846 /* ---------------------------------------------------------------------- */
4847 
4848 /** Look up the name of an ID by index in the list of IDs of a given category.
4849  *
4850 \verbatim embed:rst
4851 This function copies the name of the *category* ID with the index
4852 *idx* into the provided C-style string buffer.  The length of the buffer
4853 must be provided as *buf_size* argument.  If the name of the style
4854 exceeds the length of the buffer, it will be truncated accordingly.
4855 If the index is out of range, the function returns 0 and *buffer* is
4856 set to an empty string, otherwise 1.
4857 
4858 .. versionadded:: 9Oct2020
4859 
4860 \endverbatim
4861  *
4862  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
4863  * \param category category of IDs
4864  * \param idx      index of the ID in the list of *category* styles (0 <= idx < count)
4865  * \param buffer   string buffer to copy the name of the style to
4866  * \param buf_size size of the provided string buffer
4867  * \return 1 if successful, otherwise 0
4868  */
lammps_id_name(void * handle,const char * category,int idx,char * buffer,int buf_size)4869 int lammps_id_name(void *handle, const char *category, int idx,
4870                       char *buffer, int buf_size) {
4871   LAMMPS *lmp = (LAMMPS *) handle;
4872 
4873   if (strcmp(category,"compute") == 0) {
4874     if ((idx >=0) && (idx < lmp->modify->ncompute)) {
4875       strncpy(buffer, lmp->modify->compute[idx]->id, buf_size);
4876       return 1;
4877     }
4878   } else if (strcmp(category,"dump") == 0) {
4879     if ((idx >=0) && (idx < lmp->output->ndump)) {
4880       strncpy(buffer, lmp->output->dump[idx]->id, buf_size);
4881       return 1;
4882     }
4883   } else if (strcmp(category,"fix") == 0) {
4884     if ((idx >=0) && (idx < lmp->modify->nfix)) {
4885       strncpy(buffer, lmp->modify->fix[idx]->id, buf_size);
4886       return 1;
4887     }
4888   } else if (strcmp(category,"group") == 0) {
4889     if ((idx >=0) && (idx < lmp->group->ngroup)) {
4890       strncpy(buffer, lmp->group->names[idx], buf_size);
4891       return 1;
4892     }
4893   } else if (strcmp(category,"molecule") == 0) {
4894     if ((idx >=0) && (idx < lmp->atom->nmolecule)) {
4895       strncpy(buffer, lmp->atom->molecules[idx]->id, buf_size);
4896       return 1;
4897     }
4898   } else if (strcmp(category,"region") == 0) {
4899     if ((idx >=0) && (idx < lmp->domain->nregion)) {
4900       strncpy(buffer, lmp->domain->regions[idx]->id, buf_size);
4901       return 1;
4902     }
4903   } else if (strcmp(category,"variable") == 0) {
4904     if ((idx >=0) && (idx < lmp->input->variable->nvar)) {
4905       strncpy(buffer, lmp->input->variable->names[idx], buf_size);
4906       return 1;
4907     }
4908   }
4909   buffer[0] = '\0';
4910   return 0;
4911 }
4912 
4913 /* ---------------------------------------------------------------------- */
4914 
4915 /** Count the number of loaded plugins
4916  *
4917 \verbatim embed:rst
4918 This function counts how many plugins are currently loaded.
4919 
4920 .. versionadded:: 10Mar2021
4921 
4922 \endverbatim
4923  *
4924  * \return number of loaded plugins
4925  */
lammps_plugin_count()4926 int lammps_plugin_count()
4927 {
4928 #if defined(LMP_PLUGIN)
4929   return plugin_get_num_plugins();
4930 #else
4931   return 0;
4932 #endif
4933 }
4934 
4935 /* ---------------------------------------------------------------------- */
4936 
4937 /** Look up the info of a loaded plugin by its index in the list of plugins
4938  *
4939 \verbatim embed:rst
4940 This function copies the name of the *style* plugin with the index
4941 *idx* into the provided C-style string buffer.  The length of the buffer
4942 must be provided as *buf_size* argument.  If the name of the style
4943 exceeds the length of the buffer, it will be truncated accordingly.
4944 If the index is out of range, the function returns 0 and *buffer* is
4945 set to an empty string, otherwise 1.
4946 
4947 .. versionadded:: 10Mar2021
4948 
4949 \endverbatim
4950  *
4951  * \param  idx       index of the plugin in the list all or *style* plugins
4952  * \param  stylebuf  string buffer to copy the style of the plugin to
4953  * \param  namebuf   string buffer to copy the name of the plugin to
4954  * \param  buf_size  size of the provided string buffers
4955  * \return 1 if successful, otherwise 0
4956  */
lammps_plugin_name(int idx,char * stylebuf,char * namebuf,int buf_size)4957 int lammps_plugin_name(int idx, char *stylebuf, char *namebuf, int buf_size)
4958 {
4959 #if defined(LMP_PLUGIN)
4960   stylebuf[0] = namebuf[0] = '\0';
4961 
4962   const lammpsplugin_t *plugin = plugin_get_info(idx);
4963   if (plugin) {
4964     strncpy(stylebuf,plugin->style,buf_size);
4965     strncpy(namebuf,plugin->name,buf_size);
4966     return 1;
4967   }
4968 #endif
4969   return 0;
4970 }
4971 
4972 // ----------------------------------------------------------------------
4973 // utility functions
4974 // ----------------------------------------------------------------------
4975 
4976 /** Encode three integer image flags into a single imageint.
4977  *
4978 \verbatim embed:rst
4979 
4980 The prototype for this function when compiling with ``-DLAMMPS_BIGBIG``
4981 is:
4982 
4983 .. code-block:: c
4984 
4985    int64_t lammps_encode_image_flags(int ix, int iy, int iz);
4986 
4987 This function performs the bit-shift, addition, and bit-wise OR
4988 operations necessary to combine the values of three integers
4989 representing the image flags in x-, y-, and z-direction.  Unless
4990 LAMMPS is compiled with -DLAMMPS_BIGBIG, those integers are
4991 limited 10-bit signed integers [-512, 511].  Otherwise the return
4992 type changes from ``int`` to ``int64_t`` and the valid range for
4993 the individual image flags becomes [-1048576,1048575],
4994 i.e. that of a 21-bit signed integer.  There is no check on whether
4995 the arguments conform to these requirements.
4996 
4997 \endverbatim
4998  *
4999  * \param  ix  image flag value in x
5000  * \param  iy  image flag value in y
5001  * \param  iz  image flag value in z
5002  * \return     encoded image flag integer */
5003 
lammps_encode_image_flags(int ix,int iy,int iz)5004 imageint lammps_encode_image_flags(int ix, int iy, int iz)
5005 {
5006   imageint image = ((imageint) (ix + IMGMAX) & IMGMASK) |
5007     (((imageint) (iy + IMGMAX) & IMGMASK) << IMGBITS) |
5008     (((imageint) (iz + IMGMAX) & IMGMASK) << IMG2BITS);
5009   return image;
5010 }
5011 
5012 /* ---------------------------------------------------------------------- */
5013 
5014 /** Decode a single image flag integer into three regular integers
5015  *
5016 \verbatim embed:rst
5017 
5018 The prototype for this function when compiling with ``-DLAMMPS_BIGBIG``
5019 is:
5020 
5021 .. code-block:: c
5022 
5023    void lammps_decode_image_flags(int64_t image, int *flags);
5024 
5025 This function does the reverse operation of
5026 :cpp:func:`lammps_encode_image_flags` and takes an image flag integer
5027 does the bit-shift and bit-masking operations to decode it and stores
5028 the resulting three regular integers into the buffer pointed to by
5029 *flags*.
5030 
5031 \endverbatim
5032  *
5033  * \param  image  encoded image flag integer
5034  * \param  flags  pointer to storage where the decoded image flags are stored. */
5035 
lammps_decode_image_flags(imageint image,int * flags)5036 void lammps_decode_image_flags(imageint image, int *flags)
5037 {
5038   flags[0] = (image & IMGMASK) - IMGMAX;
5039   flags[1] = (image >> IMGBITS & IMGMASK) - IMGMAX;
5040   flags[2] = (image >> IMG2BITS) - IMGMAX;
5041 }
5042 
5043 /* ---------------------------------------------------------------------- */
5044 
5045 /** Set up the callback function for a fix external instance with the given ID.
5046 
5047 \verbatim embed:rst
5048 
5049 Fix :doc:`external <fix_external>` allows programs that are running LAMMPS through
5050 its library interface to modify certain LAMMPS properties on specific
5051 timesteps, similar to the way other fixes do.
5052 
5053 This function sets the callback function for use with the "pf/callback"
5054 mode. The function has to have C language bindings with the prototype:
5055 
5056 .. code-block:: c
5057 
5058    void func(void *ptr, bigint timestep, int nlocal, tagint *ids, double **x, double **fexternal);
5059 
5060 The argument *ptr* to this function will be stored in fix external and
5061 the passed as the first argument calling the callback function `func()`.
5062 This would usually be a pointer to the active LAMMPS instance, i.e. the same
5063 pointer as the *handle* argument.  This would be needed to call
5064 functions that set the global or per-atom energy or virial contributions
5065 from within the callback function.
5066 
5067 The callback mechanism is one of the two modes of how forces and can be
5068 applied to a simulation with the help of fix external. The alternative
5069 is the array mode where you call :cpp:func:`lammps_fix_external_get_force`.
5070 
5071 Please see the documentation for :doc:`fix external <fix_external>` for
5072 more information about how to use the fix and how to couple it with an
5073 external code.
5074 
5075 .. versionchanged:: 28Jul2021
5076 
5077 \endverbatim
5078  *
5079  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5080  * \param  id       fix ID of fix external instance
5081  * \param  funcptr  pointer to callback function
5082  * \param  ptr      pointer to object in calling code, passed to callback function as first argument */
5083 
lammps_set_fix_external_callback(void * handle,const char * id,FixExternalFnPtr funcptr,void * ptr)5084 void lammps_set_fix_external_callback(void *handle, const char *id, FixExternalFnPtr funcptr, void *ptr)
5085 {
5086   LAMMPS *lmp = (LAMMPS *) handle;
5087   FixExternal::FnPtr callback = (FixExternal::FnPtr) funcptr;
5088 
5089   BEGIN_CAPTURE
5090   {
5091     int ifix = lmp->modify->find_fix(id);
5092     if (ifix < 0)
5093       lmp->error->all(FLERR,"Cannot find fix with ID '{}'!", id);
5094 
5095     Fix *fix = lmp->modify->fix[ifix];
5096 
5097     if (strcmp("external",fix->style) != 0)
5098       lmp->error->all(FLERR,"Fix '{}' is not of style 'external'", id);
5099 
5100     FixExternal *fext = (FixExternal *) fix;
5101     fext->set_callback(callback, ptr);
5102   }
5103   END_CAPTURE
5104 }
5105 
5106 /** Get pointer to the force array storage in a fix external instance with the given ID.
5107 
5108 \verbatim embed:rst
5109 
5110 Fix :doc:`external <fix_external>` allows programs that are running LAMMPS through
5111 its library interface to add or modify certain LAMMPS properties on specific
5112 timesteps, similar to the way other fixes do.
5113 
5114 This function provides access to the per-atom force storage in a fix
5115 external instance with the given fix-ID to be added to the individual
5116 atoms when using the "pf/array" mode.  The *fexternal* array can be
5117 accessed like other "native" per-atom arrays accessible via the
5118 :cpp:func:`lammps_extract_atom` function.  Please note that the array
5119 stores holds the forces for *local* atoms for each MPI ranks, in the
5120 order determined by the neighbor list build.  Because the underlying
5121 data structures can change as well as the order of atom as they migrate
5122 between MPI processes because of the domain decomposition
5123 parallelization, this function should be always called immediately
5124 before the forces are going to be set to get an up-to-date pointer.
5125  You can use e.g. :cpp:func:`lammps_get_natoms` to obtain the number
5126 of local atoms `nlocal` and then assume the dimensions of the returned
5127 force array as ``double force[nlocal][3]``.
5128 
5129 This is an alternative to the callback mechanism in fix external set up by
5130 :cpp:func:`lammps_set_fix_external_callback`. The main difference is
5131 that this mechanism can be used when forces are be pre-computed and the
5132 control alternates between LAMMPS and the external code, while the
5133 callback mechanism can call the external code to compute the force when
5134 the fix is triggered and needs them.
5135 
5136 Please see the documentation for :doc:`fix external <fix_external>` for
5137 more information about how to use the fix and how to couple it with an
5138 external code.
5139 
5140 .. versionadded:: 28Jul2021
5141 
5142 \endverbatim
5143  *
5144  * \param  handle     pointer to a previously created LAMMPS instance cast to ``void *``.
5145  * \param  id         fix ID of fix external instance
5146  * \return            a pointer to the per-atom force array allocated by the fix */
5147 
lammps_fix_external_get_force(void * handle,const char * id)5148 double **lammps_fix_external_get_force(void *handle, const char *id)
5149 {
5150   LAMMPS *lmp = (LAMMPS *) handle;
5151   double **fexternal = nullptr;
5152 
5153   BEGIN_CAPTURE
5154   {
5155     int ifix = lmp->modify->find_fix(id);
5156     if (ifix < 0)
5157       lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id);
5158 
5159     Fix *fix = lmp->modify->fix[ifix];
5160 
5161     if (strcmp("external",fix->style) != 0)
5162       lmp->error->all(FLERR,"Fix '{}' is not of style external!", id);
5163 
5164     fexternal = (double **)fix->extract("fexternal",ifix);
5165   }
5166   END_CAPTURE
5167   return fexternal;
5168 }
5169 
5170 /** Set the global energy contribution for a fix external instance with the given ID.
5171 
5172 \verbatim embed:rst
5173 
5174 This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and
5175 :cpp:func:`lammps_fix_external_get_force` to also set the contribution
5176 to the global energy from the external code.  The value of the *eng*
5177 argument will be stored in the fix and applied on the current and all
5178 following timesteps until changed by another call to this function.
5179 The energy is in energy units as determined by the current :doc:`units <units>`
5180 settings and is the **total** energy of the contribution.  Thus when
5181 running in parallel all MPI processes have to call this function with
5182 the **same** value and this will be returned as scalar property of the
5183 fix external instance when accessed in LAMMPS input commands or from
5184 variables.
5185 
5186 Please see the documentation for :doc:`fix external <fix_external>` for
5187 more information about how to use the fix and how to couple it with an
5188 external code.
5189 
5190 .. versionadded:: 28Jul2021
5191 
5192 \endverbatim
5193  *
5194  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5195  * \param  id       fix ID of fix external instance
5196  * \param  eng      total energy to be added to the global energy */
5197 
lammps_fix_external_set_energy_global(void * handle,const char * id,double eng)5198 void lammps_fix_external_set_energy_global(void *handle, const char *id, double eng)
5199 {
5200   LAMMPS *lmp = (LAMMPS *) handle;
5201 
5202   BEGIN_CAPTURE
5203   {
5204     int ifix = lmp->modify->find_fix(id);
5205     if (ifix < 0)
5206       lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id);
5207 
5208     Fix *fix = lmp->modify->fix[ifix];
5209 
5210     if (strcmp("external",fix->style) != 0)
5211       lmp->error->all(FLERR,"Fix '{}' is not of style external!", id);
5212 
5213     FixExternal *fext = (FixExternal*) fix;
5214     fext->set_energy_global(eng);
5215   }
5216   END_CAPTURE
5217 }
5218 
5219 /** Set the global virial contribution for a fix external instance with the given ID.
5220 
5221 \verbatim embed:rst
5222 
5223 This is a companion function to :cpp:func:`lammps_set_fix_external_callback`
5224 and :cpp:func:`lammps_fix_external_get_force` to set the contribution to
5225 the global virial from the external code.
5226 
5227 The 6 values of the *virial* array will be stored in the fix and applied
5228 on the current and all following timesteps until changed by another call
5229 to this function. The components of the virial need to be stored in the
5230 order: *xx*, *yy*, *zz*, *xy*, *xz*, *yz*.  In LAMMPS the virial is
5231 stored internally as `stress*volume` in units of `pressure*volume` as
5232 determined by the current :doc:`units <units>` settings and is the
5233 **total** contribution.  Thus when running in parallel all MPI processes
5234 have to call this function with the **same** value and this will then
5235 be added by fix external.
5236 
5237 Please see the documentation for :doc:`fix external <fix_external>` for
5238 more information about how to use the fix and how to couple it with an
5239 external code.
5240 
5241 .. versionadded:: 28Jul2021
5242 
5243 \endverbatim
5244  *
5245  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5246  * \param  id       fix ID of fix external instance
5247  * \param  virial   the 6 global stress tensor components to be added to the global virial */
5248 
lammps_fix_external_set_virial_global(void * handle,const char * id,double * virial)5249 void lammps_fix_external_set_virial_global(void *handle, const char *id, double *virial)
5250 {
5251   LAMMPS *lmp = (LAMMPS *) handle;
5252 
5253   BEGIN_CAPTURE
5254   {
5255     int ifix = lmp->modify->find_fix(id);
5256     if (ifix < 0)
5257       lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id);
5258 
5259     Fix *fix = lmp->modify->fix[ifix];
5260 
5261     if (strcmp("external",fix->style) != 0)
5262       lmp->error->all(FLERR,"Fix '{}' is not of style external!", id);
5263 
5264     FixExternal * fext = (FixExternal*) fix;
5265     fext->set_virial_global(virial);
5266   }
5267   END_CAPTURE
5268 }
5269 
5270 /** Set the per-atom energy contribution for a fix external instance with the given ID.
5271 
5272 \verbatim embed:rst
5273 
5274 This is a companion function to :cpp:func:`lammps_set_fix_external_callback`
5275 to set the per-atom energy contribution due to the fix from the external code
5276 as part of the callback function.  For this to work, the handle to the
5277 LAMMPS object must be passed as the *ptr* argument when registering the
5278 callback function.
5279 
5280 .. note::
5281 
5282    This function is fully independent from :cpp:func:`lammps_fix_external_set_energy_global`
5283    and will **NOT** add any contributions to the global energy tally
5284    and **NOT** check whether the sum of the contributions added here are
5285    consistent with the global added energy.
5286 
5287 
5288 Please see the documentation for :doc:`fix external <fix_external>` for
5289 more information about how to use the fix and how to couple it with an
5290 external code.
5291 
5292 .. versionadded:: 28Jul2021
5293 
5294 \endverbatim
5295  *
5296  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5297  * \param  id       fix ID of fix external instance
5298  * \param  eng      pointer to array of length nlocal with the energy to be added to the per-atom energy */
5299 
lammps_fix_external_set_energy_peratom(void * handle,const char * id,double * eng)5300 void lammps_fix_external_set_energy_peratom(void *handle, const char *id, double *eng)
5301 {
5302   LAMMPS *lmp = (LAMMPS *) handle;
5303 
5304   BEGIN_CAPTURE
5305   {
5306     int ifix = lmp->modify->find_fix(id);
5307     if (ifix < 0)
5308       lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id);
5309 
5310     Fix *fix = lmp->modify->fix[ifix];
5311 
5312     if (strcmp("external",fix->style) != 0)
5313       lmp->error->all(FLERR,"Fix '{}' is not of style external!", id);
5314 
5315     FixExternal *fext = (FixExternal*) fix;
5316     fext->set_energy_peratom(eng);
5317   }
5318   END_CAPTURE
5319 }
5320 
5321 /** Set the per-atom virial contribution for a fix external instance with the given ID.
5322 
5323 \verbatim embed:rst
5324 
5325 This is a companion function to :cpp:func:`lammps_set_fix_external_callback`
5326 to set the per-atom virial contribution due to the fix from the external code
5327 as part of the callback function.  For this to work, the handle to the
5328 LAMMPS object must be passed as the *ptr* argument when registering the
5329 callback function.
5330 
5331 .. note::
5332 
5333    This function is fully independent from :cpp:func:`lammps_fix_external_set_virial_global`
5334    and will **NOT** add any contributions to the global virial tally
5335    and **NOT** check whether the sum of the contributions added here are
5336    consistent with the global added virial.
5337 
5338 The order and units of the per-atom stress tensor elements are the same
5339 as for the global virial.  The code in fix external assumes the
5340 dimensions of the per-atom virial array is ``double virial[nlocal][6]``.
5341 
5342 Please see the documentation for :doc:`fix external <fix_external>` for
5343 more information about how to use the fix and how to couple it with an
5344 external code.
5345 
5346 .. versionadded:: 28Jul2021
5347 
5348 \endverbatim
5349  *
5350  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5351  * \param  id       fix ID of fix external instance
5352  * \param  virial   a list of nlocal entries with the 6 per-atom stress tensor components to be added to the per-atom virial */
5353 
lammps_fix_external_set_virial_peratom(void * handle,const char * id,double ** virial)5354 void lammps_fix_external_set_virial_peratom(void *handle, const char *id, double **virial)
5355 {
5356   LAMMPS *lmp = (LAMMPS *) handle;
5357 
5358   BEGIN_CAPTURE
5359   {
5360     int ifix = lmp->modify->find_fix(id);
5361     if (ifix < 0)
5362       lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id);
5363 
5364     Fix *fix = lmp->modify->fix[ifix];
5365 
5366     if (strcmp("external",fix->style) != 0)
5367       lmp->error->all(FLERR,"Fix '{}' is not of style external!", id);
5368 
5369     FixExternal * fext = (FixExternal*) fix;
5370     fext->set_virial_peratom(virial);
5371   }
5372   END_CAPTURE
5373 }
5374 
5375 /** Set the vector length for a global vector stored with fix external for analysis
5376 
5377 \verbatim embed:rst
5378 
5379 This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and
5380 :cpp:func:`lammps_fix_external_get_force` to set the length of a global vector of
5381 properties that will be stored with the fix via
5382 :cpp:func:`lammps_fix_external_set_vector`.
5383 
5384 This function needs to be called **before** a call to
5385 :cpp:func:`lammps_fix_external_set_vector` and **before** a run or minimize
5386 command. When running in parallel it must be called from **all** MPI
5387 processes and with the same length parameter.
5388 
5389 Please see the documentation for :doc:`fix external <fix_external>` for
5390 more information about how to use the fix and how to couple it with an
5391 external code.
5392 
5393 .. versionadded:: 28Jul2021
5394 
5395 \endverbatim
5396  *
5397  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5398  * \param  id       fix ID of fix external instance
5399  * \param  len      length of the global vector to be stored with the fix */
5400 
lammps_fix_external_set_vector_length(void * handle,const char * id,int len)5401 void lammps_fix_external_set_vector_length(void *handle, const char *id, int len)
5402 {
5403   LAMMPS *lmp = (LAMMPS *) handle;
5404 
5405   BEGIN_CAPTURE
5406   {
5407     int ifix = lmp->modify->find_fix(id);
5408     if (ifix < 0)
5409       lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id);
5410 
5411     Fix *fix = lmp->modify->fix[ifix];
5412 
5413     if (strcmp("external",fix->style) != 0)
5414       lmp->error->all(FLERR,"Fix '{}' is not of style external!", id);
5415 
5416     FixExternal *fext = (FixExternal*) fix;
5417     fext->set_vector_length(len);
5418   }
5419   END_CAPTURE
5420 }
5421 
5422 /** Store a global vector value for a fix external instance with the given ID.
5423 
5424 \verbatim embed:rst
5425 
5426 This is a companion function to :cpp:func:`lammps_set_fix_external_callback` and
5427 :cpp:func:`lammps_fix_external_get_force` to set the values of a global vector of
5428 properties that will be stored with the fix.  And can be accessed from
5429 within LAMMPS input commands (e.g. fix ave/time or variables) when used
5430 in a vector context.
5431 
5432 This function needs to be called **after** a call to
5433 :cpp:func:`lammps_fix_external_set_vector_length` and the  and **before** a run or minimize
5434 command.  When running in parallel it must be called from **all** MPI
5435 processes and with the **same** index and value parameters.  The value
5436 is assumed to be extensive.
5437 
5438 .. note::
5439 
5440    The index in the *idx* parameter is 1-based, i.e. the first element
5441    is set with idx = 1 and the last element of the vector with idx = N,
5442    where N is the value of the *len* parameter of the call to
5443    :cpp:func:`lammps_fix_external_set_vector_length`.
5444 
5445 Please see the documentation for :doc:`fix external <fix_external>` for
5446 more information about how to use the fix and how to couple it with an
5447 external code.
5448 
5449 .. versionadded:: 28Jul2021
5450 
5451 \endverbatim
5452  *
5453  * \param  handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5454  * \param  id       fix ID of fix external instance
5455  * \param  idx      1-based index of in global vector
5456  * \param  val      value to be stored in global vector */
5457 
lammps_fix_external_set_vector(void * handle,const char * id,int idx,double val)5458 void lammps_fix_external_set_vector(void *handle, const char *id, int idx, double val)
5459 {
5460   LAMMPS *lmp = (LAMMPS *) handle;
5461 
5462   BEGIN_CAPTURE
5463   {
5464     int ifix = lmp->modify->find_fix(id);
5465     if (ifix < 0)
5466       lmp->error->all(FLERR,"Can not find fix with ID '{}'!", id);
5467 
5468     Fix *fix = lmp->modify->fix[ifix];
5469 
5470     if (strcmp("external",fix->style) != 0)
5471       lmp->error->all(FLERR,"Fix '{}' is not of style external!", id);
5472 
5473     FixExternal * fext = (FixExternal*) fix;
5474     fext->set_vector(idx, val);
5475   }
5476   END_CAPTURE
5477 }
5478 
5479 /* ---------------------------------------------------------------------- */
5480 
5481 /** Free memory buffer allocated by LAMMPS.
5482  *
5483 \verbatim embed:rst
5484 
5485 Some of the LAMMPS C library interface functions return data as pointer
5486 to a buffer that has been allocated by LAMMPS or the library interface.
5487 This function can be used to delete those in order to avoid memory
5488 leaks.
5489 
5490 \endverbatim
5491  *
5492  * \param  ptr  pointer to data allocated by LAMMPS */
5493 
lammps_free(void * ptr)5494 void lammps_free(void *ptr)
5495 {
5496   free(ptr);
5497 }
5498 
5499 /* ---------------------------------------------------------------------- */
5500 
5501 /** Check if LAMMPS is currently inside a run or minimization
5502  *
5503  * This function can be used from signal handlers or multi-threaded
5504  * applications to determine if the LAMMPS instance is currently active.
5505  *
5506  * \param  handle pointer to a previously created LAMMPS instance cast to ``void *``.
5507  * \return        0 if idle or >0 if active */
5508 
lammps_is_running(void * handle)5509 int lammps_is_running(void *handle)
5510 {
5511   LAMMPS *  lmp = (LAMMPS *) handle;
5512   return lmp->update->whichflag;
5513 }
5514 
5515 /** Force a timeout to cleanly stop an ongoing run
5516  *
5517  * This function can be used from signal handlers or multi-threaded
5518  * applications to cleanly terminate an ongoing run.
5519  *
5520  * \param  handle pointer to a previously created LAMMPS instance cast to ``void *`` */
5521 
lammps_force_timeout(void * handle)5522 void lammps_force_timeout(void *handle)
5523 {
5524   LAMMPS *  lmp = (LAMMPS *) handle;
5525   return lmp->timer->force_timeout();
5526 }
5527 
5528 // ----------------------------------------------------------------------
5529 // Library functions for error handling with exceptions enabled
5530 // ----------------------------------------------------------------------
5531 
5532 /** Check if there is a (new) error message available
5533 
5534 \verbatim embed:rst
5535 This function can be used to query if an error inside of LAMMPS
5536 has thrown a :ref:`C++ exception <exceptions>`.
5537 
5538 .. note::
5539 
5540    This function will always report "no error" when the LAMMPS library
5541    has been compiled without ``-DLAMMPS_EXCEPTIONS`` which turns fatal
5542    errors aborting LAMMPS into a C++ exceptions. You can use the library
5543    function :cpp:func:`lammps_config_has_exceptions` to check if this is
5544    the case.
5545 \endverbatim
5546  *
5547  * \param handle   pointer to a previously created LAMMPS instance cast to ``void *``.
5548  * \return 0 on no error, 1 on error.
5549  */
lammps_has_error(void * handle)5550 int lammps_has_error(void *handle) {
5551 #ifdef LAMMPS_EXCEPTIONS
5552   LAMMPS *  lmp = (LAMMPS *) handle;
5553   Error * error = lmp->error;
5554   return (error->get_last_error().empty()) ? 0 : 1;
5555 #else
5556   return 0;
5557 #endif
5558 }
5559 
5560 /* ---------------------------------------------------------------------- */
5561 
5562 /** Copy the last error message into the provided buffer
5563 
5564 \verbatim embed:rst
5565 This function can be used to retrieve the error message that was set
5566 in the event of an error inside of LAMMPS which resulted in a
5567 :ref:`C++ exception <exceptions>`.  A suitable buffer for a C-style
5568 string has to be provided and its length.  If the internally stored
5569 error message is longer, it will be truncated accordingly.  The return
5570 value of the function corresponds to the kind of error: a "1" indicates
5571 an error that occurred on all MPI ranks and is often recoverable, while
5572 a "2" indicates an abort that would happen only in a single MPI rank
5573 and thus may not be recoverable as other MPI ranks may be waiting on
5574 the failing MPI ranks to send messages.
5575 
5576 .. note::
5577 
5578    This function will do nothing when the LAMMPS library has been
5579    compiled without ``-DLAMMPS_EXCEPTIONS`` which turns errors aborting
5580    LAMMPS into a C++ exceptions.  You can use the library function
5581    :cpp:func:`lammps_config_has_exceptions` to check if this is the case.
5582 \endverbatim
5583  *
5584  * \param  handle    pointer to a previously created LAMMPS instance cast to ``void *``.
5585  * \param  buffer    string buffer to copy the error message to
5586  * \param  buf_size  size of the provided string buffer
5587  * \return           1 when all ranks had the error, 2 on a single rank error. */
5588 
lammps_get_last_error_message(void * handle,char * buffer,int buf_size)5589 int lammps_get_last_error_message(void *handle, char *buffer, int buf_size) {
5590 #ifdef LAMMPS_EXCEPTIONS
5591   LAMMPS *lmp = (LAMMPS *) handle;
5592   Error *error = lmp->error;
5593   buffer[0] = buffer[buf_size-1] = '\0';
5594 
5595   if (!error->get_last_error().empty()) {
5596     int error_type = error->get_last_error_type();
5597     strncpy(buffer, error->get_last_error().c_str(), buf_size-1);
5598     error->set_last_error("", ERROR_NONE);
5599     return error_type;
5600   }
5601 #endif
5602   return 0;
5603 }
5604 
5605 // Local Variables:
5606 // fill-column: 72
5607 // End:
5608