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