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 #include "dump_image.h"
16 
17 #include "atom.h"
18 #include "atom_vec.h"
19 #include "atom_vec_body.h"
20 #include "atom_vec_line.h"
21 #include "atom_vec_tri.h"
22 #include "body.h"
23 #include "comm.h"
24 #include "domain.h"
25 #include "error.h"
26 #include "fix.h"
27 #include "force.h"
28 #include "image.h"
29 #include "input.h"
30 #include "math_const.h"
31 #include "math_extra.h"
32 #include "memory.h"
33 #include "modify.h"
34 #include "molecule.h"
35 #include "tokenizer.h"
36 #include "variable.h"
37 
38 #include <cmath>
39 #include <cctype>
40 #include <cstring>
41 
42 using namespace LAMMPS_NS;
43 using namespace MathConst;
44 
45 #define BIG 1.0e20
46 
47 enum{NUMERIC,ATOM,TYPE,ELEMENT,ATTRIBUTE};
48 enum{SPHERE,LINE,TRI};           // also in some Body and Fix child classes
49 enum{STATIC,DYNAMIC};
50 enum{NO,YES};
51 
52 /* ---------------------------------------------------------------------- */
53 
DumpImage(LAMMPS * lmp,int narg,char ** arg)54 DumpImage::DumpImage(LAMMPS *lmp, int narg, char **arg) :
55   DumpCustom(lmp, narg, arg), thetastr(nullptr), phistr(nullptr), cxstr(nullptr),
56   cystr(nullptr), czstr(nullptr), upxstr(nullptr), upystr(nullptr), upzstr(nullptr),
57   zoomstr(nullptr), diamtype(nullptr), diamelement(nullptr),
58   bdiamtype(nullptr), colortype(nullptr), colorelement(nullptr), bcolortype(nullptr),
59   avec_line(nullptr), avec_tri(nullptr), avec_body(nullptr), fixptr(nullptr), image(nullptr),
60   chooseghost(nullptr), bufcopy(nullptr)
61 {
62   if (binary || multiproc) error->all(FLERR,"Invalid dump image filename");
63 
64   // force binary flag on to avoid corrupted output on Windows
65 
66   binary = 1;
67   multifile_override = 0;
68 
69   // set filetype based on filename suffix
70 
71   int n = strlen(filename);
72   if (strlen(filename) > 4 && strcmp(&filename[n-4],".jpg") == 0)
73     filetype = JPG;
74   else if (strlen(filename) > 4 && strcmp(&filename[n-4],".JPG") == 0)
75     filetype = JPG;
76   else if (strlen(filename) > 5 && strcmp(&filename[n-5],".jpeg") == 0)
77     filetype = JPG;
78   else if (strlen(filename) > 5 && strcmp(&filename[n-5],".JPEG") == 0)
79     filetype = JPG;
80   else if (strlen(filename) > 4 && strcmp(&filename[n-4],".png") == 0)
81     filetype = PNG;
82   else if (strlen(filename) > 4 && strcmp(&filename[n-4],".PNG") == 0)
83     filetype = PNG;
84   else filetype = PPM;
85 
86 #ifndef LAMMPS_JPEG
87   if (filetype == JPG)
88     error->all(FLERR,"Support for writing images in JPEG format not included");
89 #endif
90 #ifndef LAMMPS_PNG
91   if (filetype == PNG)
92     error->all(FLERR,"Support for writing images in PNG format not included");
93 #endif
94 
95   // atom color,diameter settings
96 
97   if (nfield != 2) error->all(FLERR,"Illegal dump image command");
98 
99   acolor = ATTRIBUTE;
100   if (strcmp(arg[5],"type") == 0) acolor = TYPE;
101   else if (strcmp(arg[5],"element") == 0) acolor = ELEMENT;
102 
103   adiam = ATTRIBUTE;
104   if (strcmp(arg[6],"type") == 0) adiam = TYPE;
105   else if (strcmp(arg[6],"element") == 0) adiam = ELEMENT;
106 
107   // create Image class with single colormap for atoms
108   // change defaults for 2d
109 
110   image = new Image(lmp,1);
111 
112   if (domain->dimension == 2) {
113     image->theta = 0.0;
114     image->phi = 0.0;
115     image->up[0] = 0.0; image->up[1] = 1.0; image->up[2] = 0.0;
116   }
117 
118   // set defaults for optional args
119 
120   atomflag = YES;
121   lineflag = triflag = bodyflag = fixflag = NO;
122   if (atom->nbondtypes == 0) bondflag = NO;
123   else {
124     bondflag = YES;
125     bcolor = ATOM;
126     bdiam = NUMERIC;
127     bdiamvalue = 0.5;
128   }
129   char *fixID = nullptr;
130 
131   thetastr = phistr = nullptr;
132   cflag = STATIC;
133   cx = cy = cz = 0.5;
134   cxstr = cystr = czstr = nullptr;
135 
136   upxstr = upystr = upzstr = nullptr;
137   zoomstr = nullptr;
138   boxflag = YES;
139   boxdiam = 0.02;
140   axesflag = NO;
141   subboxflag = NO;
142 
143   // parse optional args
144 
145   int iarg = ioptional;
146   while (iarg < narg) {
147     if (strcmp(arg[iarg],"atom") == 0) {
148       if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
149       if (strcmp(arg[iarg+1],"yes") == 0) atomflag = YES;
150       else if (strcmp(arg[iarg+1],"no") == 0) atomflag = NO;
151       else error->all(FLERR,"Illegal dump image command");
152       iarg += 2;
153 
154     } else if (strcmp(arg[iarg],"adiam") == 0) {
155       if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
156       adiam = NUMERIC;
157       adiamvalue = utils::numeric(FLERR,arg[iarg+1],false,lmp);
158       if (adiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command");
159       iarg += 2;
160 
161     } else if (strcmp(arg[iarg],"bond") == 0) {
162       if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
163       if (atom->nbondtypes == 0)
164         error->all(FLERR,"Dump image bond not allowed with no bond types");
165       bondflag = YES;
166       if (strcmp(arg[iarg+1],"none") == 0) bondflag = NO;
167       else if (strcmp(arg[iarg+1],"atom") == 0) bcolor = ATOM;
168       else if (strcmp(arg[iarg+1],"type") == 0) bcolor = TYPE;
169       else error->all(FLERR,"Illegal dump image command");
170       if (!islower(arg[iarg+2][0])) {
171           bdiam = NUMERIC;
172           bdiamvalue = utils::numeric(FLERR,arg[iarg+2],false,lmp);
173           if (bdiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command");
174       } else if (strcmp(arg[iarg+2],"atom") == 0) bdiam = ATOM;
175       else if (strcmp(arg[iarg+2],"type") == 0) bdiam = TYPE;
176       else if (strcmp(arg[iarg+2],"none") == 0) bondflag = NO;
177       else error->all(FLERR,"Illegal dump image command");
178       iarg += 3;
179 
180 
181     } else if (strcmp(arg[iarg],"line") == 0) {
182       if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
183       lineflag = YES;
184       if (strcmp(arg[iarg+1],"type") == 0) lcolor = TYPE;
185       else error->all(FLERR,"Illegal dump image command");
186       ldiam = NUMERIC;
187       ldiamvalue = utils::numeric(FLERR,arg[iarg+2],false,lmp);
188       iarg += 3;
189 
190     } else if (strcmp(arg[iarg],"tri") == 0) {
191       if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command");
192       triflag = YES;
193       if (strcmp(arg[iarg+1],"type") == 0) tcolor = TYPE;
194       else error->all(FLERR,"Illegal dump image command");
195       tstyle = utils::inumeric(FLERR,arg[iarg+2],false,lmp);
196       tdiamvalue = utils::numeric(FLERR,arg[iarg+3],false,lmp);
197       iarg += 4;
198 
199     } else if (strcmp(arg[iarg],"body") == 0) {
200       if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command");
201       bodyflag = YES;
202       if (strcmp(arg[iarg+1],"type") == 0) bodycolor = TYPE;
203       else error->all(FLERR,"Illegal dump image command");
204       bodyflag1 = utils::numeric(FLERR,arg[iarg+2],false,lmp);
205       bodyflag2 = utils::numeric(FLERR,arg[iarg+3],false,lmp);
206       iarg += 4;
207 
208     } else if (strcmp(arg[iarg],"fix") == 0) {
209       if (iarg+5 > narg) error->all(FLERR,"Illegal dump image command");
210       fixflag = YES;
211       fixID = arg[iarg+1];
212       if (strcmp(arg[iarg+2],"type") == 0) fixcolor = TYPE;
213       else error->all(FLERR,"Illegal dump image command");
214       fixflag1 = utils::numeric(FLERR,arg[iarg+3],false,lmp);
215       fixflag2 = utils::numeric(FLERR,arg[iarg+4],false,lmp);
216       iarg += 5;
217 
218     } else if (strcmp(arg[iarg],"size") == 0) {
219       if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
220       int width = utils::inumeric(FLERR,arg[iarg+1],false,lmp);
221       int height = utils::inumeric(FLERR,arg[iarg+2],false,lmp);
222       if (width <= 0 || height <= 0)
223         error->all(FLERR,"Illegal dump image command");
224       image->width = width;
225       image->height = height;
226       iarg += 3;
227 
228     } else if (strcmp(arg[iarg],"view") == 0) {
229       if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
230       if (utils::strmatch(arg[iarg+1],"^v_")) {
231         thetastr = utils::strdup(arg[iarg+1]+2);
232       } else {
233         double theta = utils::numeric(FLERR,arg[iarg+1],false,lmp);
234         if (theta < 0.0 || theta > 180.0)
235           error->all(FLERR,"Invalid dump image theta value");
236         theta *= MY_PI/180.0;
237         image->theta = theta;
238       }
239       if (utils::strmatch(arg[iarg+2],"^v_")) {
240         phistr = utils::strdup(arg[iarg+2]+2);
241       } else {
242         double phi = utils::numeric(FLERR,arg[iarg+2],false,lmp);
243         phi *= MY_PI/180.0;
244         image->phi = phi;
245       }
246       iarg += 3;
247 
248     } else if (strcmp(arg[iarg],"center") == 0) {
249       if (iarg+5 > narg) error->all(FLERR,"Illegal dump image command");
250       if (strcmp(arg[iarg+1],"s") == 0) cflag = STATIC;
251       else if (strcmp(arg[iarg+1],"d") == 0) cflag = DYNAMIC;
252       else error->all(FLERR,"Illegal dump image command");
253       if (utils::strmatch(arg[iarg+2],"^v_")) {
254         cxstr = utils::strdup(arg[iarg+2]+2);
255         cflag = DYNAMIC;
256       } else cx = utils::numeric(FLERR,arg[iarg+2],false,lmp);
257       if (utils::strmatch(arg[iarg+3],"^v_")) {
258         cystr = utils::strdup(arg[iarg+3]+2);
259         cflag = DYNAMIC;
260       } else cy = utils::numeric(FLERR,arg[iarg+3],false,lmp);
261       if (utils::strmatch(arg[iarg+4],"^v_")) {
262         czstr = utils::strdup(arg[iarg+4]+2);
263         cflag = DYNAMIC;
264       } else cz = utils::numeric(FLERR,arg[iarg+4],false,lmp);
265       iarg += 5;
266 
267     } else if (strcmp(arg[iarg],"up") == 0) {
268       if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command");
269       if (utils::strmatch(arg[iarg+1],"^v_")) {
270         upxstr = utils::strdup(arg[iarg+1]+2);
271       } else image->up[0] = utils::numeric(FLERR,arg[iarg+1],false,lmp);
272       if (utils::strmatch(arg[iarg+2],"^v_")) {
273         upystr = utils::strdup(arg[iarg+2]+2);
274       } else image->up[1] = utils::numeric(FLERR,arg[iarg+2],false,lmp);
275       if (utils::strmatch(arg[iarg+3],"^v_")) {
276         upzstr = utils::strdup(arg[iarg+3]+2);
277       } else image->up[2] = utils::numeric(FLERR,arg[iarg+3],false,lmp);
278       iarg += 4;
279 
280     } else if (strcmp(arg[iarg],"zoom") == 0) {
281       if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
282       if (utils::strmatch(arg[iarg+1],"^v_")) {
283         zoomstr = utils::strdup(arg[iarg+1]+2);
284       } else {
285         double zoom = utils::numeric(FLERR,arg[iarg+1],false,lmp);
286         if (zoom <= 0.0) error->all(FLERR,"Illegal dump image command");
287         image->zoom = zoom;
288       }
289       iarg += 2;
290 
291     } else if (strcmp(arg[iarg],"box") == 0) {
292       if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
293       if (strcmp(arg[iarg+1],"yes") == 0) boxflag = YES;
294       else if (strcmp(arg[iarg+1],"no") == 0) boxflag = NO;
295       else error->all(FLERR,"Illegal dump image command");
296       boxdiam = utils::numeric(FLERR,arg[iarg+2],false,lmp);
297       if (boxdiam < 0.0) error->all(FLERR,"Illegal dump image command");
298       iarg += 3;
299 
300     } else if (strcmp(arg[iarg],"axes") == 0) {
301       if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
302       if (strcmp(arg[iarg+1],"yes") == 0) axesflag = YES;
303       else if (strcmp(arg[iarg+1],"no") == 0) axesflag = NO;
304       else error->all(FLERR,"Illegal dump image command");
305       axeslen = utils::numeric(FLERR,arg[iarg+2],false,lmp);
306       axesdiam = utils::numeric(FLERR,arg[iarg+3],false,lmp);
307       if (axeslen < 0.0 || axesdiam < 0.0)
308         error->all(FLERR,"Illegal dump image command");
309       iarg += 4;
310 
311     } else if (strcmp(arg[iarg],"subbox") == 0) {
312       if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
313       if (strcmp(arg[iarg+1],"yes") == 0) subboxflag = YES;
314       else if (strcmp(arg[iarg+1],"no") == 0) subboxflag = NO;
315       else error->all(FLERR,"Illegal dump image command");
316       subboxdiam = utils::numeric(FLERR,arg[iarg+2],false,lmp);
317       if (subboxdiam < 0.0) error->all(FLERR,"Illegal dump image command");
318       iarg += 3;
319 
320     } else if (strcmp(arg[iarg],"shiny") == 0) {
321       if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
322       double shiny = utils::numeric(FLERR,arg[iarg+1],false,lmp);
323       if (shiny < 0.0 || shiny > 1.0)
324         error->all(FLERR,"Illegal dump image command");
325       image->shiny = shiny;
326       iarg += 2;
327 
328     } else if (strcmp(arg[iarg],"ssao") == 0) {
329       if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command");
330       if (strcmp(arg[iarg+1],"yes") == 0) image->ssao = YES;
331       else if (strcmp(arg[iarg+1],"no") == 0) image->ssao = NO;
332       else error->all(FLERR,"Illegal dump image command");
333       int seed = utils::inumeric(FLERR,arg[iarg+2],false,lmp);
334       if (seed <= 0) error->all(FLERR,"Illegal dump image command");
335       image->seed = seed;
336       double ssaoint = utils::numeric(FLERR,arg[iarg+3],false,lmp);
337       if (ssaoint < 0.0 || ssaoint > 1.0)
338         error->all(FLERR,"Illegal dump image command");
339       image->ssaoint = ssaoint;
340       iarg += 4;
341 
342     } else error->all(FLERR,"Illegal dump image command");
343   }
344 
345   // error checks and setup for lineflag, triflag, bodyflag, fixflag
346 
347   if (lineflag) {
348     avec_line = (AtomVecLine *) atom->style_match("line");
349     if (!avec_line)
350       error->all(FLERR,"Dump image line requires atom style line");
351   }
352   if (triflag) {
353     avec_tri = (AtomVecTri *) atom->style_match("tri");
354     if (!avec_tri)
355       error->all(FLERR,"Dump image tri requires atom style tri");
356   }
357   if (bodyflag) {
358     avec_body = (AtomVecBody *) atom->style_match("body");
359     if (!avec_body)
360       error->all(FLERR,"Dump image body yes requires atom style body");
361   }
362 
363   extraflag = 0;
364   if (lineflag || triflag || bodyflag) extraflag = 1;
365 
366   if (fixflag) {
367     int ifix = modify->find_fix(fixID);
368     if (ifix < 0) error->all(FLERR,"Fix ID for dump image does not exist");
369     fixptr = modify->fix[ifix];
370   }
371 
372   // allocate image buffer now that image size is known
373 
374   image->buffers();
375 
376   // communication needed for bonds colored by atoms
377 
378   if (bondflag) {
379     if (bcolor == ATOM || bdiam == ATOM) comm_forward = 3;
380     else comm_forward = 1;
381   }
382 
383   // additional defaults for dump_modify options
384 
385   diamtype = new double[ntypes+1];
386   diamelement = new double[ntypes+1];
387   colortype = new double*[ntypes+1];
388   colorelement = new double*[ntypes+1];
389 
390   for (int i = 1; i <= ntypes; i++) {
391     diamtype[i] = 1.0;
392     if (i % 6 == 1) colortype[i] = image->color2rgb("red");
393     else if (i % 6 == 2) colortype[i] = image->color2rgb("green");
394     else if (i % 6 == 3) colortype[i] = image->color2rgb("blue");
395     else if (i % 6 == 4) colortype[i] = image->color2rgb("yellow");
396     else if (i % 6 == 5) colortype[i] = image->color2rgb("aqua");
397     else if (i % 6 == 0) colortype[i] = image->color2rgb("cyan");
398   }
399 
400   if (bondflag) {
401     bdiamtype = new double[atom->nbondtypes+1];
402     bcolortype = new double*[atom->nbondtypes+1];
403     for (int i = 1; i <= atom->nbondtypes; i++) {
404       bdiamtype[i] = 0.5;
405       if (i % 6 == 1) bcolortype[i] = image->color2rgb("red");
406       else if (i % 6 == 2) bcolortype[i] = image->color2rgb("green");
407       else if (i % 6 == 3) bcolortype[i] = image->color2rgb("blue");
408       else if (i % 6 == 4) bcolortype[i] = image->color2rgb("yellow");
409       else if (i % 6 == 5) bcolortype[i] = image->color2rgb("aqua");
410       else if (i % 6 == 0) bcolortype[i] = image->color2rgb("cyan");
411     }
412   } else {
413     bdiamtype = nullptr;
414     bcolortype = nullptr;
415   }
416 
417   // viewflag = DYNAMIC if any view parameter is dynamic
418 
419   viewflag = STATIC;
420   if (thetastr || phistr || cflag == DYNAMIC ||
421       upxstr || upystr || upzstr || zoomstr) viewflag = DYNAMIC;
422 
423   box_bounds();
424   if (cflag == STATIC) box_center();
425   if (viewflag == STATIC) view_params();
426 
427   // local data
428 
429   maxbufcopy = 0;
430   chooseghost = nullptr;
431   bufcopy = nullptr;
432 }
433 
434 /* ---------------------------------------------------------------------- */
435 
~DumpImage()436 DumpImage::~DumpImage()
437 {
438   delete image;
439 
440   delete [] diamtype;
441   delete [] diamelement;
442   delete [] colortype;
443   delete [] colorelement;
444   delete [] bdiamtype;
445   delete [] bcolortype;
446   memory->destroy(chooseghost);
447   memory->destroy(bufcopy);
448 }
449 
450 /* ---------------------------------------------------------------------- */
451 
init_style()452 void DumpImage::init_style()
453 {
454   if (multifile == 0 && !multifile_override)
455     error->all(FLERR,"Dump image requires one snapshot per file");
456   if (sort_flag) error->all(FLERR,"Dump image cannot perform sorting");
457 
458   DumpCustom::init_style();
459 
460   // check variables
461 
462   if (thetastr) {
463     thetavar = input->variable->find(thetastr);
464     if (thetavar < 0)
465       error->all(FLERR,"Variable name for dump image theta does not exist");
466     if (!input->variable->equalstyle(thetavar))
467       error->all(FLERR,"Variable for dump image theta is invalid style");
468   }
469   if (phistr) {
470     phivar = input->variable->find(phistr);
471     if (phivar < 0)
472       error->all(FLERR,"Variable name for dump image phi does not exist");
473     if (!input->variable->equalstyle(phivar))
474       error->all(FLERR,"Variable for dump image phi is invalid style");
475   }
476   if (cxstr) {
477     cxvar = input->variable->find(cxstr);
478     if (cxvar < 0)
479       error->all(FLERR,"Variable name for dump image center does not exist");
480     if (!input->variable->equalstyle(cxvar))
481       error->all(FLERR,"Variable for dump image center is invalid style");
482   }
483   if (cystr) {
484     cyvar = input->variable->find(cystr);
485     if (cyvar < 0)
486       error->all(FLERR,"Variable name for dump image center does not exist");
487     if (!input->variable->equalstyle(cyvar))
488       error->all(FLERR,"Variable for dump image center is invalid style");
489   }
490   if (czstr) {
491     czvar = input->variable->find(czstr);
492     if (czvar < 0)
493       error->all(FLERR,"Variable name for dump image center does not exist");
494     if (!input->variable->equalstyle(czvar))
495       error->all(FLERR,"Variable for dump image center is invalid style");
496   }
497   if (upxstr) {
498     upxvar = input->variable->find(upxstr);
499     if (upxvar < 0)
500       error->all(FLERR,"Variable name for dump image center does not exist");
501     if (!input->variable->equalstyle(upxvar))
502       error->all(FLERR,"Variable for dump image center is invalid style");
503   }
504   if (upystr) {
505     upyvar = input->variable->find(upystr);
506     if (upyvar < 0)
507       error->all(FLERR,"Variable name for dump image center does not exist");
508     if (!input->variable->equalstyle(upyvar))
509       error->all(FLERR,"Variable for dump image center is invalid style");
510   }
511   if (upzstr) {
512     upzvar = input->variable->find(upzstr);
513     if (upzvar < 0)
514       error->all(FLERR,"Variable name for dump image center does not exist");
515     if (!input->variable->equalstyle(upzvar))
516       error->all(FLERR,"Variable for dump image center is invalid style");
517   }
518   if (zoomstr) {
519     zoomvar = input->variable->find(zoomstr);
520     if (zoomvar < 0)
521       error->all(FLERR,"Variable name for dump image zoom does not exist");
522     if (!input->variable->equalstyle(zoomvar))
523       error->all(FLERR,"Variable for dump image zoom is invalid style");
524   }
525 
526   // set up type -> element mapping
527 
528   if (atomflag && acolor == ELEMENT) {
529     for (int i = 1; i <= ntypes; i++) {
530       colorelement[i] = image->element2color(typenames[i]);
531       if (colorelement[i] == nullptr)
532         error->all(FLERR,"Invalid dump image element name");
533     }
534   }
535 
536   if (atomflag && adiam == ELEMENT) {
537     for (int i = 1; i <= ntypes; i++) {
538       diamelement[i] = image->element2diam(typenames[i]);
539       if (diamelement[i] == 0.0)
540         error->all(FLERR,"Invalid dump image element name");
541     }
542   }
543 }
544 
545 /* ---------------------------------------------------------------------- */
546 
write()547 void DumpImage::write()
548 {
549   // open new file
550 
551   openfile();
552 
553   // reset box center and view parameters if dynamic
554 
555   box_bounds();
556   if (cflag == DYNAMIC) box_center();
557   if (viewflag == DYNAMIC) view_params();
558 
559   // nme = # of atoms this proc will contribute to dump
560 
561   nme = count();
562 
563   if (nme > maxbuf) {
564     maxbuf = nme;
565     memory->destroy(buf);
566     memory->create(buf,maxbuf*size_one,"dump:buf");
567   }
568 
569   // pack buf with color & diameter
570 
571   pack(nullptr);
572 
573   // set minmax color range if using dynamic atom color map
574 
575   if (acolor == ATTRIBUTE && image->map_dynamic(0)) {
576     double two[2],twoall[2];
577     double lo = BIG;
578     double hi = -BIG;
579     int m = 0;
580     for (int i = 0; i < nchoose; i++) {
581       lo = MIN(lo,buf[m]);
582       hi = MAX(hi,buf[m]);
583       m += size_one;
584     }
585     two[0] = -lo;
586     two[1] = hi;
587     MPI_Allreduce(two,twoall,2,MPI_DOUBLE,MPI_MAX,world);
588     int flag = image->map_minmax(0,-twoall[0],twoall[1]);
589     if (flag) error->all(FLERR,"Invalid color map min/max values");
590   }
591 
592   // create image on each proc, then merge them
593 
594   image->clear();
595   create_image();
596   image->merge();
597 
598   // write image file
599 
600   if (me == 0) {
601     if (filetype == JPG) image->write_JPG(fp);
602     else if (filetype == PNG) image->write_PNG(fp);
603     else image->write_PPM(fp);
604     if (multifile) {
605       fclose(fp);
606       fp = nullptr;
607     }
608   }
609 }
610 
611 /* ----------------------------------------------------------------------
612    simulation box bounds
613 ------------------------------------------------------------------------- */
614 
box_bounds()615 void DumpImage::box_bounds()
616 {
617   if (domain->triclinic == 0) {
618     boxxlo = domain->boxlo[0];
619     boxxhi = domain->boxhi[0];
620     boxylo = domain->boxlo[1];
621     boxyhi = domain->boxhi[1];
622     boxzlo = domain->boxlo[2];
623     boxzhi = domain->boxhi[2];
624   } else {
625     boxxlo = domain->boxlo_bound[0];
626     boxxhi = domain->boxhi_bound[0];
627     boxylo = domain->boxlo_bound[1];
628     boxyhi = domain->boxhi_bound[1];
629     boxzlo = domain->boxlo_bound[2];
630     boxzhi = domain->boxhi_bound[2];
631     boxxy = domain->xy;
632     boxxz = domain->xz;
633     boxyz = domain->yz;
634   }
635 }
636 
637 /* ----------------------------------------------------------------------
638    reset view parameters
639    called once from constructor if view is STATIC
640    called every snapshot from write() if view is DYNAMIC
641 ------------------------------------------------------------------------- */
642 
box_center()643 void DumpImage::box_center()
644 {
645   if (cxstr) cx = input->variable->compute_equal(cxvar);
646   if (cystr) cy = input->variable->compute_equal(cyvar);
647   if (czstr) cz = input->variable->compute_equal(czvar);
648 
649   image->xctr = boxxlo + cx*(boxxhi-boxxlo);
650   image->yctr = boxylo + cy*(boxyhi-boxylo);
651   image->zctr = boxzlo + cz*(boxzhi-boxzlo);
652 }
653 
654 /* ----------------------------------------------------------------------
655    reset view parameters in Image class
656    called once from constructor if view is STATIC
657    called every snapshot from write() if view is DYNAMIC
658 ------------------------------------------------------------------------- */
659 
view_params()660 void DumpImage::view_params()
661 {
662   // view direction theta and phi
663 
664   if (thetastr) {
665     double theta = input->variable->compute_equal(thetavar);
666     if (theta < 0.0 || theta > 180.0)
667       error->all(FLERR,"Invalid dump image theta value");
668     theta *= MY_PI/180.0;
669     image->theta = theta;
670   }
671 
672   if (phistr) {
673     double phi = input->variable->compute_equal(phivar);
674     phi *= MY_PI/180.0;
675     image->phi = phi;
676   }
677 
678   // up vector
679 
680   if (upxstr) image->up[0] = input->variable->compute_equal(upxvar);
681   if (upystr) image->up[1] = input->variable->compute_equal(upyvar);
682   if (upzstr) image->up[2] = input->variable->compute_equal(upzvar);
683 
684   // zoom
685 
686   if (zoomstr) image->zoom = input->variable->compute_equal(zoomvar);
687   if (image->zoom <= 0.0) error->all(FLERR,"Invalid dump image zoom value");
688 
689   // remainder of view setup is internal to Image class
690 
691   image->view_params(boxxlo,boxxhi,boxylo,boxyhi,boxzlo,boxzhi);
692 }
693 
694 /* ----------------------------------------------------------------------
695    create image for atoms on this proc
696    every pixel has depth
697 ------------------------------------------------------------------------- */
698 
create_image()699 void DumpImage::create_image()
700 {
701   int i,j,k,m,n,itype,atom1,atom2,imol,iatom,btype,ibonus,drawflag;
702   tagint tagprev;
703   double diameter,delx,dely,delz;
704   int *bodyvec,*fixvec;
705   double **bodyarray,**fixarray;
706   double *color,*color1,*color2;
707   double *p1,*p2,*p3;
708   double xmid[3],pt1[3],pt2[3],pt3[3];
709   double mat[3][3];
710 
711   // render my atoms
712 
713   if (atomflag) {
714     double **x = atom->x;
715     int *line = atom->line;
716     int *tri = atom->tri;
717     int *body = atom->body;
718 
719     m = 0;
720     for (i = 0; i < nchoose; i++) {
721       j = clist[i];
722 
723       if (acolor == TYPE) {
724         itype = static_cast<int> (buf[m]);
725         color = colortype[itype];
726       } else if (acolor == ELEMENT) {
727         itype = static_cast<int> (buf[m]);
728         color = colorelement[itype];
729       } else if (acolor == ATTRIBUTE) {
730         color = image->map_value2color(0,buf[m]);
731       } else color = image->color2rgb("white");
732 
733       if (adiam == NUMERIC) {
734         diameter = adiamvalue;
735       } else if (adiam == TYPE) {
736         itype = static_cast<int> (buf[m+1]);
737         diameter = diamtype[itype];
738       } else if (adiam == ELEMENT) {
739         itype = static_cast<int> (buf[m+1]);
740         diameter = diamelement[itype];
741       } else if (adiam == ATTRIBUTE) {
742         diameter = buf[m+1];
743       }
744 
745       // do not draw if line,tri,body keywords enabled and atom is one of those
746 
747       drawflag = 1;
748       if (extraflag) {
749         if (lineflag && line[j] >= 0) drawflag = 0;
750         if (triflag && tri[j] >= 0) drawflag = 0;
751         if (bodyflag && body[j] >= 0) drawflag = 0;
752       }
753 
754       if (drawflag) image->draw_sphere(x[j],color,diameter);
755 
756       m += size_one;
757     }
758   }
759 
760   // render atoms that are lines
761 
762   if (lineflag) {
763     double length,theta,dx,dy;
764     double **x = atom->x;
765     int *line = atom->line;
766     int *type = atom->type;
767 
768     for (i = 0; i < nchoose; i++) {
769       j = clist[i];
770       if (line[j] < 0) continue;
771 
772       if (lcolor == TYPE) {
773         color = colortype[type[j]];
774       }
775 
776       if (ldiam == NUMERIC) {
777         diameter = ldiamvalue;
778       }
779 
780       length = avec_line->bonus[line[j]].length;
781       theta = avec_line->bonus[line[j]].theta;
782       dx = 0.5*length*cos(theta);
783       dy = 0.5*length*sin(theta);
784 
785       pt1[0] = x[j][0] + dx;
786       pt1[1] = x[j][1] + dy;
787       pt1[2] = 0.0;
788       pt2[0] = x[j][0] - dx;
789       pt2[1] = x[j][1] - dy;
790       pt2[2] = 0.0;
791 
792       image->draw_cylinder(pt1,pt2,color,ldiamvalue,3);
793     }
794   }
795 
796   // render atoms that are triangles
797   // tstyle = 1 for tri only, 2 for edges only, 3 for both
798 
799   if (triflag) {
800     int tridraw = 1;
801     if (tstyle == 2) tridraw = 0;
802     int edgedraw = 1;
803     if (tstyle == 1) edgedraw = 0;
804 
805     double **x = atom->x;
806     int *tri = atom->tri;
807     int *type = atom->type;
808 
809     for (i = 0; i < nchoose; i++) {
810       j = clist[i];
811       if (tri[j] < 0) continue;
812 
813       if (tcolor == TYPE) {
814         color = colortype[type[j]];
815       }
816 
817       MathExtra::quat_to_mat(avec_tri->bonus[tri[i]].quat,mat);
818       MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c1,pt1);
819       MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c2,pt2);
820       MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c3,pt3);
821       MathExtra::add3(pt1,x[i],pt1);
822       MathExtra::add3(pt2,x[i],pt2);
823       MathExtra::add3(pt3,x[i],pt3);
824 
825       if (tridraw) image->draw_triangle(pt1,pt2,pt3,color);
826       if (edgedraw) {
827         image->draw_cylinder(pt1,pt2,color,tdiamvalue,3);
828         image->draw_cylinder(pt2,pt3,color,tdiamvalue,3);
829         image->draw_cylinder(pt3,pt1,color,tdiamvalue,3);
830       }
831     }
832   }
833 
834   // render atoms that are bodies
835 
836   if (bodyflag) {
837     Body *bptr = avec_body->bptr;
838     int *body = atom->body;
839 
840     m = 0;
841     for (i = 0; i < nchoose; i++) {
842       j = clist[i];
843       if (body[j] < 0) continue;
844 
845       if (bodycolor == TYPE) {
846         itype = static_cast<int> (buf[m]);
847         color = colortype[itype];
848       }
849 
850       ibonus = body[i];
851       n = bptr->image(ibonus,bodyflag1,bodyflag2,bodyvec,bodyarray);
852       for (k = 0; k < n; k++) {
853         if (bodyvec[k] == SPHERE)
854           image->draw_sphere(bodyarray[k],color,bodyarray[k][3]);
855         else if (bodyvec[k] == LINE)
856           image->draw_cylinder(&bodyarray[k][0],&bodyarray[k][3],
857                                color,bodyarray[k][6],3);
858       }
859 
860       m += size_one;
861     }
862   }
863 
864   // render bonds for my atoms
865   // both atoms in bond must be selected for bond to be rendered
866   // if newton_bond is off, only render bond once
867   // render bond in 2 pieces if crosses periodic boundary
868   // if bond is deleted (type = 0), do not render
869   // if bond is turned off (type < 0), still render
870 
871   if (bondflag) {
872     double **x = atom->x;
873     tagint *tag = atom->tag;
874     tagint **bond_atom = atom->bond_atom;
875     int **bond_type = atom->bond_type;
876     int *num_bond = atom->num_bond;
877     int *molindex = atom->molindex;
878     int *molatom = atom->molatom;
879     int *type = atom->type;
880     int nlocal = atom->nlocal;
881     int newton_bond = force->newton_bond;
882     int molecular = atom->molecular;
883     Molecule **onemols = atom->avec->onemols;
884 
885     // communicate choose flag for ghost atoms to know if they are selected
886     // if bcolor/bdiam = ATOM, setup bufcopy to comm atom color/diam attributes
887 
888     if (atom->nmax > maxbufcopy) {
889       maxbufcopy = atom->nmax;
890       memory->destroy(chooseghost);
891       memory->create(chooseghost,maxbufcopy,"dump:chooseghost");
892       if (comm_forward == 3) {
893         memory->destroy(bufcopy);
894         memory->create(bufcopy,maxbufcopy,2,"dump:bufcopy");
895       }
896     }
897 
898     for (i = 0; i < nlocal; i++) chooseghost[i] = choose[i];
899 
900     if (comm_forward == 3) {
901       for (i = 0; i < nlocal; i++) bufcopy[i][0] = bufcopy[i][1] = 0.0;
902       m = 0;
903       for (i = 0; i < nchoose; i++) {
904         j = clist[i];
905         bufcopy[j][0] = buf[m];
906         bufcopy[j][1] = buf[m+1];
907         m += size_one;
908       }
909     }
910 
911     comm->forward_comm_dump(this);
912 
913     for (i = 0; i < nchoose; i++) {
914       atom1 = clist[i];
915       if (molecular == Atom::MOLECULAR) n = num_bond[atom1];
916       else {
917         if (molindex[atom1] < 0) continue;
918         imol = molindex[atom1];
919         iatom = molatom[atom1];
920         n = onemols[imol]->num_bond[iatom];
921       }
922 
923       for (m = 0; m < n; m++) {
924         if (molecular == Atom::MOLECULAR) {
925           btype = bond_type[atom1][m];
926           atom2 = atom->map(bond_atom[atom1][m]);
927         } else {
928           tagprev = tag[i] - iatom - 1;
929           btype = atom->map(onemols[imol]->bond_type[iatom][m]);
930           atom2 = atom->map(onemols[imol]->bond_atom[iatom][m]+tagprev);
931         }
932 
933         if (atom2 < 0 || !chooseghost[atom2]) continue;
934         if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue;
935         if (btype == 0) continue;
936 
937         if (bcolor == ATOM) {
938           if (acolor == TYPE) {
939             color1 = colortype[type[atom1]];
940             color2 = colortype[type[atom2]];
941           } else if (acolor == ELEMENT) {
942             color1 = colorelement[type[atom1]];
943             color2 = colorelement[type[atom2]];
944           } else if (acolor == ATTRIBUTE) {
945             color1 = image->map_value2color(0,bufcopy[atom1][0]);
946             color2 = image->map_value2color(0,bufcopy[atom2][0]);
947           } else {
948             color1 = image->color2rgb("white");
949             color2 = image->color2rgb("white");
950           }
951         } else if (bcolor == TYPE) {
952           itype = btype;
953           if (itype < 0) itype = -itype;
954           color = bcolortype[itype];
955         }
956 
957         if (bdiam == NUMERIC) {
958           diameter = bdiamvalue;
959         } else if (bdiam == ATOM) {
960           if (adiam == NUMERIC) {
961             diameter = adiamvalue;
962           } else if (adiam == TYPE) {
963             diameter = MIN(diamtype[type[atom1]],diamtype[type[atom1]]);
964           } else if (adiam == ELEMENT) {
965             diameter = MIN(diamelement[type[atom1]],diamelement[type[atom1]]);
966           } else if (adiam == ATTRIBUTE) {
967             diameter = MIN(bufcopy[atom1][1],bufcopy[atom2][1]);
968           }
969         } else if (bdiam == TYPE) {
970           itype = btype;
971           if (itype < 0) itype = -itype;
972           diameter = bdiamtype[itype];
973         }
974 
975         // draw cylinder in 2 pieces if bcolor = ATOM
976         // or bond crosses periodic boundary
977 
978         delx = x[atom2][0] - x[atom1][0];
979         dely = x[atom2][1] - x[atom1][1];
980         delz = x[atom2][2] - x[atom1][2];
981 
982         if (bcolor == ATOM || domain->minimum_image_check(delx,dely,delz)) {
983           domain->minimum_image(delx,dely,delz);
984           xmid[0] = x[atom1][0] + 0.5*delx;
985           xmid[1] = x[atom1][1] + 0.5*dely;
986           xmid[2] = x[atom1][2] + 0.5*delz;
987           if (bcolor == ATOM)
988             image->draw_cylinder(x[atom1],xmid,color1,diameter,3);
989           else image->draw_cylinder(x[atom1],xmid,color,diameter,3);
990           xmid[0] = x[atom2][0] - 0.5*delx;
991           xmid[1] = x[atom2][1] - 0.5*dely;
992           xmid[2] = x[atom2][2] - 0.5*delz;
993           if (bcolor == ATOM)
994             image->draw_cylinder(xmid,x[atom2],color2,diameter,3);
995           else image->draw_cylinder(xmid,x[atom2],color,diameter,3);
996 
997         } else image->draw_cylinder(x[atom1],x[atom2],color,diameter,3);
998       }
999     }
1000   }
1001 
1002   // render objects provided by a fix
1003 
1004   if (fixflag) {
1005     int tridraw=0,edgedraw=0;
1006     if (domain->dimension == 3) {
1007       tridraw = 1;
1008       edgedraw = 1;
1009       if ((int) fixflag1 == 2) tridraw = 0;
1010       if ((int) fixflag1 == 1) edgedraw = 0;
1011     }
1012 
1013     n = fixptr->image(fixvec,fixarray);
1014 
1015     for (i = 0; i < n; i++) {
1016       if (fixvec[i] == SPHERE) {
1017         // no fix draws spheres yet
1018       } else if (fixvec[i] == LINE) {
1019         if (fixcolor == TYPE) {
1020           itype = static_cast<int> (fixarray[i][0]);
1021           color = colortype[itype];
1022         }
1023         image->draw_cylinder(&fixarray[i][1],&fixarray[i][4],
1024                              color,fixflag1,3);
1025       } else if (fixvec[i] == TRI) {
1026         if (fixcolor == TYPE) {
1027           itype = static_cast<int> (fixarray[i][0]);
1028           color = colortype[itype];
1029         }
1030         p1 = &fixarray[i][1];
1031         p2 = &fixarray[i][4];
1032         p3 = &fixarray[i][7];
1033         if (tridraw) image->draw_triangle(p1,p2,p3,color);
1034         if (edgedraw) {
1035           image->draw_cylinder(p1,p2,color,fixflag2,3);
1036           image->draw_cylinder(p2,p3,color,fixflag2,3);
1037           image->draw_cylinder(p3,p1,color,fixflag2,3);
1038         }
1039       }
1040     }
1041   }
1042 
1043   // render outline of my sub-box, orthogonal or triclinic
1044 
1045   if (subboxflag) {
1046     diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo);
1047     if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo);
1048     diameter *= subboxdiam;
1049 
1050     double *sublo = domain->sublo;
1051     double *subhi = domain->subhi;
1052 
1053     double (*boxcorners)[3];
1054     double box[8][3];
1055     if (domain->triclinic == 0) {
1056       box[0][0] = sublo[0]; box[0][1] = sublo[1]; box[0][2] = sublo[2];
1057       box[1][0] = subhi[0]; box[1][1] = sublo[1]; box[1][2] = sublo[2];
1058       box[2][0] = sublo[0]; box[2][1] = subhi[1]; box[2][2] = sublo[2];
1059       box[3][0] = subhi[0]; box[3][1] = subhi[1]; box[3][2] = sublo[2];
1060       box[4][0] = sublo[0]; box[4][1] = sublo[1]; box[4][2] = subhi[2];
1061       box[5][0] = subhi[0]; box[5][1] = sublo[1]; box[5][2] = subhi[2];
1062       box[6][0] = sublo[0]; box[6][1] = subhi[1]; box[6][2] = subhi[2];
1063       box[7][0] = subhi[0]; box[7][1] = subhi[1]; box[7][2] = subhi[2];
1064       boxcorners = box;
1065     } else {
1066       domain->subbox_corners();
1067       boxcorners = domain->corners;
1068     }
1069 
1070     image->draw_box(boxcorners,diameter);
1071   }
1072 
1073   // render outline of simulation box, orthogonal or triclinic
1074 
1075   if (boxflag) {
1076     diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo);
1077     if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo);
1078     diameter *= boxdiam;
1079 
1080     double (*boxcorners)[3];
1081     double box[8][3];
1082     if (domain->triclinic == 0) {
1083       box[0][0] = boxxlo; box[0][1] = boxylo; box[0][2] = boxzlo;
1084       box[1][0] = boxxhi; box[1][1] = boxylo; box[1][2] = boxzlo;
1085       box[2][0] = boxxlo; box[2][1] = boxyhi; box[2][2] = boxzlo;
1086       box[3][0] = boxxhi; box[3][1] = boxyhi; box[3][2] = boxzlo;
1087       box[4][0] = boxxlo; box[4][1] = boxylo; box[4][2] = boxzhi;
1088       box[5][0] = boxxhi; box[5][1] = boxylo; box[5][2] = boxzhi;
1089       box[6][0] = boxxlo; box[6][1] = boxyhi; box[6][2] = boxzhi;
1090       box[7][0] = boxxhi; box[7][1] = boxyhi; box[7][2] = boxzhi;
1091       boxcorners = box;
1092     } else {
1093       domain->box_corners();
1094       boxcorners = domain->corners;
1095     }
1096 
1097     image->draw_box(boxcorners,diameter);
1098   }
1099 
1100   // render XYZ axes in red/green/blue
1101   // offset by 10% of box size and scale by axeslen
1102 
1103   if (axesflag) {
1104     diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo);
1105     if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo);
1106     diameter *= axesdiam;
1107 
1108     double (*boxcorners)[3];
1109     double axes[4][3];
1110     if (domain->triclinic == 0) {
1111       axes[0][0] = boxxlo; axes[0][1] = boxylo; axes[0][2] = boxzlo;
1112       axes[1][0] = boxxhi; axes[1][1] = boxylo; axes[1][2] = boxzlo;
1113       axes[2][0] = boxxlo; axes[2][1] = boxyhi; axes[2][2] = boxzlo;
1114       axes[3][0] = boxxlo; axes[3][1] = boxylo; axes[3][2] = boxzhi;
1115     } else {
1116       domain->box_corners();
1117       boxcorners = domain->corners;
1118       axes[0][0] = boxcorners[0][0];
1119       axes[0][1] = boxcorners[0][1];
1120       axes[0][2] = boxcorners[0][2];
1121       axes[1][0] = boxcorners[1][0];
1122       axes[1][1] = boxcorners[1][1];
1123       axes[1][2] = boxcorners[1][2];
1124       axes[2][0] = boxcorners[2][0];
1125       axes[2][1] = boxcorners[2][1];
1126       axes[2][2] = boxcorners[2][2];
1127       axes[3][0] = boxcorners[4][0];
1128       axes[3][1] = boxcorners[4][1];
1129       axes[3][2] = boxcorners[4][2];
1130     }
1131 
1132     double offset = MAX(boxxhi-boxxlo,boxyhi-boxylo);
1133     if (domain->dimension == 3) offset = MAX(offset,boxzhi-boxzlo);
1134     offset *= 0.1;
1135     axes[0][0] -= offset; axes[0][1] -= offset; axes[0][2] -= offset;
1136     axes[1][0] -= offset; axes[1][1] -= offset; axes[1][2] -= offset;
1137     axes[2][0] -= offset; axes[2][1] -= offset; axes[2][2] -= offset;
1138     axes[3][0] -= offset; axes[3][1] -= offset; axes[3][2] -= offset;
1139 
1140     axes[1][0] = axes[0][0] + axeslen*(axes[1][0]-axes[0][0]);
1141     axes[1][1] = axes[0][1] + axeslen*(axes[1][1]-axes[0][1]);
1142     axes[1][2] = axes[0][2] + axeslen*(axes[1][2]-axes[0][2]);
1143     axes[2][0] = axes[0][0] + axeslen*(axes[2][0]-axes[0][0]);
1144     axes[2][1] = axes[0][1] + axeslen*(axes[2][1]-axes[0][1]);
1145     axes[2][2] = axes[0][2] + axeslen*(axes[2][2]-axes[0][2]);
1146     axes[3][0] = axes[0][0] + axeslen*(axes[3][0]-axes[0][0]);
1147     axes[3][1] = axes[0][1] + axeslen*(axes[3][1]-axes[0][1]);
1148     axes[3][2] = axes[0][2] + axeslen*(axes[3][2]-axes[0][2]);
1149 
1150     image->draw_axes(axes,diameter);
1151   }
1152 }
1153 
1154 /* ---------------------------------------------------------------------- */
1155 
pack_forward_comm(int n,int * list,double * buf,int,int *)1156 int DumpImage::pack_forward_comm(int n, int *list, double *buf,
1157                                  int /*pbc_flag*/, int * /*pbc*/)
1158 {
1159   int i,j,m;
1160 
1161   m = 0;
1162 
1163   if (comm_forward == 1) {
1164     for (i = 0; i < n; i++) {
1165       j = list[i];
1166       buf[m++] = chooseghost[j];
1167     }
1168   } else {
1169     for (i = 0; i < n; i++) {
1170       j = list[i];
1171       buf[m++] = chooseghost[j];
1172       buf[m++] = bufcopy[j][0];
1173       buf[m++] = bufcopy[j][1];
1174     }
1175   }
1176 
1177   return m;
1178 }
1179 
1180 /* ---------------------------------------------------------------------- */
1181 
unpack_forward_comm(int n,int first,double * buf)1182 void DumpImage::unpack_forward_comm(int n, int first, double *buf)
1183 {
1184   int i,m,last;
1185 
1186   m = 0;
1187   last = first + n;
1188 
1189   if (comm_forward == 1)
1190     for (i = first; i < last; i++) chooseghost[i] = static_cast<int> (buf[m++]);
1191   else {
1192     for (i = first; i < last; i++) {
1193       chooseghost[i] = static_cast<int> (buf[m++]);
1194       bufcopy[i][0] = buf[m++];
1195       bufcopy[i][1] = buf[m++];
1196     }
1197   }
1198 }
1199 
1200 /* ---------------------------------------------------------------------- */
1201 
modify_param(int narg,char ** arg)1202 int DumpImage::modify_param(int narg, char **arg)
1203 {
1204   int n = DumpCustom::modify_param(narg,arg);
1205   if (n) return n;
1206 
1207   if (strcmp(arg[0],"acolor") == 0) {
1208     if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
1209     int nlo,nhi;
1210     utils::bounds(FLERR,arg[1],1,atom->ntypes,nlo,nhi,error);
1211 
1212     // get list of colors
1213     auto colors = Tokenizer(arg[2],"/").as_vector();
1214     const int ncolors = colors.size();
1215 
1216     // assign colors in round-robin fashion to types
1217 
1218     int m = 0;
1219     for (int i = nlo; i <= nhi; i++) {
1220       colortype[i] = image->color2rgb(colors[m%ncolors].c_str());
1221       if (colortype[i] == nullptr)
1222         error->all(FLERR,"Invalid color in dump_modify command");
1223       m++;
1224     }
1225     return 3;
1226   }
1227 
1228   if (strcmp(arg[0],"adiam") == 0) {
1229     if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
1230     int nlo,nhi;
1231     utils::bounds(FLERR,arg[1],1,atom->ntypes,nlo,nhi,error);
1232     double diam = utils::numeric(FLERR,arg[2],false,lmp);
1233     if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command");
1234     for (int i = nlo; i <= nhi; i++) diamtype[i] = diam;
1235     return 3;
1236   }
1237 
1238   if (strcmp(arg[0],"amap") == 0) {
1239     if (narg < 6) error->all(FLERR,"Illegal dump_modify command");
1240     if (strlen(arg[3]) != 2) error->all(FLERR,"Illegal dump_modify command");
1241     int factor = 0;
1242     if (arg[3][0] == 's') factor = 1;
1243     else if (arg[3][0] == 'c') factor = 2;
1244     else if (arg[3][0] == 'd') factor = 3;
1245     else error->all(FLERR,"Illegal dump_modify command");
1246     int nentry = utils::inumeric(FLERR,arg[5],false,lmp);
1247     if (nentry < 1) error->all(FLERR,"Illegal dump_modify command");
1248     n = 6 + factor*nentry;
1249     if (narg < n) error->all(FLERR,"Illegal dump_modify command");
1250     int flag = image->map_reset(0,n-1,&arg[1]);
1251     if (flag) error->all(FLERR,"Illegal dump_modify command");
1252     return n;
1253   }
1254 
1255   if (strcmp(arg[0],"bcolor") == 0) {
1256     if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
1257     if (atom->nbondtypes == 0)
1258       error->all(FLERR,"Dump modify bcolor not allowed with no bond types");
1259     int nlo,nhi;
1260     utils::bounds(FLERR,arg[1],1,atom->nbondtypes,nlo,nhi,error);
1261 
1262     // ptrs = list of ncount colornames separated by '/'
1263 
1264     int ncount = 1;
1265     char *nextptr;
1266     char *ptr = arg[2];
1267     while ((nextptr = strchr(ptr,'/'))) {
1268       ptr = nextptr + 1;
1269       ncount++;
1270     }
1271     char **ptrs = new char*[ncount+1];
1272     ncount = 0;
1273     ptrs[ncount++] = strtok(arg[2],"/");
1274     while ((ptrs[ncount++] = strtok(nullptr,"/")));
1275     ncount--;
1276 
1277     // assign each of ncount colors in round-robin fashion to types
1278 
1279     int m = 0;
1280     for (int i = nlo; i <= nhi; i++) {
1281       bcolortype[i] = image->color2rgb(ptrs[m%ncount]);
1282       if (bcolortype[i] == nullptr)
1283         error->all(FLERR,"Invalid color in dump_modify command");
1284       m++;
1285     }
1286 
1287     delete [] ptrs;
1288     return 3;
1289   }
1290 
1291   if (strcmp(arg[0],"bdiam") == 0) {
1292     if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
1293     if (atom->nbondtypes == 0)
1294       error->all(FLERR,"Dump modify bdiam not allowed with no bond types");
1295     int nlo,nhi;
1296     utils::bounds(FLERR,arg[1],1,atom->nbondtypes,nlo,nhi,error);
1297     double diam = utils::numeric(FLERR,arg[2],false,lmp);
1298     if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command");
1299     for (int i = nlo; i <= nhi; i++) bdiamtype[i] = diam;
1300     return 3;
1301   }
1302 
1303   if (strcmp(arg[0],"backcolor") == 0) {
1304     if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
1305     double *color = image->color2rgb(arg[1]);
1306     if (color == nullptr) error->all(FLERR,"Invalid color in dump_modify command");
1307     image->background[0] = static_cast<int> (color[0]*255.0);
1308     image->background[1] = static_cast<int> (color[1]*255.0);
1309     image->background[2] = static_cast<int> (color[2]*255.0);
1310     return 2;
1311   }
1312 
1313   if (strcmp(arg[0],"boxcolor") == 0) {
1314     if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
1315     image->boxcolor = image->color2rgb(arg[1]);
1316     if (image->boxcolor == nullptr)
1317       error->all(FLERR,"Invalid color in dump_modify command");
1318     return 2;
1319   }
1320 
1321   if (strcmp(arg[0],"color") == 0) {
1322     if (narg < 5) error->all(FLERR,"Illegal dump_modify command");
1323     int flag = image->addcolor(arg[1],utils::numeric(FLERR,arg[2],false,lmp),
1324                                utils::numeric(FLERR,arg[3],false,lmp),
1325                                utils::numeric(FLERR,arg[4],false,lmp));
1326     if (flag) error->all(FLERR,"Illegal dump_modify command");
1327     return 5;
1328   }
1329 
1330   return 0;
1331 }
1332