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 /* ----------------------------------------------------------------------
16    Contributing authors:  Axel Kohlmeyer (Temple U),
17                           Richard Berger (Temple U)
18 ------------------------------------------------------------------------- */
19 
20 #include "info.h"
21 
22 #include "accelerator_kokkos.h"
23 #include "angle.h"
24 #include "atom.h"
25 #include "bond.h"
26 #include "comm.h"
27 #include "compute.h"
28 #include "dihedral.h"
29 #include "domain.h"
30 #include "dump.h"
31 #include "error.h"
32 #include "fix.h"
33 #include "force.h"
34 #include "group.h"
35 #include "improper.h"
36 #include "input.h"
37 #include "modify.h"
38 #include "neighbor.h"
39 #include "output.h"
40 #include "pair.h"
41 #include "pair_hybrid.h"
42 #include "region.h"
43 #include "text_file_reader.h"
44 #include "update.h"
45 #include "variable.h"
46 #include "fmt/chrono.h"
47 
48 #include <cctype>
49 #include <cmath>
50 #include <cstring>
51 #include <ctime>
52 #include <exception>
53 #include <map>
54 
55 #ifdef _WIN32
56 #ifndef WIN32_LEAN_AND_MEAN
57 #define WIN32_LEAN_AND_MEAN
58 #endif
59 #define PSAPI_VERSION 1
60 #include <windows.h>
61 #include <cstdint>
62 #include <psapi.h>
63 #else
64 #include <sys/resource.h>
65 #include <sys/utsname.h>
66 #endif
67 
68 #if defined(__linux__)
69 #include <malloc.h>
70 #endif
71 
72 namespace LAMMPS_NS {
73 
74 enum {COMPUTES=1<<0,
75       DUMPS=1<<1,
76       FIXES=1<<2,
77       GROUPS=1<<3,
78       REGIONS=1<<4,
79       CONFIG=1<<5,
80       TIME=1<<6,
81       MEMORY=1<<7,
82       VARIABLES=1<<8,
83       SYSTEM=1<<9,
84       COMM=1<<10,
85       COEFFS=1<<11,
86       ATOM_STYLES=1<<12,
87       INTEGRATE_STYLES=1<<13,
88       MINIMIZE_STYLES=1<<14,
89       PAIR_STYLES=1<<15,
90       BOND_STYLES=1<<16,
91       ANGLE_STYLES=1<<17,
92       DIHEDRAL_STYLES=1<<18,
93       IMPROPER_STYLES=1<<19,
94       KSPACE_STYLES=1<<20,
95       FIX_STYLES=1<<21,
96       COMPUTE_STYLES=1<<22,
97       REGION_STYLES=1<<23,
98       DUMP_STYLES=1<<24,
99       COMMAND_STYLES=1<<25,
100       ACCELERATOR=1<<26,
101       ALL=~0};
102 
103 static const int STYLES = ATOM_STYLES | INTEGRATE_STYLES | MINIMIZE_STYLES
104                         | PAIR_STYLES | BOND_STYLES | ANGLE_STYLES
105                         | DIHEDRAL_STYLES | IMPROPER_STYLES | KSPACE_STYLES
106                         | FIX_STYLES | COMPUTE_STYLES | REGION_STYLES
107                         | DUMP_STYLES | COMMAND_STYLES;
108 }
109 
110 using namespace LAMMPS_NS;
111 
112 // must match enumerator in variable.h
113 static const char *varstyles[] = {
114   "index", "loop", "world", "universe", "uloop", "string", "getenv",
115   "file", "atomfile", "format", "equal", "atom", "vector", "python",
116   "internal", "(unknown)"};
117 
118 static const char *mapstyles[] = { "none", "array", "hash", "yes" };
119 
120 static const char *commstyles[] = { "brick", "tiled" };
121 static const char *commlayout[] = { "uniform", "nonuniform", "irregular" };
122 
123 static const char bstyles[] = "pfsm";
124 
125 template<typename ValueType>
126 static void print_columns(FILE *fp, std::map<std::string, ValueType> *styles);
127 
128 template<typename ValueType>
129 static bool find_style(const LAMMPS *lmp, std::map<std::string, ValueType> *styles,
130                        const std::string &name, bool suffix_check);
131 
132 template<typename ValueType>
133 static std::vector<std::string> get_style_names(std::map<std::string, ValueType> *styles);
134 
135 /* ---------------------------------------------------------------------- */
136 
command(int narg,char ** arg)137 void Info::command(int narg, char **arg)
138 {
139   FILE *out=screen;
140   int flags=0;
141 
142   if (comm->me != 0) return;
143 
144   // parse arguments
145   int idx = 0;
146 
147   while (idx < narg) {
148     if (strncmp(arg[idx],"all",3) == 0) {
149       flags |= ALL;
150       ++idx;
151     } else if ((idx+1 < narg) && (strncmp(arg[idx],"out",3) == 0)
152                && (strncmp(arg[idx+1],"screen",3) == 0)) {
153       if ((out != screen) && (out != logfile)) fclose(out);
154       out = screen;
155       idx += 2;
156     } else if ((idx+1 < narg) && (strncmp(arg[idx],"out",3) == 0)
157                && (strncmp(arg[idx+1],"log",3) == 0)) {
158       if ((out != screen) && (out != logfile)) fclose(out);
159       out = logfile;
160       idx += 2;
161     } else if ((idx+2 < narg) && (strncmp(arg[idx],"out",3) == 0)
162                && (strncmp(arg[idx+1],"append",3) == 0)) {
163       if ((out != screen) && (out != logfile)) fclose(out);
164       out = fopen(arg[idx+2],"a");
165       idx += 3;
166     } else if ((idx+2 < narg) && (strncmp(arg[idx],"out",3) == 0)
167                && (strncmp(arg[idx+1],"overwrite",3) == 0)) {
168       if ((out != screen) && (out != logfile)) fclose(out);
169       out = fopen(arg[idx+2],"w");
170       idx += 3;
171     } else if (strncmp(arg[idx],"communication",5) == 0) {
172       flags |= COMM;
173       ++idx;
174     } else if (strncmp(arg[idx],"computes",5) == 0) {
175       flags |= COMPUTES;
176       ++idx;
177     } else if (strncmp(arg[idx],"dumps",5) == 0) {
178       flags |= DUMPS;
179       ++idx;
180     } else if (strncmp(arg[idx],"fixes",5) == 0) {
181       flags |= FIXES;
182       ++idx;
183     } else if (strncmp(arg[idx],"groups",3) == 0) {
184       flags |= GROUPS;
185       ++idx;
186     } else if (strncmp(arg[idx],"regions",3) == 0) {
187       flags |= REGIONS;
188       ++idx;
189     } else if (strncmp(arg[idx],"config",3) == 0) {
190       flags |= CONFIG;
191       ++idx;
192     } else if (strncmp(arg[idx],"time",3) == 0) {
193       flags |= TIME;
194       ++idx;
195     } else if (strncmp(arg[idx],"memory",3) == 0) {
196       flags |= MEMORY;
197       ++idx;
198     } else if (strncmp(arg[idx],"variables",3) == 0) {
199       flags |= VARIABLES;
200       ++idx;
201     } else if (strncmp(arg[idx],"system",3) == 0) {
202       flags |= SYSTEM;
203       ++idx;
204     } else if (strncmp(arg[idx],"coeffs",3) == 0) {
205       flags |= COEFFS;
206       ++idx;
207     } else if (strncmp(arg[idx],"accelerator",3) == 0) {
208       flags |= ACCELERATOR;
209       ++idx;
210     } else if (strncmp(arg[idx],"styles",3) == 0) {
211       if (idx+1 < narg) {
212         ++idx;
213         if (strncmp(arg[idx],"all",3) == 0) {
214           flags |= STYLES;
215           ++idx;
216         } else if (strncmp(arg[idx],"atom",3) == 0) {
217           flags |= ATOM_STYLES;
218           ++idx;
219         } else if (strncmp(arg[idx],"integrate",3) == 0) {
220           flags |= INTEGRATE_STYLES;
221           ++idx;
222         } else if (strncmp(arg[idx],"minimize",3) == 0) {
223           flags |= MINIMIZE_STYLES;
224           ++idx;
225         } else if (strncmp(arg[idx],"pair",3) == 0) {
226           flags |= PAIR_STYLES;
227           ++idx;
228         } else if (strncmp(arg[idx],"bond",3) == 0) {
229           flags |= BOND_STYLES;
230           ++idx;
231         } else if (strncmp(arg[idx],"angle",3) == 0) {
232           flags |= ANGLE_STYLES;
233           ++idx;
234         } else if (strncmp(arg[idx],"dihedral",3) == 0) {
235           flags |= DIHEDRAL_STYLES;
236           ++idx;
237         } else if (strncmp(arg[idx],"improper",3) == 0) {
238           flags |= IMPROPER_STYLES;
239           ++idx;
240         } else if (strncmp(arg[idx],"kspace",3) == 0) {
241           flags |= KSPACE_STYLES;
242           ++idx;
243         } else if (strncmp(arg[idx],"fix",3) == 0) {
244           flags |= FIX_STYLES;
245           ++idx;
246         } else if (strncmp(arg[idx],"compute",4) == 0) {
247           flags |= COMPUTE_STYLES;
248           ++idx;
249         } else if (strncmp(arg[idx],"region",3) == 0) {
250           flags |= REGION_STYLES;
251           ++idx;
252         } else if (strncmp(arg[idx],"dump",3) == 0) {
253           flags |= DUMP_STYLES;
254           ++idx;
255         } else if (strncmp(arg[idx],"command",4) == 0) {
256           flags |= COMMAND_STYLES;
257           ++idx;
258         } else {
259           flags |= STYLES;
260         }
261       } else {
262         flags |= STYLES;
263         ++idx;
264       }
265     } else {
266       error->warning(FLERR,"Ignoring unknown or incorrect info command flag");
267       ++idx;
268     }
269   }
270 
271   if (out == nullptr) return;
272 
273   fputs("\nInfo-Info-Info-Info-Info-Info-Info-Info-Info-Info-Info\n",out);
274   std::time_t now = std::time(nullptr);
275   fmt::print(out,"Printed on {:%a %b %d %H:%M:%S %Y}\n", fmt::localtime(now));
276 
277   if (flags & CONFIG) {
278     fmt::print(out,"\nLAMMPS version: {} / {}\n",
279                lmp->version, lmp->num_ver);
280 
281     if (lmp->has_git_info)
282       fmt::print(out,"Git info: {} / {} / {}\n",
283                  lmp->git_branch, lmp->git_descriptor,lmp->git_commit);
284 
285     fmt::print(out,"\nOS information: {}\n\n",get_os_info());
286 
287     fmt::print(out,"sizeof(smallint): {}-bit\n"
288                "sizeof(imageint): {}-bit\n"
289                "sizeof(tagint):   {}-bit\n"
290                "sizeof(bigint):   {}-bit\n",
291                sizeof(smallint)*8, sizeof(imageint)*8,
292                sizeof(tagint)*8, sizeof(bigint)*8);
293 
294     fmt::print(out,"\nCompiler: {} with {}\nC++ standard: {}\n",
295                get_compiler_info(),get_openmp_info(),get_cxx_info());
296 
297     fputs("\nActive compile time flags:\n\n",out);
298     if (has_gzip_support()) fputs("-DLAMMPS_GZIP\n",out);
299     if (has_png_support()) fputs("-DLAMMPS_PNG\n",out);
300     if (has_jpeg_support()) fputs("-DLAMMPS_JPEG\n",out);
301     if (has_ffmpeg_support()) fputs("-DLAMMPS_FFMPEG\n",out);
302     if (has_exceptions()) fputs("-DLAMMPS_EXCEPTIONS\n",out);
303 
304 #if defined(LAMMPS_BIGBIG)
305     fputs("-DLAMMPS_BIGBIG\n",out);
306 #elif defined(LAMMPS_SMALLBIG)
307     fputs("-DLAMMPS_SMALLBIG\n",out);
308 #else // defined(LAMMPS_SMALLSMALL)
309     fputs("-DLAMMPS_SMALLSMALL\n",out);
310 #endif
311 
312     int ncword, ncline = 0;
313     fputs("\nInstalled packages:\n\n",out);
314     for (const char **pkg = lmp->installed_packages; *pkg != nullptr; ++pkg) {
315       ncword = strlen(*pkg);
316       if (ncline + ncword > 78) {
317         ncline = 0;
318         fputs("\n",out);
319       }
320       fmt::print(out,"{} ",*pkg);
321       ncline += ncword + 1;
322     }
323     fputs("\n",out);
324   }
325 
326   if (flags & ACCELERATOR) {
327     fmt::print(out,"\nAccelerator configuration:\n\n{}",
328                get_accelerator_info());
329     if (Info::has_gpu_device())
330       fmt::print(out,"\nAvailable GPU devices:\n{}\n",get_gpu_device_info());
331   }
332 
333   if (flags & MEMORY) {
334     double meminfo[3];
335 
336     get_memory_info(meminfo);
337 
338     fputs("\nMemory allocation information (MPI rank 0):\n\n",out);
339     fmt::print(out,"Total dynamically allocated memory: {:.4} Mbyte\n",
340                meminfo[0]);
341 
342 #if defined(_WIN32)
343     fmt::print(out,"Non-shared memory use: {:.4} Mbyte\n",meminfo[1]);
344     fmt::print(out,"Maximum working set size: {:.4} Mbyte\n",meminfo[2]);
345 #else
346 #if defined(__linux__)
347     fmt::print(out,"Current reserved memory pool size: {:.4} Mbyte\n",
348                meminfo[1]);
349 #endif
350     fmt::print(out,"Maximum resident set size: {:.4} Mbyte\n",meminfo[2]);
351 #endif
352   }
353 
354   if (flags & COMM) {
355     int major,minor;
356     std::string version = get_mpi_info(major,minor);
357 
358     fmt::print(out,"\nCommunication information:\n"
359                "MPI library level: MPI v{}.{}\n"
360                "MPI version: {}\n",major,minor,version);
361 
362     fmt::print(out,"Comm style = {},  Comm layout = {}\n"
363                "Communicate velocities for ghost atoms = {}\n",
364                commstyles[comm->style], commlayout[comm->layout],
365                comm->ghost_velocity ? "yes" : "no");
366 
367     if (domain->box_exist) {
368       if (comm->mode == 0)
369         fmt::print(out,"Communication mode = single\n"
370                    "Communication cutoff = {}\n",
371                    comm->get_comm_cutoff());
372 
373       if (comm->mode == 1) {
374         fputs("Communication mode = multi\n",out);
375         double cut;
376         for (int i=0; i < neighbor->ncollections; ++i) {
377           if (comm->cutusermulti) cut = comm->cutusermulti[i];
378           else cut = 0.0;
379           for (int j=0; j < neighbor->ncollections; ++j) {
380             cut = MAX(cut,sqrt(neighbor->cutcollectionsq[i][j]));
381           }
382 
383           if (comm->cutusermulti) cut = MAX(cut,comm->cutusermulti[i]);
384           fmt::print(out,"Communication cutoff for collection {} = {:.8}\n", i, cut);
385         }
386       }
387 
388       if (comm->mode == 2) {
389         fputs("Communication mode = multi/old\n",out);
390         double cut;
391         for (int i=1; i <= atom->ntypes && neighbor->cuttype; ++i) {
392           cut = neighbor->cuttype[i];
393           if (comm->cutusermultiold) cut = MAX(cut,comm->cutusermultiold[i]);
394           fmt::print(out,"Communication cutoff for type {} = {:.8}\n", i, cut);
395         }
396       }
397     }
398     fmt::print(out,"Nprocs = {},   Nthreads = {}\n",comm->nprocs,comm->nthreads);
399     if (domain->box_exist)
400       fmt::print(out,"Processor grid = {} x {} x {}\n",comm->procgrid[0],
401                  comm->procgrid[1], comm->procgrid[2]);
402   }
403 
404   if (flags & SYSTEM) {
405     fputs("\nSystem information:\n",out);
406     fmt::print(out,"Units         = {}\n", update->unit_style);
407     fmt::print(out,"Atom style    = {}\n", atom->atom_style);
408     fmt::print(out,"Atom map      = {}\n", mapstyles[atom->map_style]);
409     if (atom->molecular != Atom::ATOMIC) {
410       const char *msg;
411       msg = (atom->molecular == Atom::TEMPLATE) ? "template" : "standard";
412       fmt::print(out,"Molecule type = {}\n",msg);
413     }
414     fmt::print(out,"Atoms     = {:12},  types = {:8d},  style = {}\n",
415                atom->natoms, atom->ntypes, force->pair_style);
416 
417     if (force->pair && utils::strmatch(force->pair_style,"^hybrid")) {
418       PairHybrid *hybrid = (PairHybrid *)force->pair;
419       fmt::print(out,"Hybrid sub-styles:");
420       for (int i=0; i < hybrid->nstyles; ++i)
421         fmt::print(out," {}", hybrid->keywords[i]);
422       fputc('\n',out);
423     }
424     if (atom->molecular != Atom::ATOMIC) {
425       const char *msg;
426       msg = force->bond_style ? force->bond_style : "none";
427       fmt::print(out,"Bonds     = {:12},  types = {:8},  style = {}\n",
428                  atom->nbonds, atom->nbondtypes, msg);
429 
430       msg = force->angle_style ? force->angle_style : "none";
431       fmt::print(out,"Angles    = {:12},  types = {:8},  style = {}\n",
432                  atom->nangles, atom->nangletypes, msg);
433 
434       msg = force->dihedral_style ? force->dihedral_style : "none";
435       fmt::print(out,"Dihedrals = {:12},  types = {:8},  style = {}\n",
436                  atom->ndihedrals, atom->ndihedraltypes, msg);
437 
438       msg = force->improper_style ? force->improper_style : "none";
439       fmt::print(out,"Impropers = {:12},  types = {:8},  style = {}\n",
440                  atom->nimpropers, atom->nimpropertypes, msg);
441 
442       const double * const special_lj   = force->special_lj;
443       const double * const special_coul = force->special_coul;
444 
445       fmt::print(out,"Special bond factors lj =    {:<8} {:<8} {:<8}\n"
446                  "Special bond factors coul =  {:<8} {:<8} {:<8}\n",
447                  special_lj[1],special_lj[2],special_lj[3],
448                  special_coul[1],special_coul[2],special_coul[3]);
449     }
450 
451     fmt::print(out,"Kspace style = {}\n",
452                force->kspace ? force->kspace_style : "none");
453 
454     if (domain->box_exist) {
455       fmt::print(out,"\nDimensions = {}\n",domain->dimension);
456       fmt::print(out,"{} box = {:.8} x {:.8} x {:.8}\n",
457                  domain->triclinic ? "Triclinic" : "Orthogonal",
458                  domain->xprd, domain->yprd, domain->zprd);
459       fmt::print(out,"Boundaries = {},{} {},{} {},{}\n",
460                  bstyles[domain->boundary[0][0]],bstyles[domain->boundary[0][1]],
461                  bstyles[domain->boundary[1][0]],bstyles[domain->boundary[1][1]],
462                  bstyles[domain->boundary[2][0]],bstyles[domain->boundary[2][1]]);
463       fmt::print(out,"xlo, xhi = {:.8}, {:.8}\n", domain->boxlo[0], domain->boxhi[0]);
464       fmt::print(out,"ylo, yhi = {:.8}, {:.8}\n", domain->boxlo[1], domain->boxhi[1]);
465       fmt::print(out,"zlo, zhi = {:.8}, {:.8}\n", domain->boxlo[2], domain->boxhi[2]);
466       if (domain->triclinic)
467         fmt::print(out,"Xy, xz, yz = {:.8}, {:.8}, {:.8}\n",
468                    domain->xy, domain->xz, domain->yz);
469     } else {
470       fputs("\nBox has not yet been created\n",out);
471     }
472   }
473 
474   if (domain->box_exist && (flags & COEFFS)) {
475     Pair *pair=force->pair;
476 
477     fputs("\nCoeff status information:\n",out);
478     if (pair) {
479       fputs("\nPair Coeffs:\n",out);
480       for (int i=1; i <= atom->ntypes; ++i)
481         for (int j=i; j <= atom->ntypes; ++j) {
482           fmt::print(out,"{:6d} {:6d}:",i,j);
483           if (pair->allocated && pair->setflag[i][j]) fputs(" is set\n",out);
484           else fputs(" is not set\n",out);
485         }
486     }
487     if (force->bond) {
488       Bond *bond=force->bond;
489 
490       if (bond) {
491         fputs("\nBond Coeffs:\n",out);
492         for (int i=1; i <= atom->nbondtypes; ++i) {
493           fmt::print(out,"{:6d}:",i);
494           if (bond->allocated && bond->setflag[i]) fputs(" is set\n",out);
495           else fputs (" is not set\n",out);
496         }
497       }
498     }
499     if (force->angle) {
500       Angle *angle=force->angle;
501 
502       if (angle) {
503         fputs("\nAngle Coeffs:\n",out);
504         for (int i=1; i <= atom->nangletypes; ++i) {
505           fmt::print(out,"{:6d}:",i);
506           if (angle->allocated && angle->setflag[i]) fputs(" is set\n",out);
507           else fputs (" is not set\n",out);
508         }
509       }
510     }
511     if (force->dihedral) {
512       Dihedral *dihedral=force->dihedral;
513 
514       if (dihedral) {
515         fputs("\nDihedral Coeffs:\n",out);
516         for (int i=1; i <= atom->ndihedraltypes; ++i) {
517           fmt::print(out,"{:6d}:",i);
518           if (dihedral->allocated && dihedral->setflag[i]) fputs(" is set\n",out);
519           else fputs (" is not set\n",out);
520         }
521       }
522     }
523     if (force->improper) {
524       Improper *b=force->improper;
525 
526       if (b) {
527         fputs("\nImproper Coeffs:\n",out);
528         for (int i=1; i <= atom->nimpropertypes; ++i) {
529           fmt::print(out,"{:6d}:",i);
530           if (b->allocated && b->setflag[i]) fputs(" is set\n",out);
531           else fputs (" is not set\n",out);
532         }
533       }
534     }
535   }
536 
537   if (flags & GROUPS) {
538     int ngroup = group->ngroup;
539     char **names = group->names;
540     int *dynamic = group->dynamic;
541     fputs("\nGroup information:\n",out);
542     for (int i=0; i < ngroup; ++i) {
543       if (names[i])
544         fmt::print(out,"Group[{:2d}]:     {:16} ({})\n",
545                    i, names[i], dynamic[i] ? "dynamic" : "static");
546     }
547   }
548 
549   if (flags & REGIONS) {
550     int nreg = domain->nregion;
551     Region **regs = domain->regions;
552     fputs("\nRegion information:\n",out);
553     for (int i=0; i < nreg; ++i) {
554       fmt::print(out,"Region[{:3d}]:  {:16}  style = {:16}  side = {}\n",
555                  i, std::string(regs[i]->id)+',',
556                  std::string(regs[i]->style)+',',
557                  regs[i]->interior ? "in" : "out");
558       if (regs[i]->bboxflag)
559         fmt::print(out,"   Boundary:  lo {:.8} {:.8} {:.8}  hi {:.8} {:.8} {:.8}\n",
560                    regs[i]->extent_xlo, regs[i]->extent_ylo,
561                    regs[i]->extent_zlo, regs[i]->extent_xhi,
562                    regs[i]->extent_yhi, regs[i]->extent_zhi);
563       else fputs("   No Boundary\n",out);
564     }
565   }
566 
567   if (flags & COMPUTES) {
568     int ncompute = modify->ncompute;
569     Compute **compute = modify->compute;
570     char **names = group->names;
571     fputs("\nCompute information:\n",out);
572     for (int i=0; i < ncompute; ++i) {
573       fmt::print(out,"Compute[{:3d}]:  {:16}  style = {:16}  group = {}\n",
574                  i, std::string(compute[i]->id)+',',
575                  std::string(compute[i]->style)+',',
576                  names[compute[i]->igroup]);
577     }
578   }
579 
580   if (flags & DUMPS) {
581     int ndump = output->ndump;
582     Dump **dump = output->dump;
583     int *nevery = output->every_dump;           \
584     char **vnames = output->var_dump;
585     char **names = group->names;
586     fputs("\nDump information:\n",out);
587     for (int i=0; i < ndump; ++i) {
588       fmt::print(out,"Dump[{:3d}]:     {:16}  file = {:16}  style = {:16}  group = {:16}  ",
589                  i, std::string(dump[i]->id)+',',
590                  std::string(dump[i]->filename)+',',
591                  std::string(dump[i]->style)+',',
592                  std::string(names[dump[i]->igroup])+',');
593       if (nevery[i]) {
594         fmt::print(out,"every = {}\n", nevery[i]);
595       } else {
596         fmt::print(out,"every = {}\n", vnames[i]);
597       }
598     }
599   }
600 
601   if (flags & FIXES) {
602     int nfix = modify->nfix;
603     Fix **fix = modify->fix;
604     char **names = group->names;
605     fputs("\nFix information:\n",out);
606     for (int i=0; i < nfix; ++i) {
607       fmt::print(out, "Fix[{:3d}]:      {:16}  style = {:16}  group = {}\n",
608                  i,std::string(fix[i]->id)+',',
609                  std::string(fix[i]->style)+',',
610                  names[fix[i]->igroup]);
611     }
612   }
613 
614   if (flags & VARIABLES) {
615     int nvar = input->variable->nvar;
616     int *style = input->variable->style;
617     char **names = input->variable->names;
618     char ***data = input->variable->data;
619     fputs("\nVariable information:\n",out);
620     for (int i=0; i < nvar; ++i) {
621       int ndata = 1;
622       fmt::print(out,"Variable[{:3d}]: {:16}  style = {:16}  def =",
623                  i,std::string(names[i])+',',
624                  std::string(varstyles[style[i]])+',');
625       if (style[i] == Variable::INTERNAL) {
626         fmt::print(out,"{:.8}\n",input->variable->dvalue[i]);
627         continue;
628       }
629       if ((style[i] != Variable::LOOP) && (style[i] != Variable::ULOOP))
630         ndata = input->variable->num[i];
631       for (int j=0; j < ndata; ++j)
632         if (data[i][j]) fmt::print(out," {}",data[i][j]);
633       fputs("\n",out);
634     }
635   }
636 
637   if (flags & TIME) {
638     double wallclock = MPI_Wtime() - lmp->initclock;
639     double cpuclock = 0.0;
640 
641 #if defined(_WIN32)
642     // from MSD docs.
643     FILETIME ct,et,kt,ut;
644     union { FILETIME ft; uint64_t ui; } cpu;
645     if (GetProcessTimes(GetCurrentProcess(),&ct,&et,&kt,&ut)) {
646       cpu.ft = ut;
647       cpuclock = cpu.ui * 0.0000001;
648     }
649 #else /* POSIX */
650     struct rusage ru;
651     if (getrusage(RUSAGE_SELF, &ru) == 0) {
652       cpuclock  = (double) ru.ru_utime.tv_sec;
653       cpuclock += (double) ru.ru_utime.tv_usec * 0.000001;
654     }
655 #endif /* ! _WIN32 */
656 
657     int cpuh,cpum,cpus,wallh,wallm,walls;
658     cpus = fmod(cpuclock,60.0);
659     cpuclock = (cpuclock - cpus) / 60.0;
660     cpum = fmod(cpuclock,60.0);
661     cpuh = (cpuclock - cpum) / 60.0;
662     walls = fmod(wallclock,60.0);
663     wallclock = (wallclock - walls) / 60.0;
664     wallm = fmod(wallclock,60.0);
665     wallh = (wallclock - wallm) / 60.0;
666     fmt::print(out,"\nTotal time information (MPI rank 0):\n"
667                "  CPU time: {:4d}:{:02d}:{:02d}\n"
668                " Wall time: {:4d}:{:02d}:{:02d}\n",
669                cpuh,cpum,cpus,wallh,wallm,walls);
670   }
671 
672   if (flags & STYLES) {
673     available_styles(out, flags);
674   }
675 
676   fputs("\nInfo-Info-Info-Info-Info-Info-Info-Info-Info-Info-Info\n\n",out);
677 
678   // close output file pointer if opened locally thus forcing a hard sync.
679   if ((out != screen) && (out != logfile))
680     fclose(out);
681 }
682 
available_styles(FILE * out,int flags)683 void Info::available_styles(FILE * out, int flags)
684 {
685 
686   fputs("\nStyles information:\n",out);
687 
688   if (flags & ATOM_STYLES)      atom_styles(out);
689   if (flags & INTEGRATE_STYLES) integrate_styles(out);
690   if (flags & MINIMIZE_STYLES)  minimize_styles(out);
691   if (flags & PAIR_STYLES)      pair_styles(out);
692   if (flags & BOND_STYLES)      bond_styles(out);
693   if (flags & ANGLE_STYLES)     angle_styles(out);
694   if (flags & DIHEDRAL_STYLES)  dihedral_styles(out);
695   if (flags & IMPROPER_STYLES)  improper_styles(out);
696   if (flags & KSPACE_STYLES)    kspace_styles(out);
697   if (flags & FIX_STYLES)       fix_styles(out);
698   if (flags & COMPUTE_STYLES)   compute_styles(out);
699   if (flags & REGION_STYLES)    region_styles(out);
700   if (flags & DUMP_STYLES)      dump_styles(out);
701   if (flags & COMMAND_STYLES)   command_styles(out);
702 }
703 
atom_styles(FILE * out)704 void Info::atom_styles(FILE *out)
705 {
706   fputs("\nAtom styles:\n",out);
707   print_columns(out, atom->avec_map);
708   fputs("\n\n\n",out);
709 }
710 
integrate_styles(FILE * out)711 void Info::integrate_styles(FILE *out)
712 {
713   fputs("\nIntegrate styles:\n",out);
714   print_columns(out, update->integrate_map);
715   fputs("\n\n\n",out);
716 }
717 
minimize_styles(FILE * out)718 void Info::minimize_styles(FILE *out)
719 {
720   fputs("\nMinimize styles:\n",out);
721   print_columns(out, update->minimize_map);
722   fputs("\n\n\n",out);
723 }
724 
pair_styles(FILE * out)725 void Info::pair_styles(FILE *out)
726 {
727   fputs("\nPair styles:\n",out);
728   print_columns(out, force->pair_map);
729   fputs("\n\n\n",out);
730 }
731 
bond_styles(FILE * out)732 void Info::bond_styles(FILE *out)
733 {
734   fputs("\nBond styles:\n",out);
735   print_columns(out, force->bond_map);
736   fputs("\n\n\n",out);
737 }
738 
angle_styles(FILE * out)739 void Info::angle_styles(FILE *out)
740 {
741   fputs("\nAngle styles:\n",out);
742   print_columns(out, force->angle_map);
743   fputs("\n\n\n",out);
744 }
745 
dihedral_styles(FILE * out)746 void Info::dihedral_styles(FILE *out)
747 {
748   fputs("\nDihedral styles:\n",out);
749   print_columns(out, force->dihedral_map);
750   fputs("\n\n\n",out);
751 }
752 
improper_styles(FILE * out)753 void Info::improper_styles(FILE *out)
754 {
755   fputs("\nImproper styles:\n",out);
756   print_columns(out, force->improper_map);
757   fputs("\n\n\n",out);
758 }
759 
kspace_styles(FILE * out)760 void Info::kspace_styles(FILE *out)
761 {
762   fputs("\nKSpace styles:\n",out);
763   print_columns(out, force->kspace_map);
764   fputs("\n\n\n",out);
765 }
766 
fix_styles(FILE * out)767 void Info::fix_styles(FILE *out)
768 {
769   fputs("\nFix styles:\n",out);
770   print_columns(out, modify->fix_map);
771   fputs("\n\n\n",out);
772 }
773 
compute_styles(FILE * out)774 void Info::compute_styles(FILE *out)
775 {
776   fputs("\nCompute styles:\n",out);
777   print_columns(out, modify->compute_map);
778   fputs("\n\n\n",out);
779 }
780 
region_styles(FILE * out)781 void Info::region_styles(FILE *out)
782 {
783   fputs("\nRegion styles:\n",out);
784   print_columns(out, domain->region_map);
785   fputs("\n\n\n",out);
786 }
787 
dump_styles(FILE * out)788 void Info::dump_styles(FILE *out)
789 {
790   fputs("\nDump styles:\n",out);
791   print_columns(out,output->dump_map);
792   fputs("\n\n\n",out);
793 }
794 
command_styles(FILE * out)795 void Info::command_styles(FILE *out)
796 {
797   fputs("\nCommand styles (add-on input script commands):\n",out);
798   print_columns(out, input->command_map);
799   fputs("\n\n\n",out);
800 }
801 
802 
803 /* ---------------------------------------------------------------------- */
804 
805 // the is_active() function returns true if the selected style or name
806 // in the selected category is currently in use.
807 
is_active(const char * category,const char * name)808 bool Info::is_active(const char *category, const char *name)
809 {
810   if ((category == nullptr) || (name == nullptr)) return false;
811   const char *style = "none";
812 
813   if (strcmp(category,"package") == 0) {
814     if (strcmp(name,"gpu") == 0) {
815       return (modify->find_fix("package_gpu") >= 0) ? true : false;
816     } else if (strcmp(name,"intel") == 0) {
817       return (modify->find_fix("package_intel") >= 0) ? true : false;
818     } else if (strcmp(name,"kokkos") == 0) {
819       return (lmp->kokkos && lmp->kokkos->kokkos_exists) ? true : false;
820     } else if (strcmp(name,"omp") == 0) {
821       return (modify->find_fix("package_omp") >= 0) ? true : false;
822     } else error->all(FLERR,"Unknown name for info package category: {}", name);
823 
824   } else if (strcmp(category,"newton") == 0) {
825     if (strcmp(name,"pair") == 0) return (force->newton_pair != 0);
826     else if (strcmp(name,"bond") == 0) return (force->newton_bond != 0);
827     else if (strcmp(name,"any") == 0) return (force->newton != 0);
828     else error->all(FLERR,"Unknown name for info newton category: {}", name);
829 
830   } else if (strcmp(category,"pair") == 0) {
831     if (force->pair == nullptr) return false;
832     if (strcmp(name,"single") == 0) return (force->pair->single_enable != 0);
833     else if (strcmp(name,"respa") == 0) return (force->pair->respa_enable != 0);
834     else if (strcmp(name,"manybody") == 0) return (force->pair->manybody_flag != 0);
835     else if (strcmp(name,"tail") == 0) return (force->pair->tail_flag != 0);
836     else if (strcmp(name,"shift") == 0) return (force->pair->offset_flag != 0);
837     else error->all(FLERR,"Unknown name for info pair category: {}", name);
838 
839   } else if (strcmp(category,"comm_style") == 0) {
840     style = commstyles[comm->style];
841   } else if (strcmp(category,"min_style") == 0) {
842     style = update->minimize_style;
843   } else if (strcmp(category,"run_style") == 0) {
844     style = update->integrate_style;
845   } else if (strcmp(category,"atom_style") == 0) {
846     style = atom->atom_style;
847   } else if (strcmp(category,"pair_style") == 0) {
848     style = force->pair_style;
849   } else if (strcmp(category,"bond_style") == 0) {
850     style = force->bond_style;
851   } else if (strcmp(category,"angle_style") == 0) {
852     style = force->angle_style;
853   } else if (strcmp(category,"dihedral_style") == 0) {
854     style = force->dihedral_style;
855   } else if (strcmp(category,"improper_style") == 0) {
856     style = force->improper_style;
857   } else if (strcmp(category,"kspace_style") == 0) {
858     style = force->kspace_style;
859   } else error->all(FLERR,"Unknown category for info is_active(): {}", category);
860 
861   int match = 0;
862   if (strcmp(style,name) == 0) match = 1;
863 
864   if (!match && lmp->suffix_enable) {
865     if (lmp->suffix) {
866       std::string name_w_suffix = name + std::string("/") + lmp->suffix;
867       if (name_w_suffix == style) match = 1;
868     }
869     if (!match && lmp->suffix2) {
870       std::string name_w_suffix = name + std::string("/") + lmp->suffix2;
871       if (name_w_suffix == style) match = 1;
872     }
873   }
874   return match ? true : false;
875 }
876 
877 /* ---------------------------------------------------------------------- */
878 
879 // the is_available() function returns true if the selected style
880 // or name in the selected category is available for use (but need
881 // not be currently active).
882 
is_available(const char * category,const char * name)883 bool Info::is_available(const char *category, const char *name)
884 {
885   if ((category == nullptr) || (name == nullptr)) return false;
886 
887   if (has_style(category, name)) {
888     return true;
889   } else if (strcmp(category,"feature") == 0) {
890     if (strcmp(name,"gzip") == 0) {
891       return has_gzip_support();
892     } else if (strcmp(name,"png") == 0) {
893       return has_png_support();
894     } else if (strcmp(name,"jpeg") == 0) {
895       return has_jpeg_support();
896     } else if (strcmp(name,"ffmpeg") == 0) {
897       return has_ffmpeg_support();
898     } else if (strcmp(name,"exceptions") == 0) {
899       return has_exceptions();
900     }
901   } else error->all(FLERR,"Unknown category for info is_available(): {}", category);
902 
903   return false;
904 }
905 
906 /* ---------------------------------------------------------------------- */
907 
908 // the is_defined() function returns true if a particular ID of the
909 // selected category (e.g. fix ID, group ID, region ID etc.) has been
910 // defined and thus can be accessed. It does *NOT* check whether a
911 // particular ID has a particular style.
912 
is_defined(const char * category,const char * name)913 bool Info::is_defined(const char *category, const char *name)
914 {
915   if ((category == nullptr) || (name == nullptr)) return false;
916 
917   if (strcmp(category,"compute") == 0) {
918     int ncompute = modify->ncompute;
919     Compute **compute = modify->compute;
920     for (int i=0; i < ncompute; ++i) {
921       if (strcmp(compute[i]->id,name) == 0)
922         return true;
923     }
924   } else if (strcmp(category,"dump") == 0) {
925     int ndump = output->ndump;
926     Dump **dump = output->dump;
927     for (int i=0; i < ndump; ++i) {
928       if (strcmp(dump[i]->id,name) == 0)
929         return true;
930     }
931   } else if (strcmp(category,"fix") == 0) {
932     int nfix = modify->nfix;
933     Fix **fix = modify->fix;
934     for (int i=0; i < nfix; ++i) {
935       if (strcmp(fix[i]->id,name) == 0)
936         return true;
937     }
938   } else if (strcmp(category,"group") == 0) {
939     int ngroup = group->ngroup;
940     char **names = group->names;
941     for (int i=0; i < ngroup; ++i) {
942       if (strcmp(names[i],name) == 0)
943         return true;
944     }
945   } else if (strcmp(category,"region") == 0) {
946     int nreg = domain->nregion;
947     Region **regs = domain->regions;
948     for (int i=0; i < nreg; ++i) {
949       if (strcmp(regs[i]->id,name) == 0)
950         return true;
951     }
952   } else if (strcmp(category,"variable") == 0) {
953     int nvar = input->variable->nvar;
954     char **names = input->variable->names;
955 
956     for (int i=0; i < nvar; ++i) {
957       if (strcmp(names[i],name) == 0)
958         return true;
959     }
960   } else error->all(FLERR,"Unknown category for info is_defined(): {}", category);
961 
962   return false;
963 }
964 
has_style(const std::string & category,const std::string & name)965 bool Info::has_style(const std::string &category, const std::string &name)
966 {
967   if (category == "atom") {
968     return find_style(lmp, atom->avec_map, name, false);
969   } else if (category == "integrate") {
970     return find_style(lmp, update->integrate_map, name, true);
971   } else if (category == "minimize") {
972     return find_style(lmp, update->minimize_map, name, true);
973   } else if (category == "pair") {
974     return find_style(lmp, force->pair_map, name, true);
975   } else if (category == "bond") {
976     return find_style(lmp, force->bond_map, name, true);
977   } else if (category == "angle") {
978     return find_style(lmp, force->angle_map, name, true);
979   } else if (category == "dihedral") {
980     return find_style(lmp, force->dihedral_map, name, true);
981   } else if (category == "improper") {
982     return find_style(lmp, force->improper_map, name, true);
983   } else if (category == "kspace") {
984     return find_style(lmp, force->kspace_map, name, true);
985   } else if (category == "fix") {
986     return find_style(lmp, modify->fix_map, name, true);
987   } else if (category == "compute") {
988     return find_style(lmp, modify->compute_map, name, true);
989   } else if (category == "region") {
990     return find_style(lmp, domain->region_map, name, false);
991   } else if (category == "dump") {
992     return find_style(lmp, output->dump_map, name, false);
993   } else if (category == "command") {
994     return find_style(lmp, input->command_map, name, false);
995   }
996   return false;
997 }
998 
get_available_styles(const std::string & category)999 std::vector<std::string> Info::get_available_styles(const std::string &category)
1000 {
1001   if (category == "atom") {
1002     return get_style_names(atom->avec_map);
1003   } else if (category == "integrate") {
1004     return get_style_names(update->integrate_map);
1005   } else if (category == "minimize") {
1006     return get_style_names(update->minimize_map);
1007   } else if (category == "pair") {
1008     return get_style_names(force->pair_map);
1009   } else if (category == "bond") {
1010     return get_style_names(force->bond_map);
1011   } else if (category == "angle") {
1012     return get_style_names(force->angle_map);
1013   } else if (category == "dihedral") {
1014     return get_style_names(force->dihedral_map);
1015   } else if (category == "improper") {
1016     return get_style_names(force->improper_map);
1017   } else if (category == "kspace") {
1018     return get_style_names(force->kspace_map);
1019   } else if (category == "fix") {
1020     return get_style_names(modify->fix_map);
1021   } else if (category == "compute") {
1022     return get_style_names(modify->compute_map);
1023   } else if (category == "region") {
1024     return get_style_names(domain->region_map);
1025   } else if (category == "dump") {
1026     return get_style_names(output->dump_map);
1027   } else if (category == "command") {
1028     return get_style_names(input->command_map);
1029   }
1030   return std::vector<std::string>();
1031 }
1032 
1033 template<typename ValueType>
get_style_names(std::map<std::string,ValueType> * styles)1034 static std::vector<std::string> get_style_names(std::map<std::string, ValueType> *styles)
1035 {
1036   std::vector<std::string> names;
1037 
1038   names.reserve(styles->size());
1039   for (auto const& kv : *styles) {
1040     // skip "secret" styles
1041     if (isupper(kv.first[0])) continue;
1042     names.push_back(kv.first);
1043   }
1044 
1045   return names;
1046 }
1047 
1048 template<typename ValueType>
find_style(const LAMMPS * lmp,std::map<std::string,ValueType> * styles,const std::string & name,bool suffix_check)1049 static bool find_style(const LAMMPS *lmp, std::map<std::string, ValueType> *styles,
1050                        const std::string &name, bool suffix_check)
1051 {
1052   if (styles->find(name) != styles->end()) {
1053     return true;
1054   }
1055 
1056   if (suffix_check && lmp->suffix_enable) {
1057     if (lmp->suffix) {
1058       std::string name_w_suffix = name + "/" + lmp->suffix;
1059       if (find_style(lmp, styles, name_w_suffix, false)) {
1060         return true;
1061       }
1062     }
1063     if (lmp->suffix2) {
1064       std::string name_w_suffix = name + "/" + lmp->suffix2;
1065       if (find_style(lmp, styles, name_w_suffix, false)) {
1066         return true;
1067       }
1068     }
1069   }
1070   return false;
1071 }
1072 
1073 template<typename ValueType>
print_columns(FILE * fp,std::map<std::string,ValueType> * styles)1074 static void print_columns(FILE *fp, std::map<std::string, ValueType> *styles)
1075 {
1076   if (styles->empty()) {
1077     fprintf(fp, "\nNone");
1078     return;
1079   }
1080 
1081   // std::map keys are already sorted
1082   int pos = 80;
1083   for (typename std::map<std::string, ValueType>::iterator it = styles->begin(); it != styles->end(); ++it) {
1084     const std::string &style_name = it->first;
1085 
1086     // skip "secret" styles
1087     if (isupper(style_name[0])) continue;
1088 
1089     int len = style_name.length();
1090     if (pos + len > 80) {
1091       fprintf(fp,"\n");
1092       pos = 0;
1093     }
1094 
1095     if (len < 16) {
1096       fprintf(fp,"%-16s", style_name.c_str());
1097       pos += 16;
1098     } else if (len < 32) {
1099       fprintf(fp,"%-32s", style_name.c_str());
1100       pos += 32;
1101     } else if (len < 48) {
1102       fprintf(fp,"%-48s", style_name.c_str());
1103       pos += 48;
1104     } else if (len < 64) {
1105       fprintf(fp,"%-64s", style_name.c_str());
1106       pos += 64;
1107     } else {
1108       fprintf(fp,"%-80s", style_name.c_str());
1109       pos += 80;
1110     }
1111   }
1112 }
1113 
has_gzip_support()1114 bool Info::has_gzip_support() {
1115 #ifdef LAMMPS_GZIP
1116   return true;
1117 #else
1118   return false;
1119 #endif
1120 }
1121 
has_png_support()1122 bool Info::has_png_support() {
1123 #ifdef LAMMPS_PNG
1124   return true;
1125 #else
1126   return false;
1127 #endif
1128 }
1129 
has_jpeg_support()1130 bool Info::has_jpeg_support() {
1131 #ifdef LAMMPS_JPEG
1132   return true;
1133 #else
1134   return false;
1135 #endif
1136 }
1137 
has_ffmpeg_support()1138 bool Info::has_ffmpeg_support() {
1139 #ifdef LAMMPS_FFMPEG
1140   return true;
1141 #else
1142   return false;
1143 #endif
1144 }
1145 
has_exceptions()1146 bool Info::has_exceptions() {
1147 #ifdef LAMMPS_EXCEPTIONS
1148   return true;
1149 #else
1150   return false;
1151 #endif
1152 }
1153 
has_package(const std::string & package_name)1154 bool Info::has_package(const std::string &package_name) {
1155   for (int i = 0; LAMMPS::installed_packages[i] != nullptr; ++i) {
1156     if (package_name == LAMMPS::installed_packages[i]) {
1157       return true;
1158     }
1159   }
1160   return false;
1161 }
1162 
1163 #if defined(LMP_GPU)
1164 extern bool lmp_gpu_config(const std::string &, const std::string &);
1165 extern bool lmp_has_gpu_device();
1166 extern std::string lmp_gpu_device_info();
1167 
has_gpu_device()1168 bool Info::has_gpu_device()
1169 {
1170   return lmp_has_gpu_device();
1171 }
1172 
get_gpu_device_info()1173 std::string Info::get_gpu_device_info()
1174 {
1175   return lmp_gpu_device_info();
1176 }
1177 #else
has_gpu_device()1178 bool Info::has_gpu_device()
1179 {
1180   return false;
1181 }
get_gpu_device_info()1182 std::string Info::get_gpu_device_info()
1183 {
1184   return "";
1185 }
1186 #endif
1187 
1188 #if defined(LMP_KOKKOS)
1189 #include "Kokkos_Macros.hpp"
1190 #endif
1191 
has_accelerator_feature(const std::string & package,const std::string & category,const std::string & setting)1192 bool Info::has_accelerator_feature(const std::string &package,
1193                                    const std::string &category,
1194                                    const std::string &setting)
1195 {
1196 #if defined(LMP_KOKKOS)
1197   if (package == "KOKKOS") {
1198     if (category == "precision") {
1199       if (setting == "double") return true;
1200       else return false;
1201     }
1202     if (category == "api") {
1203 #if defined(KOKKOS_ENABLE_OPENMP)
1204       if (setting == "openmp") return true;
1205 #endif
1206 #if defined(KOKKOS_ENABLE_SERIAL)
1207       if (setting == "serial") return true;
1208 #endif
1209 #if defined(KOKKOS_ENABLE_THREADS)
1210       if (setting == "pthreads") return true;
1211 #endif
1212 #if defined(KOKKOS_ENABLE_CUDA)
1213       if (setting == "cuda") return true;
1214 #endif
1215 #if defined(KOKKOS_ENABLE_HIP)
1216       if (setting == "hip") return true;
1217 #endif
1218 #if defined(KOKKOS_ENABLE_SYCL)
1219       if (setting == "sycl") return true;
1220 #endif
1221       return false;
1222     }
1223   }
1224 #endif
1225 #if defined(LMP_GPU)
1226   if (package == "GPU") {
1227     return lmp_gpu_config(category,setting);
1228   }
1229 #endif
1230 #if defined(LMP_OPENMP)
1231   if (package == "OPENMP") {
1232     if (category == "precision") {
1233       if (setting == "double") return true;
1234       else return false;
1235     }
1236     if (category == "api") {
1237 #if defined(_OPENMP)
1238       if (setting == "openmp") return true;
1239 #else
1240       if (setting == "serial") return true;
1241 #endif
1242       return false;
1243     }
1244   }
1245 #endif
1246 #if defined(LMP_INTEL)
1247   if (package == "INTEL") {
1248     if (category == "precision") {
1249       if (setting == "double") return true;
1250       else if (setting == "mixed") return true;
1251       else if (setting == "single")return true;
1252       else return false;
1253     }
1254     if (category == "api") {
1255 #if defined(LMP_INTEL_OFFLOAD)
1256       if (setting == "phi") return true;
1257 #elif defined(_OPENMP)
1258       if (setting == "openmp") return true;
1259 #else
1260       if (setting == "serial") return true;
1261 #endif
1262       return false;
1263     }
1264   }
1265 #endif
1266   return false;
1267 }
1268 
1269 /* ---------------------------------------------------------------------- */
1270 #define _INFOBUF_SIZE 256
1271 
get_os_info()1272 std::string Info::get_os_info()
1273 {
1274   std::string buf;
1275 
1276 #if defined(_WIN32)
1277   DWORD fullversion,majorv,minorv,buildv=0;
1278 
1279   fullversion = GetVersion();
1280   majorv = (DWORD) (LOBYTE(LOWORD(fullversion)));
1281   minorv = (DWORD) (HIBYTE(LOWORD(fullversion)));
1282   if (fullversion < 0x80000000)
1283     buildv = (DWORD) (HIWORD(fullversion));
1284 
1285   buf = fmt::format("Windows {}.{} ({}) on ",majorv,minorv,buildv);
1286 
1287   SYSTEM_INFO si;
1288   GetSystemInfo(&si);
1289 
1290   switch (si.wProcessorArchitecture) {
1291   case PROCESSOR_ARCHITECTURE_AMD64:
1292     buf += "x86_64";
1293     break;
1294   case PROCESSOR_ARCHITECTURE_ARM:
1295     buf += "arm";
1296     break;
1297   case PROCESSOR_ARCHITECTURE_IA64:
1298     buf += "ia64";
1299     break;
1300   case PROCESSOR_ARCHITECTURE_INTEL:
1301     buf += "i386";
1302     break;
1303   default:
1304     buf += "(unknown)";
1305   }
1306 #else
1307   struct utsname ut;
1308   uname(&ut);
1309 
1310   // try to get OS distribution name, if available
1311   std::string distro = ut.sysname;
1312   if (utils::file_is_readable("/etc/os-release")) {
1313     try {
1314         TextFileReader reader("/etc/os-release","");
1315         while (1) {
1316           auto words = reader.next_values(0,"=");
1317           if ((words.count() > 1) && (words.next_string() == "PRETTY_NAME")) {
1318             distro += " " + utils::trim(words.next_string());
1319             break;
1320           }
1321         }
1322     } catch (std::exception &e) {
1323       ; // EOF but keyword not found
1324     }
1325   }
1326 
1327   buf = fmt::format("{} {} on {}", distro, ut.release, ut.machine);
1328 #endif
1329   return buf;
1330 }
1331 
get_compiler_info()1332 std::string Info::get_compiler_info()
1333 {
1334   std::string buf;
1335 #if defined(__INTEL_LLVM_COMPILER)
1336   constexpr double version = static_cast<double>(__INTEL_LLVM_COMPILER)*0.01;
1337   buf = fmt::format("Intel LLVM C++ {:.1f} / {}", version, __VERSION__);
1338 #elif defined(__ibmxl__)
1339   buf = fmt::format("IBM XL C/C++ (Clang) {}.{}.{}",
1340                     __ibmxl_version__, __ibmxl_release__, __ibmxl_modification__);
1341 #elif defined(__clang__)
1342   buf = fmt::format("Clang C++ {}", __VERSION__);
1343 #elif defined(__PGI)
1344   buf = fmt::format("PGI C++ {}.{}",__PGIC__, __PGIC_MINOR__);
1345 #elif defined(__INTEL_COMPILER)
1346   double version = static_cast<double>(__INTEL_COMPILER)*0.01;
1347   buf = fmt::format("Intel Classic C++ {:.2f}.{} / {}", version,
1348                     __INTEL_COMPILER_UPDATE, __VERSION__);
1349 #elif defined(__MINGW64__)
1350   buf = fmt::format("MinGW-w64 64bit {}.{} / GNU C++ {}", __MINGW64_VERSION_MAJOR,
1351                     __MINGW64_VERSION_MINOR, __VERSION__);
1352 #elif defined(__MINGW32__)
1353   buf = fmt::format("MinGW-w64 32bit {}.{} / GNU C++ {}", __MINGW32_MAJOR_VERSION,
1354                     __MINGW32_MINOR_VERSION, __VERSION__);
1355 #elif defined(__GNUC__)
1356   buf = fmt::format("GNU C++ {}",   __VERSION__);
1357 #elif defined(_MSC_VER) && (_MSC_VER > 1920) && (_MSC_VER < 2000)
1358   constexpr int major = _MSC_VER / 100;
1359   constexpr int minor = _MSC_VER - major *100;
1360   buf = fmt::format("Microsoft Visual Studio 20{}, C/C++ {}.{}", major, major-5, minor);
1361 #else
1362   buf = "(Unknown)";
1363 #endif
1364   return buf;
1365 }
1366 
get_openmp_info()1367 std::string Info::get_openmp_info()
1368 {
1369 
1370 #if !defined(_OPENMP)
1371   return "OpenMP not enabled";
1372 #else
1373 
1374 // Supported OpenMP version corresponds to the release date of the
1375 // specifications as posted at https://www.openmp.org/specifications/
1376 
1377 #if _OPENMP > 202011
1378   return "OpenMP newer than version 5.1";
1379 #elif _OPENMP == 202011
1380   return "OpenMP 5.1";
1381 #elif _OPENMP == 201811
1382   return "OpenMP 5.0";
1383 #elif _OPENMP == 201611
1384   return "OpenMP 5.0 preview 1";
1385 #elif _OPENMP == 201511
1386   return "OpenMP 4.5";
1387 #elif _OPENMP == 201307
1388   return "OpenMP 4.0";
1389 #elif _OPENMP == 201107
1390   return "OpenMP 3.1";
1391 #elif _OPENMP == 200805
1392   return "OpenMP 3.0";
1393 #elif _OPENMP == 200505
1394   return "OpenMP 2.5";
1395 #elif _OPENMP == 200203
1396   return "OpenMP 2.0";
1397 #else
1398   return "unknown OpenMP version";
1399 #endif
1400 
1401 #endif
1402 }
1403 
get_mpi_vendor()1404 std::string Info::get_mpi_vendor() {
1405   #if defined(MPI_STUBS)
1406   return "MPI STUBS";
1407   #elif defined(OPEN_MPI)
1408   return "Open MPI";
1409   #elif defined(MPICH_NAME)
1410   return "MPICH";
1411   #elif defined(I_MPI_VERSION)
1412   return "Intel MPI";
1413   #elif defined(PLATFORM_MPI)
1414   return "Platform MPI";
1415   #elif defined(HP_MPI)
1416   return "HP MPI";
1417   #elif defined(MSMPI_VER)
1418   return "Microsoft MPI";
1419   #else
1420   return "Unknown MPI implementation";
1421   #endif
1422 }
1423 
get_mpi_info(int & major,int & minor)1424 std::string Info::get_mpi_info(int &major, int &minor)
1425 {
1426   int len;
1427 #if (defined(MPI_VERSION) && (MPI_VERSION > 2)) || defined(MPI_STUBS)
1428   static char version[MPI_MAX_LIBRARY_VERSION_STRING];
1429   MPI_Get_library_version(version,&len);
1430 #else
1431   static char version[32];
1432   strcpy(version,get_mpi_vendor().c_str());
1433   len = strlen(version);
1434 #endif
1435 
1436   MPI_Get_version(&major,&minor);
1437   if (len > 80) {
1438     char *ptr = strchr(version+80,'\n');
1439     if (ptr) *ptr = '\0';
1440   }
1441   return std::string(version);
1442 }
1443 
get_cxx_info()1444 std::string Info::get_cxx_info()
1445 {
1446 #if __cplusplus > 202002L
1447   return "newer than C++20";
1448 #elif __cplusplus == 202002L
1449   return "C++20";
1450 #elif __cplusplus == 201703L
1451   return "C++17";
1452 #elif __cplusplus == 201402L
1453   return "C++14";
1454 #elif __cplusplus == 201103L
1455   return "C++11";
1456 #elif __cplusplus == 199711L
1457   return "C++98";
1458 #else
1459   return "unknown";
1460 #endif
1461 }
1462 
get_accelerator_info(const std::string & package)1463 std::string Info::get_accelerator_info(const std::string &package)
1464 {
1465   std::string mesg("");
1466   if ((package.empty() || (package == "GPU")) && has_package("GPU")) {
1467     mesg += "GPU package API:";
1468     if (has_accelerator_feature("GPU","api","cuda"))   mesg += " CUDA";
1469     if (has_accelerator_feature("GPU","api","hip"))    mesg += " HIP";
1470     if (has_accelerator_feature("GPU","api","opencl")) mesg += " OpenCL";
1471     mesg +=  "\nGPU package precision:";
1472     if (has_accelerator_feature("GPU","precision","single")) mesg += " single";
1473     if (has_accelerator_feature("GPU","precision","mixed"))  mesg += " mixed";
1474     if (has_accelerator_feature("GPU","precision","double")) mesg += " double";
1475     mesg += "\n";
1476   }
1477   if ((package.empty() || (package == "KOKKOS")) && has_package("KOKKOS")) {
1478     mesg += "KOKKOS package API:";
1479     if (has_accelerator_feature("KOKKOS","api","cuda"))     mesg += " CUDA";
1480     if (has_accelerator_feature("KOKKOS","api","hip"))      mesg += " HIP";
1481     if (has_accelerator_feature("KOKKOS","api","sycl"))     mesg += " SYCL";
1482     if (has_accelerator_feature("KOKKOS","api","openmp"))   mesg += " OpenMP";
1483     if (has_accelerator_feature("KOKKOS","api","serial"))   mesg += " Serial";
1484     if (has_accelerator_feature("KOKKOS","api","pthreads")) mesg += " Pthreads";
1485     mesg +=  "\nKOKKOS package precision:";
1486     if (has_accelerator_feature("KOKKOS","precision","single")) mesg += " single";
1487     if (has_accelerator_feature("KOKKOS","precision","mixed"))  mesg += " mixed";
1488     if (has_accelerator_feature("KOKKOS","precision","double")) mesg += " double";
1489     mesg += "\n";
1490   }
1491   if ((package.empty() || (package == "OPENMP")) && has_package("OPENMP")) {
1492     mesg += "OPENMP package API:";
1493     if (has_accelerator_feature("OPENMP","api","openmp"))   mesg += " OpenMP";
1494     if (has_accelerator_feature("OPENMP","api","serial"))   mesg += " Serial";
1495     mesg +=  "\nOPENMP package precision:";
1496     if (has_accelerator_feature("OPENMP","precision","single")) mesg += " single";
1497     if (has_accelerator_feature("OPENMP","precision","mixed"))  mesg += " mixed";
1498     if (has_accelerator_feature("OPENMP","precision","double")) mesg += " double";
1499     mesg += "\n";
1500   }
1501   if ((package.empty() || (package == "INTEL")) && has_package("INTEL")) {
1502     mesg += "INTEL package API:";
1503     if (has_accelerator_feature("INTEL","api","phi"))      mesg += " Phi";
1504     if (has_accelerator_feature("INTEL","api","openmp"))   mesg += " OpenMP";
1505     mesg +=  "\nINTEL package precision:";
1506     if (has_accelerator_feature("INTEL","precision","single")) mesg += " single";
1507     if (has_accelerator_feature("INTEL","precision","mixed"))  mesg += " mixed";
1508     if (has_accelerator_feature("INTEL","precision","double")) mesg += " double";
1509     mesg += "\n";
1510   }
1511   return mesg;
1512 }
1513 
1514 /* ---------------------------------------------------------------------- */
1515 
get_memory_info(double * meminfo)1516 void Info::get_memory_info(double *meminfo)
1517 {
1518     double bytes = 0;
1519     bytes += atom->memory_usage();
1520     bytes += neighbor->memory_usage();
1521     bytes += comm->memory_usage();
1522     bytes += update->memory_usage();
1523     bytes += force->memory_usage();
1524     bytes += modify->memory_usage();
1525     for (int i = 0; i < output->ndump; i++)
1526       bytes += output->dump[i]->memory_usage();
1527     meminfo[0] = bytes/1024.0/1024.0;
1528     meminfo[1] = 0;
1529     meminfo[2] = 0;
1530 
1531 #if defined(_WIN32)
1532     HANDLE phandle = GetCurrentProcess();
1533     PROCESS_MEMORY_COUNTERS_EX pmc;
1534     GetProcessMemoryInfo(phandle,(PROCESS_MEMORY_COUNTERS *)&pmc,sizeof(pmc));
1535     meminfo[1] = (double)pmc.PrivateUsage/1048576.0;
1536     meminfo[2] = (double)pmc.PeakWorkingSetSize/1048576.0;
1537 #else
1538 #if defined(__linux__)
1539 #if defined(__GLIBC__) && __GLIBC_PREREQ(2, 33)
1540     struct mallinfo2 mi;
1541     mi = mallinfo2();
1542 #else
1543     struct mallinfo mi;
1544     mi = mallinfo();
1545 #endif
1546     meminfo[1] = (double)mi.uordblks/1048576.0+(double)mi.hblkhd/1048576.0;
1547 #endif
1548     struct rusage ru;
1549     if (getrusage(RUSAGE_SELF, &ru) == 0)
1550       meminfo[2] = (double)ru.ru_maxrss/1024.0;
1551 #endif
1552 }
1553 
1554 /* ---------------------------------------------------------------------- */
1555 
get_variable_names(int & num)1556 char **Info::get_variable_names(int &num) {
1557     num = input->variable->nvar;
1558     return input->variable->names;
1559 }
1560