/* ---------------------------------------------------------------------- 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 "compute_property_grid.h" #include "comm.h" #include "domain.h" #include "error.h" #include "grid2d.h" #include "grid3d.h" #include "memory.h" #include "update.h" #include using namespace LAMMPS_NS; enum { LOW, CTR }; enum { UNSCALED, SCALED }; /* ---------------------------------------------------------------------- */ ComputePropertyGrid::ComputePropertyGrid(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), grid2d(nullptr), grid3d(nullptr), vec2d(nullptr), vec3d(nullptr), array2d(nullptr), array3d(nullptr), pack_choice(nullptr) { if (narg < 7) utils::missing_cmd_args(FLERR, "compute property/grid", error); pergrid_flag = 1; dimension = domain->dimension; nxgrid = utils::inumeric(FLERR, arg[3], false, lmp); nygrid = utils::inumeric(FLERR, arg[4], false, lmp); nzgrid = utils::inumeric(FLERR, arg[5], false, lmp); if (dimension == 2 && nzgrid != 1) error->all(FLERR, "Compute property/grid for 2d requires nz = 1"); if (nxgrid <= 0 || nygrid <= 0 || nzgrid <= 0) error->all(FLERR, "All compute property/grid grid counts must be > 0"); nvalues = narg - 6; pack_choice = new FnPtrPack[nvalues]; for (int iarg = 6; iarg < narg; iarg++) { int jarg = iarg - 6; if (strcmp(arg[iarg], "id") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_id; } else if (strcmp(arg[iarg], "proc") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_proc; } else if (strcmp(arg[iarg], "ix") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_indices<0>; } else if (strcmp(arg[iarg], "iy") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_indices<1>; } else if (strcmp(arg[iarg], "iz") == 0) { if (dimension == 2) error->all(FLERR, "Compute property/grid for 2d cannot use z coord"); pack_choice[jarg] = &ComputePropertyGrid::pack_indices<2>; } else if (strcmp(arg[iarg], "x") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "y") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "z") == 0) { if (dimension == 2) error->all(FLERR, "Compute property/grid for 2d cannot use z coord"); pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "xs") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "ys") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "zs") == 0) { if (dimension == 2) error->all(FLERR, "Compute property/grid for 2d cannot use z coord"); pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "xc") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "yc") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "zc") == 0) { if (dimension == 2) error->all(FLERR, "Compute property/grid for 2d cannot use z coord"); pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "xsc") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "ysc") == 0) { pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else if (strcmp(arg[iarg], "zsc") == 0) { if (dimension == 2) error->all(FLERR, "Compute property/grid for 2d cannot use z coord"); pack_choice[jarg] = &ComputePropertyGrid::pack_coords; } else error->all(FLERR, "Unknown compute property/grid keyword: {}", arg[iarg]); } // initial setup of distributed grid allocate_grid(); } /* ---------------------------------------------------------------------- */ ComputePropertyGrid::~ComputePropertyGrid() { delete[] pack_choice; deallocate_grid(); } /* ---------------------------------------------------------------------- */ void ComputePropertyGrid::init() { triclinic = domain->triclinic; } /* ---------------------------------------------------------------------- */ void ComputePropertyGrid::compute_pergrid() { invoked_pergrid = update->ntimestep; // fill data vector or array with values for my grid pts if (nvalues == 1) { (this->*pack_choice[0])(0); } else { for (int n = 0; n < nvalues; n++) (this->*pack_choice[n])(n); } } /* ---------------------------------------------------------------------- subset of grid assigned to each proc may have changed deallocate and reallocate Grid class and local data structs called by load balancer when proc subdomains are adjusted ---------------------------------------------------------------------- */ void ComputePropertyGrid::reset_grid() { deallocate_grid(); allocate_grid(); } /* ---------------------------------------------------------------------- return index of grid associated with name this class can store M named grids, indexed 0 to M-1 also set dim for 2d vs 3d grid return -1 if grid name not found ------------------------------------------------------------------------- */ int ComputePropertyGrid::get_grid_by_name(const std::string &name, int &dim) { if (name == "grid") { dim = dimension; return 0; } return -1; } /* ---------------------------------------------------------------------- return ptr to Grid data struct for grid with index this class can store M named grids, indexed 0 to M-1 return nullptr if index is invalid ------------------------------------------------------------------------- */ void *ComputePropertyGrid::get_grid_by_index(int index) { if (index == 0) { if (dimension == 2) return grid2d; else return grid3d; } return nullptr; } /* ---------------------------------------------------------------------- return index of data associated with name in grid with index igrid this class can store M named grids, indexed 0 to M-1 each grid can store G named data sets, indexed 0 to G-1 a data set name can be associated with multiple grids set ncol for data set, 0 = vector, 1-N for array with N columns vector = single value per grid pt, array = N values per grid pt return -1 if data name not found ------------------------------------------------------------------------- */ int ComputePropertyGrid::get_griddata_by_name(int igrid, const std::string &name, int &ncol) { if ((igrid == 0) && (name == "data")) { if (nvalues == 1) ncol = 0; else ncol = nvalues; return 0; } return -1; } /* ---------------------------------------------------------------------- return ptr to multidim data array associated with index this class can store G named data sets, indexed 0 to M-1 return nullptr if index is invalid ------------------------------------------------------------------------- */ void *ComputePropertyGrid::get_griddata_by_index(int index) { if (index == 0) { if (dimension == 2) { if (nvalues == 1) return vec2d; else return array2d; } else { if (nvalues == 1) return vec3d; else return array3d; } } return nullptr; } /* ---------------------------------------------------------------------- instantiate the Grid class and allocate local per-grid memory ---------------------------------------------------------------------- */ void ComputePropertyGrid::allocate_grid() { if (dimension == 2) { grid2d = new Grid2d(lmp, world, nxgrid, nygrid); grid2d->setup_grid(nxlo_in, nxhi_in, nylo_in, nyhi_in, nxlo_out, nxhi_out, nylo_out, nyhi_out); if (nvalues == 1) memory->create2d_offset(vec2d, nylo_out, nyhi_out, nxlo_out, nxhi_out, "property/grid:vec2d"); else memory->create3d_offset_last(array2d, nylo_out, nyhi_out, nxlo_out, nxhi_out, nvalues, "property/grid:array2d"); ngridout = (nxhi_out - nxlo_out + 1) * (nyhi_out - nylo_out + 1); } else { grid3d = new Grid3d(lmp, world, nxgrid, nygrid, nzgrid); grid3d->setup_grid(nxlo_in, nxhi_in, nylo_in, nyhi_in, nzlo_in, nzhi_in, nxlo_out, nxhi_out, nylo_out, nyhi_out, nzlo_out, nzhi_out); if (nvalues == 1) memory->create3d_offset(vec3d, nzlo_out, nzhi_out, nylo_out, nyhi_out, nxlo_out, nxhi_out, "property/grid:vec3d"); else memory->create4d_offset_last(array3d, nzlo_out, nzhi_out, nylo_out, nyhi_out, nxlo_out, nxhi_out, nvalues, "property/grid:array3d"); ngridout = (nxhi_out - nxlo_out + 1) * (nyhi_out - nylo_out + 1) * (nzhi_out - nzlo_out + 1); } } /* ---------------------------------------------------------------------- */ void ComputePropertyGrid::deallocate_grid() { delete grid2d; delete grid3d; memory->destroy2d_offset(vec2d, nylo_out, nxlo_out); memory->destroy3d_offset_last(array2d, nylo_out, nxlo_out); memory->destroy3d_offset(vec3d, nzlo_out, nylo_out, nxlo_out); memory->destroy4d_offset_last(array3d, nzlo_out, nylo_out, nxlo_out); } /* ---------------------------------------------------------------------- memory usage of grid data ------------------------------------------------------------------------- */ double ComputePropertyGrid::memory_usage() { double bytes = (double) ngridout * nvalues * sizeof(double); return bytes; } // ---------------------------------------------------------------------- // pack methods for all values // ---------------------------------------------------------------------- /* ---------------------------------------------------------------------- grid point IDs ------------------------------------------------------------------------- */ void ComputePropertyGrid::pack_id(int n) { if (dimension == 2) { if (nvalues == 1) { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) vec2d[iy][ix] = iy * nxgrid + ix + 1; } else { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) array2d[iy][ix][n] = iy * nxgrid + ix + 1; } } else if (dimension == 3) { if (nvalues == 1) { 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++) vec3d[iz][iy][ix] = iz * nygrid * nxgrid + iy * nxgrid + ix + 1; } 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++) array3d[iz][iy][ix][n] = iz * nygrid * nxgrid + iy * nxgrid + ix + 1; } } } /* ---------------------------------------------------------------------- grid point owning processor ------------------------------------------------------------------------- */ void ComputePropertyGrid::pack_proc(int n) { int me = comm->me; if (dimension == 2) { if (nvalues == 1) { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) vec2d[iy][ix] = me; } else { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) array2d[iy][ix][n] = me; } } else if (dimension == 3) { if (nvalues == 1) { 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++) vec3d[iz][iy][ix] = me; } 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++) array3d[iz][iy][ix][n] = me; } } } /* ---------------------------------------------------------------------- grid indices via templating ------------------------------------------------------------------------- */ template void ComputePropertyGrid::pack_indices(int n) { if (dimension == 2) { if (nvalues == 1) { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (IDIM == 0) vec2d[iy][ix] = ix + 1; if (IDIM == 1) vec2d[iy][ix] = iy + 1; } } else { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (IDIM == 0) array2d[iy][ix][n] = ix + 1; if (IDIM == 1) array2d[iy][ix][n] = iy + 1; } } } else if (dimension == 3) { if (nvalues == 1) { 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++) { if (IDIM == 0) vec3d[iz][iy][ix] = ix + 1; if (IDIM == 1) vec3d[iz][iy][ix] = iy + 1; if (IDIM == 2) vec3d[iz][iy][ix] = iz + 1; } } 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++) { if (IDIM == 0) array3d[iz][iy][ix][n] = ix + 1; if (IDIM == 1) array3d[iz][iy][ix][n] = iy + 1; if (IDIM == 2) array3d[iz][iy][ix][n] = iz + 1; } } } } /* ---------------------------------------------------------------------- grid point coords LOW/CTR, SCALED/UNSCALED, DIM = 0/1 via templating dimension and orthogonal/tricilic in code logic ------------------------------------------------------------------------- */ template void ComputePropertyGrid::pack_coords(int n) { double boxlo, delta; double lamda[3], xone[3]; // 2d grid if (dimension == 2) { // for coords which are orthogonal OR scaled if (!triclinic || MODE == SCALED) { if (MODE == UNSCALED) { boxlo = domain->boxlo[IDIM]; if (IDIM == 0) delta = domain->prd[IDIM] / nxgrid; if (IDIM == 1) delta = domain->prd[IDIM] / nygrid; } if (MODE == SCALED) { boxlo = 0.0; if (IDIM == 0) delta = 1.0 / nxgrid; if (IDIM == 1) delta = 1.0 / nygrid; } if (nvalues == 1) { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (POS == LOW) { if (IDIM == 0) vec2d[iy][ix] = boxlo + ix * delta; if (IDIM == 1) vec2d[iy][ix] = boxlo + iy * delta; } if (POS == CTR) { if (IDIM == 0) vec2d[iy][ix] = boxlo + (ix + 0.5) * delta; if (IDIM == 1) vec2d[iy][ix] = boxlo + (iy + 0.5) * delta; } } } else { for (int iy = nylo_in; iy <= nyhi_in; iy++) for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (POS == LOW) { if (IDIM == 0) array2d[iy][ix][n] = boxlo + ix * delta; if (IDIM == 1) array2d[iy][ix][n] = boxlo + iy * delta; } if (POS == CTR) { if (IDIM == 0) array2d[iy][ix][n] = boxlo + (ix + 0.5) * delta; if (IDIM == 1) array2d[iy][ix][n] = boxlo + (iy + 0.5) * delta; } } } // only for coords which are triclinic AND unscaled } else { double dx = 1.0 / nxgrid; double dy = 1.0 / nygrid; lamda[2] = 0.0; if (nvalues == 1) { for (int iy = nylo_in; iy <= nyhi_in; iy++) { if (POS == LOW) lamda[1] = iy * dy; else lamda[1] = (iy + 0.5) * dy; for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (POS == LOW) lamda[0] = ix * dx; else lamda[0] = (ix + 0.5) * dx; domain->lamda2x(lamda, xone); if (IDIM == 0) vec2d[iy][ix] = xone[0]; if (IDIM == 1) vec2d[iy][ix] = xone[1]; } } } else { for (int iy = nylo_in; iy <= nyhi_in; iy++) { if (POS == LOW) lamda[1] = iy * dy; else lamda[1] = (iy + 0.5) * dy; for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (POS == LOW) lamda[0] = ix * dx; else lamda[0] = (ix + 0.5) * dx; domain->lamda2x(lamda, xone); if (IDIM == 0) array2d[iy][ix][n] = xone[0]; if (IDIM == 1) array2d[iy][ix][n] = xone[1]; } } } } // 3d grid } else if (dimension == 3) { // for coords which are orthogonal OR scaled if (!triclinic || MODE == SCALED) { if (MODE == UNSCALED) { boxlo = domain->boxlo[IDIM]; if (IDIM == 0) delta = domain->prd[IDIM] / nxgrid; if (IDIM == 1) delta = domain->prd[IDIM] / nygrid; if (IDIM == 2) delta = domain->prd[IDIM] / nzgrid; } if (MODE == SCALED) { boxlo = 0.0; if (IDIM == 0) delta = 1.0 / nxgrid; if (IDIM == 1) delta = 1.0 / nygrid; if (IDIM == 2) delta = 1.0 / nzgrid; } if (nvalues == 1) { 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++) { if (POS == LOW) { if (IDIM == 0) vec3d[iz][iy][ix] = boxlo + ix * delta; if (IDIM == 1) vec3d[iz][iy][ix] = boxlo + iy * delta; if (IDIM == 2) vec3d[iz][iy][ix] = boxlo + iz * delta; } if (POS == CTR) { if (IDIM == 0) vec3d[iz][iy][ix] = boxlo + (ix + 0.5) * delta; if (IDIM == 1) vec3d[iz][iy][ix] = boxlo + (iy + 0.5) * delta; if (IDIM == 2) vec3d[iz][iy][ix] = boxlo + (iz + 0.5) * delta; } } } 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++) { if (POS == LOW) { if (IDIM == 0) array3d[iz][iy][ix][n] = boxlo + ix * delta; if (IDIM == 1) array3d[iz][iy][ix][n] = boxlo + iy * delta; if (IDIM == 2) array3d[iz][iy][ix][n] = boxlo + iz * delta; } if (POS == CTR) { if (IDIM == 0) array3d[iz][iy][ix][n] = boxlo + (ix + 0.5) * delta; if (IDIM == 1) array3d[iz][iy][ix][n] = boxlo + (iy + 0.5) * delta; if (IDIM == 2) array3d[iz][iy][ix][n] = boxlo + (iz + 0.5) * delta; } } } // only for coords which are triclinic AND unscaled } else { double dx = 1.0 / nxgrid; double dy = 1.0 / nygrid; double dz = 1.0 / nzgrid; if (nvalues == 1) { for (int iz = nzlo_in; iz <= nzhi_in; iz++) { if (POS == LOW) lamda[2] = iz * dz; else lamda[2] = (iz + 0.5) * dz; for (int iy = nylo_in; iy <= nyhi_in; iy++) { if (POS == LOW) lamda[1] = iy * dy; else lamda[1] = (iy + 0.5) * dy; for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (POS == LOW) lamda[0] = ix * dx; else lamda[0] = (ix + 0.5) * dx; domain->lamda2x(lamda, xone); if (IDIM == 0) vec3d[iz][iy][ix] = xone[0]; if (IDIM == 1) vec3d[iz][iy][ix] = xone[1]; if (IDIM == 2) vec3d[iz][iy][ix] = xone[2]; } } } } else { for (int iz = nzlo_in; iz <= nzhi_in; iz++) { if (POS == LOW) lamda[2] = iz * dz; else lamda[2] = (iz + 0.5) * dz; for (int iy = nylo_in; iy <= nyhi_in; iy++) { if (POS == LOW) lamda[1] = iy * dy; else lamda[1] = (iy + 0.5) * dy; for (int ix = nxlo_in; ix <= nxhi_in; ix++) { if (POS == LOW) lamda[0] = ix * dx; else lamda[0] = (ix + 0.5) * dx; domain->lamda2x(lamda, xone); if (IDIM == 0) array3d[iz][iy][ix][n] = xone[0]; if (IDIM == 1) array3d[iz][iy][ix][n] = xone[1]; if (IDIM == 2) array3d[iz][iy][ix][n] = xone[2]; } } } } } } }