// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories LAMMPS development team: developers@lammps.org Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "dump_image.h" #include "arg_info.h" #include "atom.h" #include "atom_vec.h" #include "atom_vec_body.h" #include "atom_vec_line.h" #include "atom_vec_tri.h" #include "body.h" #include "comm.h" #include "compute.h" #include "domain.h" #include "error.h" #include "fix.h" #include "force.h" #include "grid2d.h" #include "grid3d.h" #include "image.h" #include "input.h" #include "math_const.h" #include "math_extra.h" #include "memory.h" #include "modify.h" #include "molecule.h" #include "output.h" #include "thermo.h" #include "tokenizer.h" #include "update.h" #include "variable.h" #include #include #include using namespace LAMMPS_NS; using MathConst::DEG2RAD; static constexpr double BIG = 1.0e20; enum { NUMERIC, ATOM, TYPE, ELEMENT, ATTRIBUTE }; enum { SPHERE, LINE, TRI }; // also in some Body and Fix child classes enum { STATIC, DYNAMIC }; enum { NO = 0, YES = 1 }; /* ---------------------------------------------------------------------- */ DumpImage::DumpImage(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg), thetastr(nullptr), phistr(nullptr), cxstr(nullptr), cystr(nullptr), czstr(nullptr), upxstr(nullptr), upystr(nullptr), upzstr(nullptr), zoomstr(nullptr), diamtype(nullptr), diamelement(nullptr), bdiamtype(nullptr), colortype(nullptr), colorelement(nullptr), bcolortype(nullptr), grid2d(nullptr), grid3d(nullptr), id_grid_compute(nullptr), id_grid_fix(nullptr), grid_compute(nullptr), grid_fix(nullptr), gbuf(nullptr), avec_line(nullptr), avec_tri(nullptr), avec_body(nullptr), fixptr(nullptr), image(nullptr), chooseghost(nullptr), bufcopy(nullptr) { if (binary || multiproc) error->all(FLERR, "Invalid dump image filename"); // force binary flag on to avoid corrupted output on Windows binary = 1; multifile_override = 0; // flag has_id as true to avoid bogus warnings about atom IDs for dump styles derived from DumpCustom has_id = true; // set filetype based on filename suffix if (utils::strmatch(filename, "\\.jpg$") || utils::strmatch(filename, "\\.JPG$") || utils::strmatch(filename, "\\.jpeg$") || utils::strmatch(filename, "\\.JPEG$")) filetype = JPG; else if (utils::strmatch(filename, "\\.png$") || utils::strmatch(filename, "\\.PNG$")) filetype = PNG; else filetype = PPM; #ifndef LAMMPS_JPEG if (filetype == JPG) error->all(FLERR,"Support for writing images in JPEG format not included"); #endif #ifndef LAMMPS_PNG if (filetype == PNG) error->all(FLERR,"Support for writing images in PNG format not included"); #endif // atom color,diameter settings if (nfield != 2) error->all(FLERR,"Illegal dump image command"); acolor = ATTRIBUTE; if (strcmp(arg[5],"type") == 0) acolor = TYPE; else if (strcmp(arg[5],"element") == 0) acolor = ELEMENT; adiam = ATTRIBUTE; if (strcmp(arg[6],"type") == 0) adiam = TYPE; else if (strcmp(arg[6],"element") == 0) adiam = ELEMENT; // create Image class with two colormaps for atoms and grid cells // change defaults for 2d image = new Image(lmp,2); if (domain->dimension == 2) { image->theta = 0.0; image->phi = 0.0; image->up[0] = 0.0; image->up[1] = 1.0; image->up[2] = 0.0; } // set defaults for optional args atomflag = YES; gridflag = NO; lineflag = triflag = bodyflag = fixflag = NO; id_grid_compute = id_grid_fix = nullptr; if (atom->nbondtypes == 0) bondflag = NO; else { bondflag = YES; bcolor = ATOM; bdiam = NUMERIC; bdiamvalue = 0.5; } char *fixID = nullptr; cflag = STATIC; cx = cy = cz = 0.5; boxflag = YES; boxdiam = 0.02; axesflag = NO; subboxflag = NO; // parse optional args int iarg = ioptional; while (iarg < narg) { if (strcmp(arg[iarg],"atom") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); atomflag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"adiam") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); adiam = NUMERIC; adiamvalue = utils::numeric(FLERR,arg[iarg+1],false,lmp); if (adiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 2; } else if (strcmp(arg[iarg],"bond") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); if (atom->nbondtypes == 0) error->all(FLERR,"Dump image bond not allowed with no bond types"); bondflag = YES; if (strcmp(arg[iarg+1],"none") == 0) bondflag = NO; else if (strcmp(arg[iarg+1],"atom") == 0) bcolor = ATOM; else if (strcmp(arg[iarg+1],"type") == 0) bcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); if (!islower(arg[iarg+2][0])) { bdiam = NUMERIC; bdiamvalue = utils::numeric(FLERR,arg[iarg+2],false,lmp); if (bdiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command"); } else if (strcmp(arg[iarg+2],"atom") == 0) bdiam = ATOM; else if (strcmp(arg[iarg+2],"type") == 0) bdiam = TYPE; else if (strcmp(arg[iarg+2],"none") == 0) bondflag = NO; else error->all(FLERR,"Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"grid") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); gridflag = YES; char *id; int igrid,idata,index; int iflag = utils::check_grid_reference((char *) "Dump image", arg[iarg+1],nevery,id, igrid,idata,index,lmp); if (iflag < 0) error->all(FLERR,"Invalid grid reference in dump image command"); if (iflag == ArgInfo::COMPUTE) id_grid_compute = utils::strdup(id); else if (iflag == ArgInfo::FIX) id_grid_fix = utils::strdup(id); delete[] id; grid_igrid = igrid; grid_idata = idata; grid_index = index; iarg += 2; } else if (strcmp(arg[iarg],"line") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); lineflag = YES; if (strcmp(arg[iarg+1],"type") == 0) lcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); ldiam = NUMERIC; ldiamvalue = utils::numeric(FLERR,arg[iarg+2],false,lmp); iarg += 3; } else if (strcmp(arg[iarg],"tri") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); triflag = YES; if (strcmp(arg[iarg+1],"type") == 0) tcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); tstyle = utils::inumeric(FLERR,arg[iarg+2],false,lmp); tdiamvalue = utils::numeric(FLERR,arg[iarg+3],false,lmp); iarg += 4; } else if (strcmp(arg[iarg],"body") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); bodyflag = YES; if (strcmp(arg[iarg+1],"type") == 0) bodycolor = TYPE; else error->all(FLERR,"Illegal dump image command"); bodyflag1 = utils::numeric(FLERR,arg[iarg+2],false,lmp); bodyflag2 = utils::numeric(FLERR,arg[iarg+3],false,lmp); iarg += 4; } else if (strcmp(arg[iarg],"fix") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal dump image command"); fixflag = YES; fixID = arg[iarg+1]; if (strcmp(arg[iarg+2],"type") == 0) fixcolor = TYPE; else error->all(FLERR,"Illegal dump image command"); fixflag1 = utils::numeric(FLERR,arg[iarg+3],false,lmp); fixflag2 = utils::numeric(FLERR,arg[iarg+4],false,lmp); iarg += 5; } else if (strcmp(arg[iarg],"size") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); int width = utils::inumeric(FLERR,arg[iarg+1],false,lmp); int height = utils::inumeric(FLERR,arg[iarg+2],false,lmp); if (width <= 0 || height <= 0) error->all(FLERR,"Illegal dump image command"); if (image->fsaa) { image->width = width*2; image->height = height*2; } else { image->width = width; image->height = height; } iarg += 3; } else if (strcmp(arg[iarg],"view") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); if (utils::strmatch(arg[iarg+1],"^v_")) { thetastr = utils::strdup(arg[iarg+1]+2); } else { const double theta = utils::numeric(FLERR,arg[iarg+1],false,lmp); if (theta < 0.0 || theta > 180.0) error->all(FLERR,"Invalid dump image theta value"); image->theta = DEG2RAD * theta; } if (utils::strmatch(arg[iarg+2],"^v_")) { phistr = utils::strdup(arg[iarg+2]+2); } else { image->phi = DEG2RAD * utils::numeric(FLERR,arg[iarg+2],false,lmp); } iarg += 3; } else if (strcmp(arg[iarg],"center") == 0) { if (iarg+5 > narg) error->all(FLERR,"Illegal dump image command"); if (strcmp(arg[iarg+1],"s") == 0) cflag = STATIC; else if (strcmp(arg[iarg+1],"d") == 0) cflag = DYNAMIC; else error->all(FLERR,"Illegal dump image command"); if (utils::strmatch(arg[iarg+2],"^v_")) { cxstr = utils::strdup(arg[iarg+2]+2); cflag = DYNAMIC; } else cx = utils::numeric(FLERR,arg[iarg+2],false,lmp); if (utils::strmatch(arg[iarg+3],"^v_")) { cystr = utils::strdup(arg[iarg+3]+2); cflag = DYNAMIC; } else cy = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (utils::strmatch(arg[iarg+4],"^v_")) { czstr = utils::strdup(arg[iarg+4]+2); cflag = DYNAMIC; } else cz = utils::numeric(FLERR,arg[iarg+4],false,lmp); iarg += 5; } else if (strcmp(arg[iarg],"up") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); if (utils::strmatch(arg[iarg+1],"^v_")) { upxstr = utils::strdup(arg[iarg+1]+2); } else image->up[0] = utils::numeric(FLERR,arg[iarg+1],false,lmp); if (utils::strmatch(arg[iarg+2],"^v_")) { upystr = utils::strdup(arg[iarg+2]+2); } else image->up[1] = utils::numeric(FLERR,arg[iarg+2],false,lmp); if (utils::strmatch(arg[iarg+3],"^v_")) { upzstr = utils::strdup(arg[iarg+3]+2); } else image->up[2] = utils::numeric(FLERR,arg[iarg+3],false,lmp); iarg += 4; } else if (strcmp(arg[iarg],"zoom") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); if (utils::strmatch(arg[iarg+1],"^v_")) { zoomstr = utils::strdup(arg[iarg+1]+2); } else { double zoom = utils::numeric(FLERR,arg[iarg+1],false,lmp); if (zoom <= 0.0) error->all(FLERR,"Illegal dump image command"); image->zoom = zoom; } iarg += 2; } else if (strcmp(arg[iarg],"box") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); boxflag = utils::logical(FLERR,arg[iarg+1],false,lmp); boxdiam = utils::numeric(FLERR,arg[iarg+2],false,lmp); if (boxdiam < 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"axes") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); axesflag = utils::logical(FLERR,arg[iarg+1],false,lmp); axeslen = utils::numeric(FLERR,arg[iarg+2],false,lmp); axesdiam = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (axeslen < 0.0 || axesdiam < 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 4; } else if (strcmp(arg[iarg],"subbox") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command"); subboxflag = utils::logical(FLERR,arg[iarg+1],false,lmp); subboxdiam = utils::numeric(FLERR,arg[iarg+2],false,lmp); if (subboxdiam < 0.0) error->all(FLERR,"Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"shiny") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command"); double shiny = utils::numeric(FLERR,arg[iarg+1],false,lmp); if (shiny < 0.0 || shiny > 1.0) error->all(FLERR,"Illegal dump image command"); image->shiny = shiny; iarg += 2; } else if (strcmp(arg[iarg],"fsaa") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); int aa = utils::logical(FLERR, arg[iarg+1], false, lmp); if (aa) { if (!image->fsaa) { image->width = image->width*2; image->height = image->height*2; } } else { if (image->fsaa) { image->width = image->width/2; image->height = image->height/2; } } image->fsaa = aa; iarg += 2; } else if (strcmp(arg[iarg],"ssao") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command"); image->ssao = utils::logical(FLERR,arg[iarg+1],false,lmp); int seed = utils::inumeric(FLERR,arg[iarg+2],false,lmp); if (seed <= 0) error->all(FLERR,"Illegal dump image command"); image->seed = seed; double ssaoint = utils::numeric(FLERR,arg[iarg+3],false,lmp); if (ssaoint < 0.0 || ssaoint > 1.0) error->all(FLERR,"Illegal dump image command"); image->ssaoint = ssaoint; iarg += 4; } else error->all(FLERR,"Illegal dump image command"); } // error checks and setup for lineflag, triflag, bodyflag, fixflag if (lineflag) { avec_line = dynamic_cast(atom->style_match("line")); if (!avec_line) error->all(FLERR,"Dump image line requires atom style line"); } if (triflag) { avec_tri = dynamic_cast(atom->style_match("tri")); if (!avec_tri) error->all(FLERR,"Dump image tri requires atom style tri"); } if (bodyflag) { avec_body = dynamic_cast(atom->style_match("body")); if (!avec_body) error->all(FLERR,"Dump image body yes requires atom style body"); } extraflag = 0; if (lineflag || triflag || bodyflag) extraflag = 1; if (fixflag) { fixptr = modify->get_fix_by_id(fixID); if (!fixptr) error->all(FLERR,"Fix ID {} for dump image does not exist", fixID); } // allocate image buffer now that image size is known image->buffers(); // communication needed for bonds colored by atoms if (bondflag) { if (bcolor == ATOM || bdiam == ATOM) comm_forward = 3; else comm_forward = 1; } // additional defaults for dump_modify options diamtype = new double[ntypes+1]; diamelement = new double[ntypes+1]; colortype = new double*[ntypes+1]; colorelement = new double*[ntypes+1]; for (int i = 1; i <= ntypes; i++) { diamtype[i] = 1.0; if (i % 6 == 1) colortype[i] = image->color2rgb("red"); else if (i % 6 == 2) colortype[i] = image->color2rgb("green"); else if (i % 6 == 3) colortype[i] = image->color2rgb("blue"); else if (i % 6 == 4) colortype[i] = image->color2rgb("yellow"); else if (i % 6 == 5) colortype[i] = image->color2rgb("aqua"); else if (i % 6 == 0) colortype[i] = image->color2rgb("cyan"); } if (bondflag) { bdiamtype = new double[atom->nbondtypes+1]; bcolortype = new double*[atom->nbondtypes+1]; for (int i = 1; i <= atom->nbondtypes; i++) { bdiamtype[i] = 0.5; if (i % 6 == 1) bcolortype[i] = image->color2rgb("red"); else if (i % 6 == 2) bcolortype[i] = image->color2rgb("green"); else if (i % 6 == 3) bcolortype[i] = image->color2rgb("blue"); else if (i % 6 == 4) bcolortype[i] = image->color2rgb("yellow"); else if (i % 6 == 5) bcolortype[i] = image->color2rgb("aqua"); else if (i % 6 == 0) bcolortype[i] = image->color2rgb("cyan"); } } else { bdiamtype = nullptr; bcolortype = nullptr; } // viewflag = DYNAMIC if any view parameter is dynamic viewflag = STATIC; if (thetastr || phistr || cflag == DYNAMIC || upxstr || upystr || upzstr || zoomstr) viewflag = DYNAMIC; box_bounds(); if (cflag == STATIC) box_center(); if (viewflag == STATIC) view_params(); // local data grid_compute = nullptr; grid_fix = nullptr; maxbufcopy = 0; chooseghost = nullptr; bufcopy = nullptr; maxgrid = 0; gbuf = nullptr; } /* ---------------------------------------------------------------------- */ DumpImage::~DumpImage() { delete image; output->thermo->set_image_fname(""); delete[] diamtype; delete[] diamelement; delete[] colortype; delete[] colorelement; delete[] bdiamtype; delete[] bcolortype; memory->destroy(chooseghost); memory->destroy(bufcopy); memory->destroy(gbuf); delete[] upxstr; delete[] upystr; delete[] upzstr; delete[] zoomstr; delete[] thetastr; delete[] phistr; delete[] cxstr; delete[] cystr; delete[] czstr; delete[] id_grid_compute; delete[] id_grid_fix; } /* ---------------------------------------------------------------------- */ void DumpImage::init_style() { if (multifile == 0 && !multifile_override) error->all(FLERR,"Dump image requires one snapshot per file"); if (sort_flag) error->all(FLERR,"Dump image cannot perform sorting"); DumpCustom::init_style(); // for grid output, find current ptr for compute or fix // check that fix frequency is acceptable if (gridflag) { if (id_grid_compute) { grid_compute = modify->get_compute_by_id(id_grid_compute); if (!grid_compute) error->all(FLERR,"Could not find dump image grid compute ID {}",id_grid_compute); } else if (id_grid_fix) { grid_fix = modify->get_fix_by_id(id_grid_fix); if (!grid_fix) error->all(FLERR,"Could not find dump image fix ID {}",id_grid_fix); if (nevery % grid_fix->peratom_freq) error->all(FLERR,"Dump image and grid fix not computed at compatible times"); } } // check image variables if (thetastr) { thetavar = input->variable->find(thetastr); if (thetavar < 0) error->all(FLERR,"Variable name for dump image theta does not exist"); if (!input->variable->equalstyle(thetavar)) error->all(FLERR,"Variable for dump image theta is invalid style"); } if (phistr) { phivar = input->variable->find(phistr); if (phivar < 0) error->all(FLERR,"Variable name for dump image phi does not exist"); if (!input->variable->equalstyle(phivar)) error->all(FLERR,"Variable for dump image phi is invalid style"); } if (cxstr) { cxvar = input->variable->find(cxstr); if (cxvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(cxvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (cystr) { cyvar = input->variable->find(cystr); if (cyvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(cyvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (czstr) { czvar = input->variable->find(czstr); if (czvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(czvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (upxstr) { upxvar = input->variable->find(upxstr); if (upxvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upxvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (upystr) { upyvar = input->variable->find(upystr); if (upyvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upyvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (upzstr) { upzvar = input->variable->find(upzstr); if (upzvar < 0) error->all(FLERR,"Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upzvar)) error->all(FLERR,"Variable for dump image center is invalid style"); } if (zoomstr) { zoomvar = input->variable->find(zoomstr); if (zoomvar < 0) error->all(FLERR,"Variable name for dump image zoom does not exist"); if (!input->variable->equalstyle(zoomvar)) error->all(FLERR,"Variable for dump image zoom is invalid style"); } // set up type -> element mapping if (atomflag && acolor == ELEMENT) { for (int i = 1; i <= ntypes; i++) { colorelement[i] = image->element2color(typenames[i]); if (colorelement[i] == nullptr) error->all(FLERR,"Invalid dump image element name"); } } if (atomflag && adiam == ELEMENT) { for (int i = 1; i <= ntypes; i++) { diamelement[i] = image->element2diam(typenames[i]); if (diamelement[i] == 0.0) error->all(FLERR,"Invalid dump image element name"); } } } /* ---------------------------------------------------------------------- */ void DumpImage::write() { // open new file openfile(); // reset box center and view parameters if dynamic box_bounds(); if (cflag == DYNAMIC) box_center(); if (viewflag == DYNAMIC) view_params(); // nme = # of atoms this proc will contribute to dump nme = count(); if (nme > maxbuf) { maxbuf = nme; memory->destroy(buf); memory->create(buf,maxbuf*size_one,"dump:buf"); } // pack atom buf with color & diameter pack(nullptr); // set minmax color range if using dynamic atom color map if (acolor == ATTRIBUTE && image->map_dynamic(0)) { double two[2],twoall[2]; double lo = BIG; double hi = -BIG; int m = 0; for (int i = 0; i < nchoose; i++) { lo = MIN(lo,buf[m]); hi = MAX(hi,buf[m]); m += size_one; } two[0] = -lo; two[1] = hi; MPI_Allreduce(two,twoall,2,MPI_DOUBLE,MPI_MAX,world); int flag = image->map_minmax(0,-twoall[0],twoall[1]); if (flag) error->all(FLERR,"Invalid atom color map min/max values"); } // pack grid gbuf with grid cell values // ngrid = # of grid cells this proc owns if (gridflag) { if (domain->dimension == 2) { if (grid_compute) grid2d = (Grid2d *) grid_compute->get_grid_by_index(grid_igrid); else if (grid_fix) grid2d = (Grid2d *) grid_fix->get_grid_by_index(grid_igrid); grid2d->get_size(nxgrid,nygrid); grid2d->get_bounds_owned(nxlo_in,nxhi_in,nylo_in,nyhi_in); ngrid = (nxhi_in-nxlo_in+1) * (nyhi_in-nylo_in+1); } else { if (grid_compute) grid3d = (Grid3d *) grid_compute->get_grid_by_index(grid_igrid); else if (grid_fix) grid3d = (Grid3d *) grid_fix->get_grid_by_index(grid_igrid); grid3d->get_size(nxgrid,nygrid,nzgrid); grid3d->get_bounds_owned(nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in); ngrid = (nxhi_in-nxlo_in+1) * (nyhi_in-nylo_in+1) * (nzhi_in-nzlo_in+1); } // ensure gbuf is large enough if (ngrid > maxgrid) { memory->destroy(gbuf); maxgrid = ngrid; memory->create(gbuf,maxgrid,"dump/image:gbuf"); } // invoke Compute for per-grid quantities // cannot invoke before first run, otherwise invoke if necessary if (grid_compute) { if (!grid_compute->is_initialized()) error->all(FLERR,"Grid compute ID {} used in dump image cannot be invoked " "before initialization by a run", grid_compute->id); if (!(grid_compute->invoked_flag & Compute::INVOKED_PERGRID)) { grid_compute->compute_pergrid(); grid_compute->invoked_flag |= Compute::INVOKED_PERGRID; } } // access grid data and load gbuf if (domain->dimension == 2) { if (grid_index == 0) { double **vec2d; if (grid_compute) vec2d = (double **) grid_compute->get_griddata_by_index(grid_idata); else if (grid_fix) vec2d = (double **) grid_fix->get_griddata_by_index(grid_idata); int n = 0; for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) gbuf[n++] = vec2d[iy][ix]; } else { double ***array2d; if (grid_compute) array2d = (double ***) grid_compute->get_griddata_by_index(grid_idata); else if (grid_fix) array2d = (double ***) grid_fix->get_griddata_by_index(grid_idata); int index = grid_index - 1; int n = 0; for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) gbuf[n++] = array2d[iy][ix][index]; } } else if (domain->dimension == 3) { if (grid_index == 0) { double ***vec3d; if (grid_compute) vec3d = (double ***) grid_compute->get_griddata_by_index(grid_idata); else if (grid_fix) vec3d = (double ***) grid_fix->get_griddata_by_index(grid_idata); int n = 0; for (int iz = nzlo_in; iz <= nzhi_in; iz++) for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) gbuf[n++] = vec3d[iz][iy][ix]; } } else { double ****array3d; if (grid_compute) array3d = (double ****) grid_compute->get_griddata_by_index(grid_idata); else if (grid_fix) array3d = (double ****) grid_fix->get_griddata_by_index(grid_idata); int index = grid_index - 1; int n = 0; for (int iz = nzlo_in; iz <= nzhi_in; iz++) for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) gbuf[n++] = array3d[iz][iy][ix][index]; } } // set minmax color range if using dynamic grid color map if (gridflag && image->map_dynamic(1)) { double two[2],twoall[2]; double lo = BIG; double hi = -BIG; for (int i = 0; i < ngrid; i++) { lo = MIN(lo,gbuf[i]); hi = MAX(hi,gbuf[i]); } two[0] = -lo; two[1] = hi; MPI_Allreduce(two,twoall,2,MPI_DOUBLE,MPI_MAX,world); int flag = image->map_minmax(1,-twoall[0],twoall[1]); if (flag) error->all(FLERR,"Invalid grid color map min/max values"); } // create image on each proc, then merge them image->clear(); create_image(); image->merge(); // write image file if (me == 0) { if (filetype == JPG) image->write_JPG(fp); else if (filetype == PNG) image->write_PNG(fp); else image->write_PPM(fp); if (multifile) { fclose(fp); fp = nullptr; // cache last dump image filename for access through library interface. // update only *after* the file has been written so there will be no invalid read. // have to recreate the substitution done within openfile(). output->thermo->set_image_fname(utils::star_subst(filename, update->ntimestep, padflag)); } } } /* ---------------------------------------------------------------------- simulation box bounds ------------------------------------------------------------------------- */ void DumpImage::box_bounds() { if (domain->triclinic == 0) { boxxlo = domain->boxlo[0]; boxxhi = domain->boxhi[0]; boxylo = domain->boxlo[1]; boxyhi = domain->boxhi[1]; boxzlo = domain->boxlo[2]; boxzhi = domain->boxhi[2]; } else { boxxlo = domain->boxlo_bound[0]; boxxhi = domain->boxhi_bound[0]; boxylo = domain->boxlo_bound[1]; boxyhi = domain->boxhi_bound[1]; boxzlo = domain->boxlo_bound[2]; boxzhi = domain->boxhi_bound[2]; boxxy = domain->xy; boxxz = domain->xz; boxyz = domain->yz; } } /* ---------------------------------------------------------------------- reset view parameters called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::box_center() { if (cxstr) cx = input->variable->compute_equal(cxvar); if (cystr) cy = input->variable->compute_equal(cyvar); if (czstr) cz = input->variable->compute_equal(czvar); image->xctr = boxxlo + cx*(boxxhi-boxxlo); image->yctr = boxylo + cy*(boxyhi-boxylo); image->zctr = boxzlo + cz*(boxzhi-boxzlo); } /* ---------------------------------------------------------------------- reset view parameters in Image class called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::view_params() { // view direction theta and phi if (thetastr) { const double theta = input->variable->compute_equal(thetavar); if (theta < 0.0 || theta > 180.0) error->all(FLERR,"Invalid dump image theta value"); image->theta = DEG2RAD * theta; } if (phistr) image->phi = DEG2RAD * input->variable->compute_equal(phivar); // up vector if (upxstr) image->up[0] = input->variable->compute_equal(upxvar); if (upystr) image->up[1] = input->variable->compute_equal(upyvar); if (upzstr) image->up[2] = input->variable->compute_equal(upzvar); // zoom if (zoomstr) image->zoom = input->variable->compute_equal(zoomvar); if (image->zoom <= 0.0) error->all(FLERR,"Invalid dump image zoom value"); // remainder of view setup is internal to Image class image->view_params(boxxlo,boxxhi,boxylo,boxyhi,boxzlo,boxzhi); } /* ---------------------------------------------------------------------- create image for all data this proc owns all procs draw simulation box edges if requested every drawn pixel has depth so merge can decide which to keep ------------------------------------------------------------------------- */ void DumpImage::create_image() { int i,j,k,m,n,itype,atom1,atom2,imol,iatom,btype,ibonus,drawflag; tagint tagprev; double diameter,delx,dely,delz; int *bodyvec,*fixvec; double **bodyarray,**fixarray; double *color,*color1,*color2; double *p1,*p2,*p3; double xmid[3],pt1[3],pt2[3],pt3[3]; double mat[3][3]; // render my atoms if (atomflag) { double **x = atom->x; int *line = atom->line; int *tri = atom->tri; int *body = atom->body; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; if (acolor == TYPE) { itype = static_cast (buf[m]); color = colortype[itype]; } else if (acolor == ELEMENT) { itype = static_cast (buf[m]); color = colorelement[itype]; } else if (acolor == ATTRIBUTE) { color = image->map_value2color(0,buf[m]); } else color = image->color2rgb("white"); if (adiam == NUMERIC) { diameter = adiamvalue; } else if (adiam == TYPE) { itype = static_cast (buf[m+1]); diameter = diamtype[itype]; } else if (adiam == ELEMENT) { itype = static_cast (buf[m+1]); diameter = diamelement[itype]; } else if (adiam == ATTRIBUTE) { diameter = buf[m+1]; } // do not draw if line,tri,body keywords enabled and atom is one of those drawflag = 1; if (extraflag) { if (lineflag && line[j] >= 0) drawflag = 0; if (triflag && tri[j] >= 0) drawflag = 0; if (bodyflag && body[j] >= 0) drawflag = 0; } if (drawflag) image->draw_sphere(x[j],color,diameter); m += size_one; } } // render my grid cells // 2 triangles for 2d rectangle, 12 triangles for 3d cube surface // grid_cell_corners_2d/3d calculates orthogonal vs triclinic corner pts // for 3d, outward normals on all 6 faces if (gridflag) { // reset lighting for flat surfaces to make them brighter image->ambientColor[0] = image->ambientColor[1] = image->ambientColor[2] = 0.9; image->keyLightColor[0] = image->keyLightColor[1] = image->keyLightColor[2] = 0.3; image->fillLightColor[0] = image->fillLightColor[1] = image->fillLightColor[2] = 0.3; image->backLightColor[0] = image->backLightColor[1] = image->backLightColor[2] = 0.3; int n = 0; if (domain->dimension == 2) { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) { grid_cell_corners_2d(ix,iy); color = image->map_value2color(1,gbuf[n++]); image->draw_triangle(gcorners[0],gcorners[1],gcorners[3],color); image->draw_triangle(gcorners[0],gcorners[3],gcorners[2],color); } } else { for (int iz = nzlo_in; iz <= nzhi_in; iz++) for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) { grid_cell_corners_3d(ix,iy,iz); color = image->map_value2color(1,gbuf[n++]); // lower x face image->draw_triangle(gcorners[0],gcorners[4],gcorners[6],color); image->draw_triangle(gcorners[0],gcorners[6],gcorners[2],color); // upper x face image->draw_triangle(gcorners[1],gcorners[5],gcorners[7],color); image->draw_triangle(gcorners[1],gcorners[7],gcorners[3],color); // lower y face image->draw_triangle(gcorners[0],gcorners[1],gcorners[5],color); image->draw_triangle(gcorners[0],gcorners[5],gcorners[4],color); // upper y face image->draw_triangle(gcorners[2],gcorners[6],gcorners[7],color); image->draw_triangle(gcorners[2],gcorners[7],gcorners[3],color); // lower z face image->draw_triangle(gcorners[0],gcorners[2],gcorners[3],color); image->draw_triangle(gcorners[0],gcorners[3],gcorners[1],color); // upper z face image->draw_triangle(gcorners[4],gcorners[5],gcorners[7],color); image->draw_triangle(gcorners[4],gcorners[7],gcorners[6],color); } } // restore lighting for curved objects image->ambientColor[0] = image->ambientColor[1] = image->ambientColor[2] = 0.0; image->keyLightColor[0] = image->keyLightColor[1] = image->keyLightColor[2] = 0.9; image->fillLightColor[0] = image->fillLightColor[1] = image->fillLightColor[2] = 0.45; image->backLightColor[0] = image->backLightColor[1] = image->backLightColor[2] = 0.9; } // render atoms that are lines if (lineflag) { double length,theta,dx,dy; double **x = atom->x; int *line = atom->line; int *type = atom->type; for (i = 0; i < nchoose; i++) { j = clist[i]; if (line[j] < 0) continue; if (lcolor == TYPE) { color = colortype[type[j]]; } if (ldiam == NUMERIC) { diameter = ldiamvalue; } length = avec_line->bonus[line[j]].length; theta = avec_line->bonus[line[j]].theta; dx = 0.5*length*cos(theta); dy = 0.5*length*sin(theta); pt1[0] = x[j][0] + dx; pt1[1] = x[j][1] + dy; pt1[2] = 0.0; pt2[0] = x[j][0] - dx; pt2[1] = x[j][1] - dy; pt2[2] = 0.0; image->draw_cylinder(pt1,pt2,color,ldiamvalue,3); } } // render atoms that are triangles // tstyle = 1 for tri only, 2 for edges only, 3 for both if (triflag) { int tridraw = 1; if (tstyle == 2) tridraw = 0; int edgedraw = 1; if (tstyle == 1) edgedraw = 0; double **x = atom->x; int *tri = atom->tri; int *type = atom->type; for (i = 0; i < nchoose; i++) { j = clist[i]; if (tri[j] < 0) continue; if (tcolor == TYPE) { color = colortype[type[j]]; } MathExtra::quat_to_mat(avec_tri->bonus[tri[i]].quat,mat); MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c1,pt1); MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c2,pt2); MathExtra::matvec(mat,avec_tri->bonus[tri[i]].c3,pt3); MathExtra::add3(pt1,x[i],pt1); MathExtra::add3(pt2,x[i],pt2); MathExtra::add3(pt3,x[i],pt3); if (tridraw) image->draw_triangle(pt1,pt2,pt3,color); if (edgedraw) { image->draw_cylinder(pt1,pt2,color,tdiamvalue,3); image->draw_cylinder(pt2,pt3,color,tdiamvalue,3); image->draw_cylinder(pt3,pt1,color,tdiamvalue,3); } } } // render atoms that are bodies if (bodyflag) { Body *bptr = avec_body->bptr; int *body = atom->body; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; if (body[j] < 0) continue; if (bodycolor == TYPE) { itype = static_cast (buf[m]); color = colortype[itype]; } ibonus = body[i]; n = bptr->image(ibonus,bodyflag1,bodyflag2,bodyvec,bodyarray); for (k = 0; k < n; k++) { if (bodyvec[k] == SPHERE) image->draw_sphere(bodyarray[k],color,bodyarray[k][3]); else if (bodyvec[k] == LINE) image->draw_cylinder(&bodyarray[k][0],&bodyarray[k][3], color,bodyarray[k][6],3); } m += size_one; } } // render bonds for my atoms // both atoms in bond must be selected for bond to be rendered // if newton_bond is off, only render bond once // render bond in 2 pieces if crosses periodic boundary // if bond is deleted (type = 0), do not render // if bond is turned off (type < 0), still render if (bondflag) { double **x = atom->x; tagint *tag = atom->tag; tagint **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; int *molindex = atom->molindex; int *molatom = atom->molatom; int *type = atom->type; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; int molecular = atom->molecular; Molecule **onemols = atom->avec->onemols; // communicate choose flag for ghost atoms to know if they are selected // if bcolor/bdiam = ATOM, setup bufcopy to comm atom color/diam attributes if (atom->nmax > maxbufcopy) { maxbufcopy = atom->nmax; memory->destroy(chooseghost); memory->create(chooseghost,maxbufcopy,"dump:chooseghost"); if (comm_forward == 3) { memory->destroy(bufcopy); memory->create(bufcopy,maxbufcopy,2,"dump:bufcopy"); } } for (i = 0; i < nlocal; i++) chooseghost[i] = choose[i]; if (comm_forward == 3) { for (i = 0; i < nlocal; i++) bufcopy[i][0] = bufcopy[i][1] = 0.0; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; bufcopy[j][0] = buf[m]; bufcopy[j][1] = buf[m+1]; m += size_one; } } comm->forward_comm(this); for (i = 0; i < nchoose; i++) { atom1 = clist[i]; if (molecular == Atom::MOLECULAR) n = num_bond[atom1]; else { if (molindex[atom1] < 0) continue; imol = molindex[atom1]; iatom = molatom[atom1]; n = onemols[imol]->num_bond[iatom]; } for (m = 0; m < n; m++) { if (molecular == Atom::MOLECULAR) { btype = bond_type[atom1][m]; atom2 = atom->map(bond_atom[atom1][m]); } else { tagprev = tag[i] - iatom - 1; btype = atom->map(onemols[imol]->bond_type[iatom][m]); atom2 = atom->map(onemols[imol]->bond_atom[iatom][m]+tagprev); } if (atom2 < 0 || !chooseghost[atom2]) continue; if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue; if (btype == 0) continue; if (bcolor == ATOM) { if (acolor == TYPE) { color1 = colortype[type[atom1]]; color2 = colortype[type[atom2]]; } else if (acolor == ELEMENT) { color1 = colorelement[type[atom1]]; color2 = colorelement[type[atom2]]; } else if (acolor == ATTRIBUTE) { color1 = image->map_value2color(0,bufcopy[atom1][0]); color2 = image->map_value2color(0,bufcopy[atom2][0]); } else { color1 = image->color2rgb("white"); color2 = image->color2rgb("white"); } } else if (bcolor == TYPE) { itype = btype; if (itype < 0) itype = -itype; color = bcolortype[itype]; } if (bdiam == NUMERIC) { diameter = bdiamvalue; } else if (bdiam == ATOM) { if (adiam == NUMERIC) { diameter = adiamvalue; } else if (adiam == TYPE) { diameter = MIN(diamtype[type[atom1]],diamtype[type[atom1]]); } else if (adiam == ELEMENT) { diameter = MIN(diamelement[type[atom1]],diamelement[type[atom1]]); } else if (adiam == ATTRIBUTE) { diameter = MIN(bufcopy[atom1][1],bufcopy[atom2][1]); } } else if (bdiam == TYPE) { itype = btype; if (itype < 0) itype = -itype; diameter = bdiamtype[itype]; } // draw cylinder in 2 pieces if bcolor = ATOM // or bond crosses periodic boundary delx = x[atom2][0] - x[atom1][0]; dely = x[atom2][1] - x[atom1][1]; delz = x[atom2][2] - x[atom1][2]; if (bcolor == ATOM || domain->minimum_image_check(delx,dely,delz)) { domain->minimum_image(delx,dely,delz); xmid[0] = x[atom1][0] + 0.5*delx; xmid[1] = x[atom1][1] + 0.5*dely; xmid[2] = x[atom1][2] + 0.5*delz; if (bcolor == ATOM) image->draw_cylinder(x[atom1],xmid,color1,diameter,3); else image->draw_cylinder(x[atom1],xmid,color,diameter,3); xmid[0] = x[atom2][0] - 0.5*delx; xmid[1] = x[atom2][1] - 0.5*dely; xmid[2] = x[atom2][2] - 0.5*delz; if (bcolor == ATOM) image->draw_cylinder(xmid,x[atom2],color2,diameter,3); else image->draw_cylinder(xmid,x[atom2],color,diameter,3); } else image->draw_cylinder(x[atom1],x[atom2],color,diameter,3); } } } // render objects provided by a fix if (fixflag) { int tridraw=0,edgedraw=0; if (domain->dimension == 3) { tridraw = 1; edgedraw = 1; if ((int) fixflag1 == 2) tridraw = 0; if ((int) fixflag1 == 1) edgedraw = 0; } n = fixptr->image(fixvec,fixarray); for (i = 0; i < n; i++) { if (fixvec[i] == SPHERE) { // no fix draws spheres yet } else if (fixvec[i] == LINE) { if (fixcolor == TYPE) { itype = static_cast (fixarray[i][0]); color = colortype[itype]; } image->draw_cylinder(&fixarray[i][1],&fixarray[i][4], color,fixflag1,3); } else if (fixvec[i] == TRI) { if (fixcolor == TYPE) { itype = static_cast (fixarray[i][0]); color = colortype[itype]; } p1 = &fixarray[i][1]; p2 = &fixarray[i][4]; p3 = &fixarray[i][7]; if (tridraw) image->draw_triangle(p1,p2,p3,color); if (edgedraw) { image->draw_cylinder(p1,p2,color,fixflag2,3); image->draw_cylinder(p2,p3,color,fixflag2,3); image->draw_cylinder(p3,p1,color,fixflag2,3); } } } } // render outline of my sub-box, orthogonal or triclinic if (subboxflag) { diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= subboxdiam; double *sublo = domain->sublo; double *subhi = domain->subhi; double (*boxcorners)[3]; double box[8][3]; if (domain->triclinic == 0) { box[0][0] = sublo[0]; box[0][1] = sublo[1]; box[0][2] = sublo[2]; box[1][0] = subhi[0]; box[1][1] = sublo[1]; box[1][2] = sublo[2]; box[2][0] = sublo[0]; box[2][1] = subhi[1]; box[2][2] = sublo[2]; box[3][0] = subhi[0]; box[3][1] = subhi[1]; box[3][2] = sublo[2]; box[4][0] = sublo[0]; box[4][1] = sublo[1]; box[4][2] = subhi[2]; box[5][0] = subhi[0]; box[5][1] = sublo[1]; box[5][2] = subhi[2]; box[6][0] = sublo[0]; box[6][1] = subhi[1]; box[6][2] = subhi[2]; box[7][0] = subhi[0]; box[7][1] = subhi[1]; box[7][2] = subhi[2]; boxcorners = box; } else { domain->subbox_corners(); boxcorners = domain->corners; } image->draw_box(boxcorners,diameter); } // render outline of simulation box, orthogonal or triclinic if (boxflag) { diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= boxdiam; double (*boxcorners)[3]; double box[8][3]; if (domain->triclinic == 0) { box[0][0] = boxxlo; box[0][1] = boxylo; box[0][2] = boxzlo; box[1][0] = boxxhi; box[1][1] = boxylo; box[1][2] = boxzlo; box[2][0] = boxxlo; box[2][1] = boxyhi; box[2][2] = boxzlo; box[3][0] = boxxhi; box[3][1] = boxyhi; box[3][2] = boxzlo; box[4][0] = boxxlo; box[4][1] = boxylo; box[4][2] = boxzhi; box[5][0] = boxxhi; box[5][1] = boxylo; box[5][2] = boxzhi; box[6][0] = boxxlo; box[6][1] = boxyhi; box[6][2] = boxzhi; box[7][0] = boxxhi; box[7][1] = boxyhi; box[7][2] = boxzhi; boxcorners = box; } else { domain->box_corners(); boxcorners = domain->corners; } image->draw_box(boxcorners,diameter); } // render XYZ axes in red/green/blue // offset by 10% of box size and scale by axeslen if (axesflag) { diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= axesdiam; double (*boxcorners)[3]; double axes[4][3]; if (domain->triclinic == 0) { axes[0][0] = boxxlo; axes[0][1] = boxylo; axes[0][2] = boxzlo; axes[1][0] = boxxhi; axes[1][1] = boxylo; axes[1][2] = boxzlo; axes[2][0] = boxxlo; axes[2][1] = boxyhi; axes[2][2] = boxzlo; axes[3][0] = boxxlo; axes[3][1] = boxylo; axes[3][2] = boxzhi; } else { domain->box_corners(); boxcorners = domain->corners; axes[0][0] = boxcorners[0][0]; axes[0][1] = boxcorners[0][1]; axes[0][2] = boxcorners[0][2]; axes[1][0] = boxcorners[1][0]; axes[1][1] = boxcorners[1][1]; axes[1][2] = boxcorners[1][2]; axes[2][0] = boxcorners[2][0]; axes[2][1] = boxcorners[2][1]; axes[2][2] = boxcorners[2][2]; axes[3][0] = boxcorners[4][0]; axes[3][1] = boxcorners[4][1]; axes[3][2] = boxcorners[4][2]; } double offset = MAX(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) offset = MAX(offset,boxzhi-boxzlo); offset *= 0.1; axes[0][0] -= offset; axes[0][1] -= offset; axes[0][2] -= offset; axes[1][0] -= offset; axes[1][1] -= offset; axes[1][2] -= offset; axes[2][0] -= offset; axes[2][1] -= offset; axes[2][2] -= offset; axes[3][0] -= offset; axes[3][1] -= offset; axes[3][2] -= offset; axes[1][0] = axes[0][0] + axeslen*(axes[1][0]-axes[0][0]); axes[1][1] = axes[0][1] + axeslen*(axes[1][1]-axes[0][1]); axes[1][2] = axes[0][2] + axeslen*(axes[1][2]-axes[0][2]); axes[2][0] = axes[0][0] + axeslen*(axes[2][0]-axes[0][0]); axes[2][1] = axes[0][1] + axeslen*(axes[2][1]-axes[0][1]); axes[2][2] = axes[0][2] + axeslen*(axes[2][2]-axes[0][2]); axes[3][0] = axes[0][0] + axeslen*(axes[3][0]-axes[0][0]); axes[3][1] = axes[0][1] + axeslen*(axes[3][1]-axes[0][1]); axes[3][2] = axes[0][2] + axeslen*(axes[3][2]-axes[0][2]); image->draw_axes(axes,diameter); } } /* ---------------------------------------------------------------------- */ void DumpImage::grid_cell_corners_2d(int ix, int iy) { double *boxlo = domain->boxlo; double *prd = domain->prd; if (!domain->triclinic) { double xdelta = prd[0] / nxgrid; double ydelta = prd[1] / nygrid; int n = 0; for (int y = 0; y < 2; y++) for (int x = 0; x < 2; x++) { gcorners[n][0] = boxlo[0] + (ix+x) * xdelta; gcorners[n][1] = boxlo[1] + (iy+y) * ydelta; gcorners[n][2] = 0.0; n++; } } else { double lamda[3]; lamda[2] = 0.0; double dx = 1.0 / nxgrid; double dy = 1.0 / nygrid; int n = 0; for (int y = 0; y < 2; y++) for (int x = 0; x < 2; x++) { lamda[0] = (ix+x) * dx; lamda[1] = (iy+y) * dy; domain->lamda2x(lamda,gcorners[n]); n++; } } } /* ---------------------------------------------------------------------- */ void DumpImage::grid_cell_corners_3d(int ix, int iy, int iz) { double *boxlo = domain->boxlo; double *prd = domain->prd; if (!domain->triclinic) { double xdelta = prd[0] / nxgrid; double ydelta = prd[1] / nygrid; double zdelta = prd[2] / nzgrid; int n = 0; for (int z = 0; z < 2; z++) for (int y = 0; y < 2; y++) for (int x = 0; x < 2; x++) { gcorners[n][0] = boxlo[0] + (ix+x) * xdelta; gcorners[n][1] = boxlo[1] + (iy+y) * ydelta; gcorners[n][2] = boxlo[2] + (iz+z) * zdelta; n++; } } else { double lamda[3]; double dx = 1.0 / nxgrid; double dy = 1.0 / nygrid; double dz = 1.0 / nzgrid; int n = 0; for (int z = 0; z < 2; z++) for (int y = 0; y < 2; y++) for (int x = 0; x < 2; x++) { lamda[0] = (ix+x) * dx; lamda[1] = (iy+y) * dy; lamda[2] = (iz+z) * dz; domain->lamda2x(lamda,gcorners[n]); n++; } } } /* ---------------------------------------------------------------------- */ int DumpImage::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,m; m = 0; if (comm_forward == 1) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = chooseghost[j]; } } else { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = chooseghost[j]; buf[m++] = bufcopy[j][0]; buf[m++] = bufcopy[j][1]; } } return m; } /* ---------------------------------------------------------------------- */ void DumpImage::unpack_forward_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (comm_forward == 1) for (i = first; i < last; i++) chooseghost[i] = static_cast (buf[m++]); else { for (i = first; i < last; i++) { chooseghost[i] = static_cast (buf[m++]); bufcopy[i][0] = buf[m++]; bufcopy[i][1] = buf[m++]; } } } /* ---------------------------------------------------------------------- */ int DumpImage::modify_param(int narg, char **arg) { int n = DumpCustom::modify_param(narg,arg); if (n) return n; if (strcmp(arg[0],"acolor") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); int nlo,nhi; utils::bounds_typelabel(FLERR,arg[1],1,atom->ntypes,nlo,nhi,lmp,Atom::ATOM); // get list of colors // assign colors in round-robin fashion to types auto colors = Tokenizer(arg[2],"/").as_vector(); const int ncolors = colors.size(); int m = 0; for (int i = nlo; i <= nhi; i++) { colortype[i] = image->color2rgb(colors[m%ncolors].c_str()); if (colortype[i] == nullptr) error->all(FLERR,"Invalid color in dump_modify command"); m++; } return 3; } if (strcmp(arg[0],"adiam") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); int nlo,nhi; utils::bounds_typelabel(FLERR,arg[1],1,atom->ntypes,nlo,nhi,lmp,Atom::ATOM); double diam = utils::numeric(FLERR,arg[2],false,lmp); if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command"); for (int i = nlo; i <= nhi; i++) diamtype[i] = diam; return 3; } if ((strcmp(arg[0],"amap") == 0) || (strcmp(arg[0],"gmap") == 0)) { if (narg < 6) error->all(FLERR,"Illegal dump_modify command"); if (strlen(arg[3]) != 2) error->all(FLERR,"Illegal dump_modify command"); int factor = 0; if (arg[3][0] == 's') factor = 1; else if (arg[3][0] == 'c') factor = 2; else if (arg[3][0] == 'd') factor = 3; else error->all(FLERR,"Illegal dump_modify command"); int nentry = utils::inumeric(FLERR,arg[5],false,lmp); if (nentry < 1) error->all(FLERR,"Illegal dump_modify command"); n = 6 + factor*nentry; if (narg < n) error->all(FLERR,"Illegal dump_modify command"); int flag; if (strcmp(arg[0],"amap") == 0) flag = image->map_reset(0,n-1,&arg[1]); if (strcmp(arg[0],"gmap") == 0) flag = image->map_reset(1,n-1,&arg[1]); if (flag) error->all(FLERR,"Illegal dump_modify command"); return n; } if (strcmp(arg[0],"bcolor") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); if (atom->nbondtypes == 0) error->all(FLERR,"Dump modify bcolor not allowed with no bond types"); int nlo,nhi; utils::bounds_typelabel(FLERR,arg[1],1,atom->nbondtypes,nlo,nhi,lmp,Atom::BOND); // process list of ncount colornames separated by '/' // assign colors in round-robin fashion to bond types auto colors = Tokenizer(arg[2],"/").as_vector(); const int ncolors = colors.size(); int m = 0; for (int i = nlo; i <= nhi; i++) { bcolortype[i] = image->color2rgb(colors[m%ncolors].c_str()); if (bcolortype[i] == nullptr) error->all(FLERR,"Invalid color in dump_modify command"); m++; } return 3; } if (strcmp(arg[0],"bdiam") == 0) { if (narg < 3) error->all(FLERR,"Illegal dump_modify command"); if (atom->nbondtypes == 0) error->all(FLERR,"Dump modify bdiam not allowed with no bond types"); int nlo,nhi; utils::bounds_typelabel(FLERR,arg[1],1,atom->nbondtypes,nlo,nhi,lmp,Atom::BOND); double diam = utils::numeric(FLERR,arg[2],false,lmp); if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command"); for (int i = nlo; i <= nhi; i++) bdiamtype[i] = diam; return 3; } if (strcmp(arg[0],"backcolor") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); double *color = image->color2rgb(arg[1]); if (color == nullptr) error->all(FLERR,"Invalid color in dump_modify command"); image->background[0] = static_cast (color[0]*255.0); image->background[1] = static_cast (color[1]*255.0); image->background[2] = static_cast (color[2]*255.0); return 2; } if (strcmp(arg[0],"boxcolor") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); image->boxcolor = image->color2rgb(arg[1]); if (image->boxcolor == nullptr) error->all(FLERR,"Invalid color in dump_modify command"); return 2; } if (strcmp(arg[0],"color") == 0) { if (narg < 5) error->all(FLERR,"Illegal dump_modify command"); int flag = image->addcolor(arg[1],utils::numeric(FLERR,arg[2],false,lmp), utils::numeric(FLERR,arg[3],false,lmp), utils::numeric(FLERR,arg[4],false,lmp)); if (flag) error->all(FLERR,"Illegal dump_modify command"); return 5; } return 0; }