1 /* ----------------------------------------------------------------------
2    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
3    https://www.lammps.org/, Sandia National Laboratories
4    Steve Plimpton, sjplimp@sandia.gov
5 
6    Copyright (2003) Sandia Corporation.  Under the terms of Contract
7    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
8    certain rights in this software.  This software is distributed under
9    the GNU General Public License.
10 
11    See the README file in the top-level LAMMPS directory.
12 ------------------------------------------------------------------------- */
13 
14 /* ----------------------------------------------------------------------
15    Contributing author: Richard Berger (Temple U)
16 ------------------------------------------------------------------------- */
17 
18 #ifdef LAMMPS_ZSTD
19 
20 #include "dump_cfg_zstd.h"
21 
22 #include "atom.h"
23 #include "domain.h"
24 #include "error.h"
25 #include "file_writer.h"
26 #include "update.h"
27 
28 #include <cstring>
29 
30 using namespace LAMMPS_NS;
31 #define UNWRAPEXPAND 10.0
32 
DumpCFGZstd(LAMMPS * lmp,int narg,char ** arg)33 DumpCFGZstd::DumpCFGZstd(LAMMPS *lmp, int narg, char **arg) : DumpCFG(lmp, narg, arg)
34 {
35   if (!compressed) error->all(FLERR, "Dump cfg/zstd only writes compressed files");
36 }
37 
38 /* ---------------------------------------------------------------------- */
39 
~DumpCFGZstd()40 DumpCFGZstd::~DumpCFGZstd() {}
41 
42 /* ----------------------------------------------------------------------
43    generic opening of a dump file
44    ASCII or binary or compressed
45    some derived classes override this function
46 ------------------------------------------------------------------------- */
47 
openfile()48 void DumpCFGZstd::openfile()
49 {
50   // single file, already opened, so just return
51 
52   if (singlefile_opened) return;
53   if (multifile == 0) singlefile_opened = 1;
54 
55   // if one file per timestep, replace '*' with current timestep
56 
57   char *filecurrent = filename;
58   if (multiproc) filecurrent = multiname;
59 
60   if (multifile) {
61     char *filestar = filecurrent;
62     filecurrent = new char[strlen(filestar) + 16];
63     char *ptr = strchr(filestar, '*');
64     *ptr = '\0';
65     if (padflag == 0)
66       sprintf(filecurrent, "%s" BIGINT_FORMAT "%s", filestar, update->ntimestep, ptr + 1);
67     else {
68       char bif[8], pad[16];
69       strcpy(bif, BIGINT_FORMAT);
70       sprintf(pad, "%%s%%0%d%s%%s", padflag, &bif[1]);
71       sprintf(filecurrent, pad, filestar, update->ntimestep, ptr + 1);
72     }
73     *ptr = '*';
74     if (maxfiles > 0) {
75       if (numfiles < maxfiles) {
76         nameslist[numfiles] = utils::strdup(filecurrent);
77         ++numfiles;
78       } else {
79         if (remove(nameslist[fileidx]) != 0) {
80           error->warning(FLERR, "Could not delete {}", nameslist[fileidx]);
81         }
82         delete[] nameslist[fileidx];
83         nameslist[fileidx] = utils::strdup(filecurrent);
84         fileidx = (fileidx + 1) % maxfiles;
85       }
86     }
87   }
88 
89   // each proc with filewriter = 1 opens a file
90 
91   if (filewriter) {
92     if (append_flag) { error->one(FLERR, "dump cfg/zstd currently doesn't support append"); }
93 
94     try {
95       writer.open(filecurrent);
96     } catch (FileWriterException &e) {
97       error->one(FLERR, e.what());
98     }
99   }
100 
101   // delete string with timestep replaced
102 
103   if (multifile) delete[] filecurrent;
104 }
105 
106 /* ---------------------------------------------------------------------- */
107 
write_header(bigint n)108 void DumpCFGZstd::write_header(bigint n)
109 {
110   // set scale factor used by AtomEye for CFG viz
111   // default = 1.0
112   // for peridynamics, set to pre-computed PD scale factor
113   //   so PD particles mimic C atoms
114   // for unwrapped coords, set to UNWRAPEXPAND (10.0)
115   //   so molecules are not split across periodic box boundaries
116 
117   double scale = 1.0;
118   if (atom->peri_flag)
119     scale = atom->pdscale;
120   else if (unwrapflag == 1)
121     scale = UNWRAPEXPAND;
122 
123   std::string header = fmt::format("Number of particles = {}\n", n);
124   header += fmt::format("A = {0:g} Angstrom (basic length-scale)\n", scale);
125   header += fmt::format("H0(1,1) = {0:g} A\n", domain->xprd);
126   header += fmt::format("H0(1,2) = 0 A \n");
127   header += fmt::format("H0(1,3) = 0 A \n");
128   header += fmt::format("H0(2,1) = {0:g} A \n", domain->xy);
129   header += fmt::format("H0(2,2) = {0:g} A\n", domain->yprd);
130   header += fmt::format("H0(2,3) = 0 A \n");
131   header += fmt::format("H0(3,1) = {0:g} A \n", domain->xz);
132   header += fmt::format("H0(3,2) = {0:g} A \n", domain->yz);
133   header += fmt::format("H0(3,3) = {0:g} A\n", domain->zprd);
134   header += fmt::format(".NO_VELOCITY.\n");
135   header += fmt::format("entry_count = {}\n", nfield - 2);
136   for (int i = 0; i < nfield - 5; i++) header += fmt::format("auxiliary[{}] = {}\n", i, auxname[i]);
137 
138   writer.write(header.c_str(), header.length());
139 }
140 
141 /* ---------------------------------------------------------------------- */
142 
write_data(int n,double * mybuf)143 void DumpCFGZstd::write_data(int n, double *mybuf)
144 {
145   if (buffer_flag) {
146     writer.write(mybuf, n);
147   } else {
148     constexpr size_t VBUFFER_SIZE = 256;
149     char vbuffer[VBUFFER_SIZE];
150     if (unwrapflag == 0) {
151       int m = 0;
152       for (int i = 0; i < n; i++) {
153         for (int j = 0; j < size_one; j++) {
154           int written = 0;
155           if (j == 0) {
156             written = snprintf(vbuffer, VBUFFER_SIZE, "%f \n", mybuf[m]);
157           } else if (j == 1) {
158             written = snprintf(vbuffer, VBUFFER_SIZE, "%s \n", typenames[(int) mybuf[m]]);
159           } else if (j >= 2) {
160             if (vtype[j] == Dump::INT)
161               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], static_cast<int>(mybuf[m]));
162             else if (vtype[j] == Dump::DOUBLE)
163               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], mybuf[m]);
164             else if (vtype[j] == Dump::STRING)
165               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], typenames[(int) mybuf[m]]);
166             else if (vtype[j] == Dump::BIGINT)
167               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], static_cast<bigint>(mybuf[m]));
168           }
169           if (written > 0) {
170             writer.write(vbuffer, written);
171           } else if (written < 0) {
172             error->one(FLERR, "Error while writing dump cfg/gz output");
173           }
174           m++;
175         }
176         writer.write("\n", 1);
177       }
178     } else if (unwrapflag == 1) {
179       int m = 0;
180       for (int i = 0; i < n; i++) {
181         for (int j = 0; j < size_one; j++) {
182           int written = 0;
183           if (j == 0) {
184             written = snprintf(vbuffer, VBUFFER_SIZE, "%f \n", mybuf[m]);
185           } else if (j == 1) {
186             written = snprintf(vbuffer, VBUFFER_SIZE, "%s \n", typenames[(int) mybuf[m]]);
187           } else if (j >= 2 && j <= 4) {
188             double unwrap_coord = (mybuf[m] - 0.5) / UNWRAPEXPAND + 0.5;
189             written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], unwrap_coord);
190           } else if (j >= 5) {
191             if (vtype[j] == Dump::INT)
192               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], static_cast<int>(mybuf[m]));
193             else if (vtype[j] == Dump::DOUBLE)
194               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], mybuf[m]);
195             else if (vtype[j] == Dump::STRING)
196               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], typenames[(int) mybuf[m]]);
197             else if (vtype[j] == Dump::BIGINT)
198               written = snprintf(vbuffer, VBUFFER_SIZE, vformat[j], static_cast<bigint>(mybuf[m]));
199           }
200           if (written > 0) {
201             writer.write(vbuffer, written);
202           } else if (written < 0) {
203             error->one(FLERR, "Error while writing dump cfg/gz output");
204           }
205           m++;
206         }
207         writer.write("\n", 1);
208       }
209     }
210   }
211 }
212 
213 /* ---------------------------------------------------------------------- */
214 
write()215 void DumpCFGZstd::write()
216 {
217   DumpCFG::write();
218   if (filewriter) {
219     if (multifile) {
220       writer.close();
221     } else {
222       if (flush_flag && writer.isopen()) { writer.flush(); }
223     }
224   }
225 }
226 
227 /* ---------------------------------------------------------------------- */
228 
modify_param(int narg,char ** arg)229 int DumpCFGZstd::modify_param(int narg, char **arg)
230 {
231   int consumed = DumpCFG::modify_param(narg, arg);
232   if (consumed == 0) {
233     try {
234       if (strcmp(arg[0], "checksum") == 0) {
235         if (narg < 2) error->all(FLERR, "Illegal dump_modify command");
236         if (strcmp(arg[1], "yes") == 0)
237           writer.setChecksum(true);
238         else if (strcmp(arg[1], "no") == 0)
239           writer.setChecksum(false);
240         else
241           error->all(FLERR, "Illegal dump_modify command");
242         return 2;
243       } else if (strcmp(arg[0], "compression_level") == 0) {
244         if (narg < 2) error->all(FLERR, "Illegal dump_modify command");
245         int compression_level = utils::inumeric(FLERR, arg[1], false, lmp);
246         writer.setCompressionLevel(compression_level);
247         return 2;
248       }
249     } catch (FileWriterException &e) {
250       error->one(FLERR, e.what());
251     }
252   }
253   return consumed;
254 }
255 #endif
256