From 348296e638628f3552deea0c6ef9a6a29805b527 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 15 Feb 2023 16:07:10 -0700 Subject: [PATCH 001/385] Adding base fix and atom style --- src/RHEO/atom_vec_rheo.cpp | 135 ++++++++++++++ src/RHEO/atom_vec_rheo.h | 45 +++++ src/RHEO/fix_rheo.cpp | 365 +++++++++++++++++++++++++++++++++++++ src/RHEO/fix_rheo.h | 91 +++++++++ src/atom.cpp | 20 ++ src/atom.h | 5 + 6 files changed, 661 insertions(+) create mode 100644 src/RHEO/atom_vec_rheo.cpp create mode 100644 src/RHEO/atom_vec_rheo.h create mode 100644 src/RHEO/fix_rheo.cpp create mode 100644 src/RHEO/fix_rheo.h diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp new file mode 100644 index 0000000000..9effad685c --- /dev/null +++ b/src/RHEO/atom_vec_rheo.cpp @@ -0,0 +1,135 @@ +/* ---------------------------------------------------------------------- + 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 "atom_vec_rheo.h" + +#include "atom.h" + +#include + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +AtomVecRHEO::AtomVecRHEO(LAMMPS *lmp) : AtomVec(lmp) +{ + molecular = Atom::ATOMIC; + mass_type = PER_TYPE; + forceclearflag = 1; + + atom->status_flag = 1; + atom->rho_flag = 1; + + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file + + fields_grow = {"status", "rho", "drho"}; + fields_copy = {"status", "rho", "drho"}; + fields_comm = {"status", "rho"}; + fields_comm_vel = {"status", "rho"}; + fields_reverse = {"drho"}; + fields_border = {"status", "rho"}; + fields_border_vel = {"status", "rho"}; + fields_exchange = {"status", "rho"}; + fields_restart = {"status", "rho"}; + fields_create = {"status", "rho", "drho"}; + fields_data_atom = {"id", "type", "status", "rho", "x"}; + fields_data_vel = {"id", "v"}; + + setup_fields(); +} + +/* ---------------------------------------------------------------------- + set local copies of all grow ptrs used by this class, except defaults + needed in replicate when 2 atom classes exist and it calls pack_restart() +------------------------------------------------------------------------- */ + +void AtomVecRHEO::grow_pointers() +{ + status = atom->status; + rho = atom->rho; + drho = atom->drho; +} + +/* ---------------------------------------------------------------------- + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector +------------------------------------------------------------------------- */ + +void AtomVecRHEO::force_clear(int n, size_t nbytes) +{ + memset(&drho[n], 0, nbytes); +} + +/* ---------------------------------------------------------------------- + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities +------------------------------------------------------------------------- */ + +void AtomVecRHEO::data_atom_post(int ilocal) +{ + drho[ilocal] = 0.0; +} + +/* ---------------------------------------------------------------------- + assign an index to named atom property and return index + return -1 if name is unknown to this atom style +------------------------------------------------------------------------- */ + +int AtomVecRHEO::property_atom(const std::string &name) +{ + if (name == "status") return 0; + if (name == "rho") return 1; + if (name == "drho") return 2; + return -1; +} + +/* ---------------------------------------------------------------------- + pack per-atom data into buf for ComputePropertyAtom + index maps to data specific to this atom style +------------------------------------------------------------------------- */ + +void AtomVecRHEO::pack_property_atom(int index, double *buf, int nvalues, int groupbit) +{ + int *mask = atom->mask; + int nlocal = atom->nlocal; + int n = 0; + + if (index == 0) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = status[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } if else (index == 1) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = rho[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 2) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = drho[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } +} diff --git a/src/RHEO/atom_vec_rheo.h b/src/RHEO/atom_vec_rheo.h new file mode 100644 index 0000000000..bdd617a01d --- /dev/null +++ b/src/RHEO/atom_vec_rheo.h @@ -0,0 +1,45 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef ATOM_CLASS +// clang-format off +AtomStyle(rheo,AtomVecRHEO); +// clang-format on +#else + +#ifndef LMP_ATOM_VEC_RHEO_H +#define LMP_ATOM_VEC_RHEO_H + +#include "atom_vec.h" + +namespace LAMMPS_NS { + +class AtomVecRHEO : virtual public AtomVec { + public: + AtomVecRHEO(class LAMMPS *); + + void grow_pointers() override; + void force_clear(int, size_t) override; + void data_atom_post(int) override; + int property_atom(const std::string &) override; + void pack_property_atom(int, double *, int, int) override; + + private: + int *status; + double *rho, *drho; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp new file mode 100644 index 0000000000..fd476d4c9e --- /dev/null +++ b/src/RHEO/fix_rheo.cpp @@ -0,0 +1,365 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 "fix_rheo.h" + +#include "atom.h" +#include "compute_rheo_grad.h" +#include "compute_rheo_interface.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_rhosum.h" +#include "compute_rheo_vshift.h" +#include "domain.h" +#include "error.h" +#include "force.h" +#include "modify.h" +#include "update.h" +#include "utils.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg), compute_grad(nullptr), compute_kernel(nullptr), + compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr) +{ + thermal_flag = 0; + rhosum_flag = 0; + shift_flag = 0; + solid_flag = 0; + rho0 = 1.0; + csq = 1.0; + + if (atom->rho_flag != 1) + error->all(FLERR,"fix rheo command requires atom_style with density"); + if (atom->status_flag != 1) + error->all(FLERR,"fix rheo command requires atom_style with status"); + + if (narg < 5) + error->all(FLERR,"Insufficient arguments for fix rheo command"); + + cut = utils::numeric(FLERR,arg[3],false,lmp); + if (strcmp(arg[4],"Quintic") == 0) { + kernel_style = QUINTIC; + } else if (strcmp(arg[4],"CRK0") == 0) { + kernel_style = CRK0; + } else if (strcmp(arg[4],"CRK1") == 0) { + kernel_style = CRK1; + } else if (strcmp(arg[4],"CRK2") == 0) { + kernel_style = CRK2; + } else error->all(FLERR,"Unknown kernel style {} in fix rheo", arg[4]); + zmin_kernel = utils::numeric(FLERR,arg[5],false,lmp); + + int iarg = 6; + while (iarg < narg){ + if (strcmp(arg[iarg],"shift") == 0) { + shift_flag = 1; + } else if (strcmp(arg[iarg],"thermal") == 0) { + thermal_flag = 1; + } else if (strcmp(arg[iarg],"rhosum") == 0) { + rhosum_flag = 1; + if(iarg + 1 >= narg) error->all(FLERR,"Illegal rhosum option in fix rheo"); + zmin_rhosum = utils::inumeric(FLERR,arg[iarg + 1],false,lmp); + iarg += 1; + } else if (strcmp(arg[iarg],"rho0") == 0) { + if(iarg + 1 >= narg) error->all(FLERR,"Illegal rho0 option in fix rheo"); + rho0 = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + iarg += 1; + } else if (strcmp(arg[iarg],"csq") == 0) { + if(iarg+1 >= narg) error->all(FLERR,"Illegal csq option in fix rheo"); + csq = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + iarg += 1; + } else { + error->all(FLERR, "Illegal fix rheo command: {}", arg[iarg]); + } + iarg += 1; + } + + time_integrate = 1; + thermal_fix_defined = 0; + viscosity_fix_defined = 0; + pressure_fix_defined = 0; +} + +/* ---------------------------------------------------------------------- */ + +FixRHEO::~FixRHEO() +{ + if (compute_kernel) modify->delete_compute("rheo_kernel"); + if (compute_grad) modify->delete_compute("rheo_grad"); + if (compute_interface) modify->delete_compute("rheo_interface"); + if (compute_rhosum) modify->delete_compute("rheo_rhosum"); + if (compute_vshift) modify->delete_compute("rheo_vshift"); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::post_constructor() +{ + compute_kernel = dynamic_cast(modify->add_compute(fmt::format("rheo_kernel all rheo/kernel {} {} {}", kernel_style, zmin_kernel, cut))); + + if (thermal_flag) + compute_grad = dynamic_cast(modify->add_compute(fmt::format("rheo_grad all rheo/grad {} velocity rho viscosity temprature", cut))); + else + compute_grad = dynamic_cast(modify->add_compute(fmt::format("rheo_grad all rheo/grad {} velocity rho viscosity", cut))); + + compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface {}", cut))); + + if (rhosum_flag) + compute_rhosum = dynamic_cast(modify->add_compute(fmt::format("rheo_rhosum all rheo/rho/sum {} {}", cut, zmin_rhosum))); + + if (shift_flag) + compute_vshift = dynamic_cast(modify->add_compute(fmt::format("rheo_vshift all rheo/vshift {}", cut))); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEO::setmask() +{ + int mask = 0; + mask |= INITIAL_INTEGRATE; + mask |= FINAL_INTEGRATE; + mask |= PRE_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::init() +{ + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::setup_pre_force(int /*vflag*/) +{ + // Check to confirm all accessory fixes are defined + if(!thermal_fix_defined && thermal_flag) + error->all(FLERR, "Missing fix rheo/thermal"); + + if (!viscosity_fix_defined) + error->all(FLERR, "Missing fix rheo/viscosity"); + + if (!pressure_fix_defined) + error->all(FLERR, "Missing fix rheo/pressure"); + + // Reset to zero for next run + thermal_fix_defined = 0; + viscosity_fix_defined = 0; + pressure_fix_defined = 0; + + pre_force(0); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::initial_integrate(int /*vflag*/) +{ + // update v and x and rho of atoms in group + int i, a, b; + double dtfm, divu; + int dim = domain->dimension; + + int *status = atom->status; + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + double *rho = atom->rho; + double *drho = atom->drho; + double *mass = atom->mass; + double *rmass = atom->rmass; + int rmass_flag = atom->rmass_flag; + + double **gradr = compute_grad->gradr; + double **gradv = compute_grad->gradv; + double **vshift = compute_vshift->array_atom; + + int *type = atom->type; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + + //Density Half-step + for (i = 0; i < nlocal; i++) { + if (status[i] & STATUS_NO_FORCE) continue; + + if (mask[i] & groupbit) { + if (rmass_flag) { + dtfm = dtf / rmass[i]; + } else { + dtfm = dtf / mass[type[i]]; + } + + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + } + } + + // Update gradients and interpolate solid properties + compute_grad->forward_fields(); // also forwards v and rho for chi + compute_interface->store_forces(); // Need to save, wiped in exchange + compute_interface->compute_peratom(); + compute_grad->compute_peratom(); + + // Position half-step + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + for (a = 0; a < dim; a++) { + x[i][a] += dtv * v[i][a]; + } + } + } + + // Update density using div(u) + if (!rhosum_flag) { + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + if (status[i] & STATUS_NO_FORCE) continue; + if (!(status[i] & STATUS_FLUID)) continue; + + divu = 0; + for (a = 0; a < dim; a++) { + divu += gradv[i][a * (1 + dim)]; + } + rho[i] += dtf * (drho[i] - rho[i] * divu); + } + } + } + + // Shifting atoms + if (shift_flag) { + compute_vshift->correct_surfaces(); + for (i = 0; i < nlocal; i++) { + + if (!(status[i] & STATUS_SHIFT)) continue; + + if (mask[i] & groupbit) { + for (a = 0; a < dim; a++) { + x[i][a] += dtv * vshift[i][a]; + for (b = 0; b < dim; b++) { + v[i][a] += dtv * vshift[i][b] * gradv[i][a * dim + b]; + } + } + + if (!rhosum_flag) { + for (a = 0; a < dim; a++) { + rho[i] += dtv * vshift[i][a] * gradr[i][a]; + } + } + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::pre_force(int /*vflag*/) +{ + if (rhosum_flag) + compute_rhosum->compute_peratom(); + + compute_grad->forward_fields(); // also forwards v and rho for chi + compute_kernel->compute_peratom(); + compute_interface->compute_peratom(); + + compute_grad->compute_peratom(); + compute_grad->forward_gradients(); + + if (shift_flag) + compute_vshift->compute_peratom(); + + // Remove extra shifting/no force options options + int *status = atom->status; + int nall = atom->nlocal + atom->nghost; + for (int i = 0; i < nall; i++) { + if (mask[i] & groupbit) { + status[i] &= ~STATUS_NO_FORCE; + + if (status[i] & STATUS_FLUID) + status[i] &= ~STATUS_SHIFT; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::final_integrate() { + int *status = atom->status; + double **gradv = compute_grad->gradv; + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + + double *rho = atom->rho; + double *drho = atom->drho; + int *type = atom->type; + int *mask = atom->mask; + double *mass = atom->mass; + int nlocal = atom->nlocal; + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + double dtfm, divu; + double *rmass = atom->rmass; + int rmass_flag = atom->rmass_flag; + int i, a; + + int dim = domain->dimension; + + // Update velocity + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + if (status[i] & STATUS_NO_FORCE) continue; + + if (rmass_flag) { + dtfm = dtf / rmass[i]; + } else { + dtfm = dtf / mass[type[i]]; + } + + for (a = 0; a < dim; a++) { + v[i][a] += dtfm * f[i][a]; + } + } + } + + // Update density using divu + if (!rhosum_flag) { + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + if (status[i] & STATUS_NO_FORCE) continue; + if (!(status[i] & STATUS_FLUID)) continue; + + divu = 0; + for (a = 0; a < dim; a++) { + divu += gradv[i][a * (1 + dim)]; + } + rho[i] += dtf * (drho[i] - rho[i] * divu); + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::reset_dt() +{ + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; +} diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h new file mode 100644 index 0000000000..8597eb2809 --- /dev/null +++ b/src/RHEO/fix_rheo.h @@ -0,0 +1,91 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS +// clang-format off +FixStyle(rheo,FixRHEO) +// clang-format on +#else + +#ifndef LMP_FIX_RHEO_H +#define LMP_FIX_RHEO_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixRHEO : public Fix { + public: + FixRHEO(class LAMMPS *, int, char **); + virtual ~FixRHEO(); + int setmask(); + virtual void post_constructor(); + virtual void init(); + virtual void setup_pre_force(int); + virtual void pre_force(int); + virtual void initial_integrate(int); + virtual void final_integrate(); + void reset_dt(); + + int kernel_style; + int thermal_flag; + int rhosum_flag; + int shift_flag; + int solid_flag; + + int thermal_fix_defined; + int viscosity_fix_defined; + int pressure_fix_defined; + + int *status, *surface; + double *conductivity, *viscosity, *pressure; + double **f_pressure; + + class ComputeRHEOGrad *compute_grad; + class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOInterface *compute_interface; + class ComputeRHEORhoSum *compute_rhosum; + class ComputeRHEOVShift *compute_vshift; + + enum {QUINTIC, CRK0, CRK1, CRK2}; + enum {LINEAR, CUBIC, TAITWATER}; + + enum { + // Phase status + STATUS_FLUID = 1 << 0, + STATUS_REACTIVE = 1 << 1, + STATUS_SOLID = 1 << 2, + STATUS_FREEZING = 1 << 3 + + // Temporary status options - reset in preforce + STATUS_SHIFT = 1 << 4, + STATUS_NO_FORCE = 1 << 5, + + // Surface status + STATUS_BULK = 1 << 6, + STATUS_LAYER = 1 << 7, + STATUS_SURFACE = 1 << 8, + STATUS_SPLASH = 1 << 9, + }; + + protected: + double cut, rho0, csq; + int zmin_kernel, rhosum_zmin; + + double dtv, dtf; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/atom.cpp b/src/atom.cpp index 32285758c0..e2613c801e 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -195,6 +195,10 @@ Atom::Atom(LAMMPS *_lmp) : Pointers(_lmp) eff_plastic_strain_rate = nullptr; damage = nullptr; + // RHEO package + + status = nullptr; + // SPH package rho = drho = esph = desph = cv = nullptr; @@ -521,6 +525,10 @@ void Atom::peratom_create() add_peratom("cc",&cc,DOUBLE,1); add_peratom("cc_flux",&cc_flux,DOUBLE,1,1); // set per-thread flag + // RHEO package + + add_peratom("status",&status,INT,0); + // SPH package add_peratom("rho",&rho,DOUBLE,0); @@ -625,6 +633,7 @@ void Atom::set_atomflag_defaults() rmass_flag = radius_flag = omega_flag = torque_flag = angmom_flag = 0; vfrac_flag = spin_flag = eradius_flag = ervel_flag = erforce_flag = 0; cs_flag = csforce_flag = vforce_flag = ervelforce_flag = etag_flag = 0; + status_flag = 0; rho_flag = esph_flag = cv_flag = vest_flag = 0; dpd_flag = edpd_flag = tdpd_flag = 0; sp_flag = 0; @@ -2911,7 +2920,12 @@ void *Atom::extract(const char *name) if (strcmp(name,"vforce") == 0) return (void *) vforce; if (strcmp(name,"etag") == 0) return (void *) etag; + // RHEO package + + if (strcmp(name,"status") == 0) return (void *) status; + // SPH package + if (strcmp(name,"rho") == 0) return (void *) rho; if (strcmp(name,"drho") == 0) return (void *) drho; if (strcmp(name,"esph") == 0) return (void *) esph; @@ -3030,6 +3044,12 @@ int Atom::extract_datatype(const char *name) if (strcmp(name,"vforce") == 0) return LAMMPS_DOUBLE_2D; if (strcmp(name,"etag") == 0) return LAMMPS_INT; + // RHEO package + + if (strcmp(name,"status") == 0) return LAMMPS_INT; + + // SPH package + if (strcmp(name,"rho") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"drho") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"esph") == 0) return LAMMPS_DOUBLE; diff --git a/src/atom.h b/src/atom.h index 20f2021947..52cec2b1bb 100644 --- a/src/atom.h +++ b/src/atom.h @@ -154,6 +154,10 @@ class Atom : protected Pointers { double *eff_plastic_strain_rate; double *damage; + // RHEO package + + int *status; + // SPH package double *rho, *drho, *esph, *desph, *cv; @@ -188,6 +192,7 @@ class Atom : protected Pointers { int rmass_flag, radius_flag, omega_flag, torque_flag, angmom_flag, quat_flag; int vfrac_flag, spin_flag, eradius_flag, ervel_flag, erforce_flag; int cs_flag, csforce_flag, vforce_flag, ervelforce_flag, etag_flag; + int status_flag; int rho_flag, esph_flag, cv_flag, vest_flag; int dpd_flag, edpd_flag, tdpd_flag; int mesont_flag; From 6cbade576c7d5726226dbb7236d81bb5f5ddfed4 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 19 Feb 2023 20:41:33 -0700 Subject: [PATCH 002/385] Adding gradient compute, minor patch bond history --- src/RHEO/compute_rheo_grad.cpp | 457 +++++++++++++++++++++++++++++++++ src/RHEO/compute_rheo_grad.h | 62 +++++ src/RHEO/fix_rheo.cpp | 1 + src/fix_bond_history.cpp | 4 +- 4 files changed, 522 insertions(+), 2 deletions(-) create mode 100644 src/RHEO/compute_rheo_grad.cpp create mode 100644 src/RHEO/compute_rheo_grad.h diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp new file mode 100644 index 0000000000..33dd3dc3bc --- /dev/null +++ b/src/RHEO/compute_rheo_grad.cpp @@ -0,0 +1,457 @@ +/* ---------------------------------------------------------------------- + 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_rheo_grad.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_solids.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "pair.h" +#include "memory.h" +#include "modify.h" +#include "update.h" +#include "utils.h" + +#include +#include + +using namespace LAMMPS_NS; +enum{COMMGRAD, COMMFIELD}; + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), compute_interface(nullptr), compute_kernel(nullptr) +{ + if (narg < 4) error->all(FLERR,"Illegal compute rheo/grad command"); + + + velocity_flag = temperature_flag = rho_flag = eta_flag = 0; + for (int iarg = 3; iarg < narg; iarg ++) { + if (strcmp(arg[iarg],"velocity") == 0) velocity_flag = 1; + else if (strcmp(arg[iarg],"rho") == 0) rho_flag = 1; + else if (strcmp(arg[iarg],"temperature") == 0) temperature_flag = 1; + else if (strcmp(arg[iarg],"viscosity") == 0) eta_flag = 1; + else error->all(FLERR, "Illegal compute rheo/grad command, {}", arg[iarg]); + } + + dim = domain->dimension; + + ncomm_grad = 0; + ncomm_field = 0; + comm_reverse = 0; + + std::string fix_cmd = "rheo_grad_property_atom all property/atom" + + if (velocity_flag) { + ncomm_grad += dim * dim; + ncomm_field += dim; + comm_reverse += dim * dim; + fix_cmd += " d2_gradv 9" + } + + if (rho_flag) { + ncomm_grad += dim; + ncomm_field += 1; + comm_reverse += dim; + fix_cmd += " d2_gradr 3" + } + + if (temperature_flag) { + ncomm_grad += dim; + ncomm_field += 1; + comm_reverse += dim; + fix_cmd += " d2_gradt 3" + } + + if (eta_flag) { + ncomm_grad += dim; + comm_reverse += dim; + fix_cmd += " d2_gradn 3" + } + + comm_forward = ncomm_grad; + + modify->add_fix(fix_cmd); + + int tmp1, tmp2, index; + if (velocity_flag) { + index = atom->find_custom("gradv", tmp1, tmp2); + gradv = atom->darray[index]; + } + + if (rho_flag) { + index = atom->find_custom("gradr", tmp1, tmp2); + gradr = atom->darray[index]; + } + + if (temperature_flag) { + index = atom->find_custom("gradt", tmp1, tmp2); + gradt = atom->darray[index]; + } + + if (eta_flag) { + index = atom->find_custom("gradn", tmp1, tmp2); + gradn = atom->darray[index]; + } +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOGrad::~ComputeRHEOGrad() +{ + modify->delete_fix("rheo_grad_property_atom"); +} + + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::init() +{ + neighbor->add_request(this, NeighConst::REQ_DEFAULT); + + cut = fix_rheo->cut; + cutsq = cut * cut; + rho0 = fix_rheo->rho0; + compute_kernel = fix_rheo->compute_kernel; + compute_interface = fix_rheo->compute_interface; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::compute_peratom() +{ + int i, j, k, ii, jj, jnum, itype, jtype, a, b; + double xtmp, ytmp, ztmp, delx, dely, delz; + double rsq, imass, jmass; + double rhoi, rhoj, Voli, Volj, drho, dT, deta; + double vij[3]; + double wp, *dWij, *dWji; + + int inum, *ilist, *numneigh, **firstneigh; + int *jlist; + int nlocal = atom->nlocal; + + double **x = atom->x; + double **v = atom->v; + double *rho = atom->rho; + double *temperature = atom->temperature; + double *eta = atom->viscosity; + int *status = atom->status; + int *type = atom->type; + double *mass = atom->mass; + int newton = force->newton; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // initialize arrays + for (i = 0; i < nmax; i++) { + if (velocity_flag) { + for (k = 0; k < dim * dim; k++) + gradv[i][k] = 0.0; + } + if (rho_flag) { + for (k = 0; k < dim; k++) + gradr[i][k] = 0.0; + } + if (temperature_flag) { + for (k = 0; k < dim; k++) + gradt[i][k] = 0.0; + } + if (eta_flag) { + for (k = 0; k < dim; k++) + gradn[i][k] = 0.0; + } + } + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + jtype = type[j]; + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + + if (rsq < cutsq) { + rhoi = rho[i]; + rhoj = rho[j]; + + // Add corrections for walls + if ((status[i] & FixRHEO::STATUS_FLUID) && !(status[j] & FixRHEO::STATUS_FLUID)) { + compute_interface->correct_v(v[i], v[j], vi, i, j); + rhoj = compute_interface->correct_rho(j,i); + } else if (!(status[i] & FixRHEO::STATUS_FLUID) && (status[j] & FixRHEO::STATUS_FLUID)) { + compute_interface->correct_v(v[j], v[i], vj, j, i); + rhoi = compute_interface->correct_rho(i,j); + } else if (!(status[i] & FixRHEO::STATUS_FLUID) && !(status[j] & FixRHEO::STATUS_FLUID)) { + rhoi = rho0; + rhoj = rho0; + } + + Voli = mass[itype] / rhoi; + Volj = mass[jtype] / rhoj; + + vij[0] = v[i][0] - v[j][0]; + vij[1] = v[i][1] - v[j][1]; + vij[2] = v[i][2] - v[j][2]; + + if (rho_flag) drho = rhoi - rhoj; + if (temperature_flag) dT = temperature[i] - temperature[j]; + if (eta_flag) deta = eta[i] - eta[j]; + + wp = compute_kernel->calc_dw(i, j, delx, dely, delz, sqrt(rsq)); + dWij = compute_kernel->dWij; + dWji = compute_kernel->dWji; + + for (a = 0; a < dim; a++) { + for (b = 0; b < dim; b++) { + if (velocity_flag) // uxx uxy uxz uyx uyy uyz uzx uzy uzz + gradv[i][a * dim + b] -= vij[a] * Volj * dWij[b]; + } + + if (rho_flag) // P,x P,y P,z + gradr[i][a] -= drho * Volj * dWij[a]; + + if (temperature_flag) // T,x T,y T,z + gradt[i][a] -= dT * Volj * dWij[a]; + + if (eta_flag) // n,x n,y n,z + gradn[i][a] -= deta * Volj * dWij[a]; + } + + if (newton || j < nlocal) { + for (a = 0; a < dim; a++) { + for (b = 0; b < dim; b++) { + if (velocity_flag) // uxx uxy uxz uyx uyy uyz uzx uzy uzz + gradv[j][a * dim + b] += vij[a] * Voli * dWji[b]; + } + + if (rho_flag) // P,x P,y P,z + gradr[j][a] += drho * Voli * dWji[a]; + + if (temperature_flag) // T,x T,y T,z + gradt[j][a] += dT * Voli * dWji[a]; + + if (eta_flag) // n,x n,y n,z + gradn[j][a] += deta * Voli * dWji[a]; + } + } + } + } + } + + if (newton) comm->reverse_comm(this); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::forward_gradients() +{ + comm_stage = COMMGRAD; + comm_forward = ncomm_grad; + comm->forward_comm(this); +} + + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::forward_fields() +{ + comm_stage = COMMFIELD; + comm_forward = ncomm_field; + comm->forward_comm(this); +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,k,m; + double *rho = atom->rho; + double *temperature = atom->temperature; + double *eta = atom->viscosity; + double **v = atom->v; + + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + if (comm_stage == COMMGRAD) { + + if (velocity_flag){ + for (k = 0; k < dim * dim; k++) + buf[m++] = gradv[j][k]; + } + + if (rho_flag) { + for (k = 0; k < dim; k++) + buf[m++] = gradr[j][k]; + } + + if (temperature_flag) { + for (k = 0; k < dim; k++) + buf[m++] = gradt[j][k]; + } + + if (eta_flag){ + for (k = 0; k < dim; k++) + buf[m++] = gradn[j][k]; + } + } else if (comm_stage == COMMFIELD) { + + if (velocity_flag) { + for (k = 0; k < dim; k++) + buf[m++] = v[j][k]; + } + + if (rho_flag) { + buf[m++] = rho[j]; + } + + if (temperature_flag) { + buf[m++] = temperature[j]; + } + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double * rho = atom->rho; + double * temperature = atom->temperature; + double ** v = atom->v; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (comm_stage == COMMGRAD) { + if (velocity_flag) { + for (k = 0; k < dim * dim; k++) + gradv[i][k] = buf[m++]; + } + if (rho_flag) { + for (k = 0; k < dim; k++) + gradr[i][k] = buf[m++]; + } + if (temperature_flag) { + for (k = 0; k < dim; k++) + gradt[i][k] = buf[m++]; + } + if (eta_flag) { + for (k = 0; k < dim; k++) + gradn[i][k] = buf[m++]; + } + } else if (comm_stage == COMMFIELD) { + if (velocity_flag) { + for (k = 0; k < dim; k++) + v[i][k] = buf[m++]; + } + if (rho_flag) { + rho[i] = buf[m++]; + } + if (temperature_flag) { + temperature[i] = buf[m++]; + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOGrad::pack_reverse_comm(int n, int first, double *buf) +{ + int i,k,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (velocity_flag) { + for (k = 0; k < dim * dim; k++) + buf[m++] = gradv[i][k]; + } + if (rho_flag) { + for (k = 0; k < dim; k++) + buf[m++] = gradr[i][k]; + } + if (temperature_flag) { + for (k = 0; k < dim; k++) + buf[m++] = gradt[i][k]; + } + if (eta_flag) { + for (k = 0; k < dim; k++) + buf[m++] = gradn[i][k]; + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i,k,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + if (velocity_flag) { + for (k = 0; k < dim * dim; k++) + gradv[j][k] += buf[m++]; + } + if (rho_flag) { + for (k = 0; k < dim; k++) + gradr[j][k] += buf[m++]; + } + if (temperature_flag) { + for (k = 0; k < dim; k++) + gradt[j][k] += buf[m++]; + } + if (eta_flag) { + for (k = 0; k < dim; k++) + gradn[j][k] += buf[m++]; + } + } +} diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h new file mode 100644 index 0000000000..8b8e28fd98 --- /dev/null +++ b/src/RHEO/compute_rheo_grad.h @@ -0,0 +1,62 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(rheo/grad,ComputeRHEOGrad) +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_GRAD_H +#define LMP_COMPUTE_RHEO_GRAD_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEOGrad : public Compute { + public: + ComputeRHEOGrad(class LAMMPS *, int, char **); + ~ComputeRHEOGrad(); + void init(); + void init_list(int, class NeighList *); + void compute_peratom(); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + int pack_reverse_comm(int, int, double *); + void unpack_reverse_comm(int, int *, double *); + void forward_gradients(); + void forward_fields(); + double **gradv; + double **gradr; + double **gradt; + double **gradn; + int stage; + + private: + int dim, comm_stage; + int ncomm_grad, ncomm_field; + double cut, cutsq, rho0; + class NeighList *list; + + class FixRHEO *fix_rheo; + class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOInterface *compute_interface; + + int velocity_flag, temperature_flag, rho_flag, eta_flag; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index fd476d4c9e..17108b4c91 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -114,6 +114,7 @@ void FixRHEO::post_constructor() compute_grad = dynamic_cast(modify->add_compute(fmt::format("rheo_grad all rheo/grad {} velocity rho viscosity temprature", cut))); else compute_grad = dynamic_cast(modify->add_compute(fmt::format("rheo_grad all rheo/grad {} velocity rho viscosity", cut))); + compute_grad->fix_rheo = this; compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface {}", cut))); diff --git a/src/fix_bond_history.cpp b/src/fix_bond_history.cpp index cae9dc744d..277df75085 100644 --- a/src/fix_bond_history.cpp +++ b/src/fix_bond_history.cpp @@ -97,7 +97,7 @@ void FixBondHistory::post_constructor() void FixBondHistory::update_atom_value(int i, int m, int idata, double value) { - if (idata >= ndata || m > nbond) error->all(FLERR, "Index exceeded in fix bond history"); + if (idata >= ndata || m > nbond) error->one(FLERR, "Index exceeded in fix bond history"); atom->darray[index][i][m * ndata + idata] = value; } @@ -105,7 +105,7 @@ void FixBondHistory::update_atom_value(int i, int m, int idata, double value) double FixBondHistory::get_atom_value(int i, int m, int idata) { - if (idata >= ndata || m > nbond) error->all(FLERR, "Index exceeded in fix bond history"); + if (idata >= ndata || m > nbond) error->one(FLERR, "Index exceeded in fix bond history"); return atom->darray[index][i][m * ndata + idata]; } From 560bd90e1149bd880600b1edea291b7b2f1963cb Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 19 Feb 2023 22:08:02 -0700 Subject: [PATCH 003/385] Drafting viscosity fix --- src/RHEO/compute_rheo_grad.cpp | 11 +- src/RHEO/compute_rheo_grad.h | 16 +-- src/RHEO/fix_rheo.cpp | 9 ++ src/RHEO/fix_rheo.h | 3 +- src/RHEO/fix_rheo_viscosity.cpp | 198 ++++++++++++++++++++++++++++++++ src/RHEO/fix_rheo_viscosity.h | 49 ++++++++ 6 files changed, 272 insertions(+), 14 deletions(-) create mode 100644 src/RHEO/fix_rheo_viscosity.cpp create mode 100644 src/RHEO/fix_rheo_viscosity.h diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 33dd3dc3bc..e87d39aa53 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -23,11 +23,8 @@ #include "force.h" #include "neighbor.h" #include "neigh_list.h" -#include "pair.h" -#include "memory.h" #include "modify.h" #include "update.h" -#include "utils.h" #include #include @@ -52,14 +49,13 @@ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : else error->all(FLERR, "Illegal compute rheo/grad command, {}", arg[iarg]); } - dim = domain->dimension; - ncomm_grad = 0; ncomm_field = 0; comm_reverse = 0; std::string fix_cmd = "rheo_grad_property_atom all property/atom" + int dim = domain->dimension; if (velocity_flag) { ncomm_grad += dim * dim; ncomm_field += dim; @@ -165,6 +161,7 @@ void ComputeRHEOGrad::compute_peratom() int *type = atom->type; double *mass = atom->mass; int newton = force->newton; + int dim = domain->dimension; inum = list->inum; ilist = list->ilist; @@ -310,6 +307,7 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, double *temperature = atom->temperature; double *eta = atom->viscosity; double **v = atom->v; + int dim = domain->dimension; m = 0; @@ -363,6 +361,7 @@ void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) double * rho = atom->rho; double * temperature = atom->temperature; double ** v = atom->v; + int dim = domain->dimension; m = 0; last = first + n; @@ -404,6 +403,7 @@ void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) int ComputeRHEOGrad::pack_reverse_comm(int n, int first, double *buf) { int i,k,m,last; + int dim = domain->dimension; m = 0; last = first + n; @@ -433,6 +433,7 @@ int ComputeRHEOGrad::pack_reverse_comm(int n, int first, double *buf) void ComputeRHEOGrad::unpack_reverse_comm(int n, int *list, double *buf) { int i,k,j,m; + int dim = domain->dimension; m = 0; for (i = 0; i < n; i++) { diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 8b8e28fd98..35b50ca834 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -28,13 +28,13 @@ class ComputeRHEOGrad : public Compute { public: ComputeRHEOGrad(class LAMMPS *, int, char **); ~ComputeRHEOGrad(); - void init(); - void init_list(int, class NeighList *); - void compute_peratom(); - int pack_forward_comm(int, int *, double *, int, int *); - void unpack_forward_comm(int, int, double *); - int pack_reverse_comm(int, int, double *); - void unpack_reverse_comm(int, int *, double *); + void init() override; + void init_list(int, class NeighList *) override; + void compute_peratom() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; void forward_gradients(); void forward_fields(); double **gradv; @@ -44,7 +44,7 @@ class ComputeRHEOGrad : public Compute { int stage; private: - int dim, comm_stage; + int comm_stage; int ncomm_grad, ncomm_field; double cut, cutsq, rho0; class NeighList *list; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 17108b4c91..b77a35dd95 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -123,6 +123,12 @@ void FixRHEO::post_constructor() if (shift_flag) compute_vshift = dynamic_cast(modify->add_compute(fmt::format("rheo_vshift all rheo/vshift {}", cut))); + + + //todo here + //allocate memory for viscosity, pressure, etc + //don't want to save to restart/datafiles (could disable fix store/state) + //but do want it available for dupm files } /* ---------------------------------------------------------------------- */ @@ -142,6 +148,9 @@ void FixRHEO::init() { dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; + + if (modify->get_fix_by_style("rheo").size() > 1) + error->all(FLERR,"Can only specify one instance of fix rheo"); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 8597eb2809..24be629efe 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -47,7 +47,8 @@ class FixRHEO : public Fix { int viscosity_fix_defined; int pressure_fix_defined; - int *status, *surface; + // Non-persistent per-atom arrays are initialized here + int *surface; double *conductivity, *viscosity, *pressure; double **f_pressure; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp new file mode 100644 index 0000000000..9f7d3cf23c --- /dev/null +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -0,0 +1,198 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 "fix_rheo_viscosity.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_grad.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "memory.h" +#include "modify.h" +#include "update.h" + +#include + +using namespace LAMMPS_NS; +using namespace FixConst; +enum {NONE, CONSTANT, TYPE, POWER}; + +/* ---------------------------------------------------------------------- */ + +FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg), eta_type(nullptr) +{ + if (narg < 4) error->all(FLERR,"Illegal fix command"); + + viscosity_style = NONE; + + comm_forward = 1; + + int ntypes = atom->ntypes; + int iarg = 3; + if (strcmp(arg[iarg],"constant") == 0) { + if (iarg+1 >= narg) error->all(FLERR,"Insufficient arguments for fix rheo/viscosity"); + viscosity_style = CONSTANT; + eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + if (eta < 0.0) error->all(FLERR,"The viscosity must be positive in fix rheo/viscosity"); + iarg += 1; + } else if (strcmp(arg[iarg],"type") == 0) { + if(iarg+ntypes >= narg) error->all(FLERR,"Insufficient arguments for fix rheo/viscosity"); + viscosity_style = TYPE; + memory->create(eta_type, ntypes + 1, "rheo_thermal:eta_type"); + for (int i = 1; i <= ntypes; i++) { + eta_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i], false, lmp); + if (eta_type[i] < 0.0) error->all(FLERR,"The viscosity must be positive in fix rheo/viscosity"); + } + iarg += ntypes; + } else if (strcmp(arg[iarg],"power") == 0) { + if (iarg+4 >= narg) error->all(FLERR,"Insufficient arguments for fix rheo/viscosity"); + viscosity_style = POWER; + eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + gd0 = utils::numeric(FLERR,arg[iarg + 2],false,lmp); + K = utils::numeric(FLERR,arg[iarg + 3],false,lmp); + npow = utils::numeric(FLERR,arg[iarg + 4],false,lmp); + tau0 = eta * gd0 - K * pow(gd0, npow); + if (eta < 0.0) error->all(FLERR,"The viscosity must be positive in fix rheo/viscosity"); + iarg += 5; + } else { + error->all(FLERR,"Illegal fix command, {}", arg[iarg]); + } + + if (viscosity_style == NONE) + error->all(FLERR,"Must specify viscosity style for fix/rheo/viscosity"); +} + +/* ---------------------------------------------------------------------- */ + +FixRHEOViscosity::~FixRHEOViscosity() +{ + memory->destroy(eta_type); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOViscosity::setmask() +{ + int mask = 0; + mask |= PRE_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOViscosity::init() +{ + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); + fix_rheo = dynamic_cast(fixes[0]); + + fix_rheo->viscosity_fix_defined = 1; + compute_grad = fix_rheo->compute_grad; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOViscosity::setup_pre_force(int /*vflag*/) +{ + // Identify whether this is the last instance of fix viscosity + // Will handle communication + last_flag = 0; + + int i = 0; + auto fixlist = modify->get_fix_by_style("rheo/viscosity"); + for (const auto &ifix : fixlist) { + if (strcmp(ifix->id, id) == 0) break; + i++; + } + + if ((i + 1) == fixlist.size()) last_flag = 1; + + pre_force(0); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOViscosity::pre_force(int /*vflag*/) +{ + int i, a, b; + double tmp, gdot; + + int *type = atom->type; + double *viscosity = fix_rheo->viscosity; + int *mask = atom->mask; + double **gradv = compute_grad->gradv; + + int nlocal = atom->nlocal; + int dim = domain->dimension; + + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + if (viscosity_style == CONSTANT) { + viscosity[i] = eta; + } else if (viscosity_style == TYPE) { + viscosity[i] = eta_type[type[i]]; + } else if (viscosity_style == POWER) { + gdot = 0.0; + for (a = 0; a < dim; a++) { + for (b = a; b < dim; b++) { + tmp = gradv[i][a * dim + b] + gradv[i][b * dim + a]; + tmp = tmp * tmp; + if (a == b) tmp *= 0.5; + gdot += tmp; + } + } + gdot = sqrt(gdot); + if (gdot <= gd0) { + viscosity[i] = eta; + } else { + viscosity[i] = K * pow(gdot, npow - 1) + tau0 / gdot; + } + } + } + } + + if (last_flag) comm->forward_comm(this); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOViscosity::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,k,m; + double *viscosity = fix_rheo->viscosity; + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = viscosity[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double *viscosity = fix_rheo->viscosity; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + viscosity[i] = buf[m++]; + } +} diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h new file mode 100644 index 0000000000..130d4d8cc8 --- /dev/null +++ b/src/RHEO/fix_rheo_viscosity.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS +// clang-format off +FixStyle(rheo/viscosity,FixRHEOViscosity) +// clang-format on +#else + +#ifndef LMP_FIX_RHEO_VISCOSITY_H +#define LMP_FIX_RHEO_VISCOSITY_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixRHEOViscosity : public Fix { + public: + FixRHEOViscosity(class LAMMPS *, int, char **); + ~FixRHEOViscosity(); + int setmask() override; + void init() override; + virtual void setup_pre_force(int) override; + void pre_force(int) override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + private: + double *eta_type, eta; + double npow, K, gd0, tau0; + int viscosity_style; + int last_flag; + class FixRHEO *fix_rheo; + class ComputeRHEOGrad *compute_grad; +}; + +} // namespace LAMMPS_NS + +#endif +#endif From 4ac7a228b5ebcb6ba656713179d8ac331417ed6f Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 20 Feb 2023 12:47:51 -0700 Subject: [PATCH 004/385] Revamping atom data storage in fixes --- src/RHEO/fix_rheo.cpp | 84 +++++++++++++++++++++++++-------- src/RHEO/fix_rheo.h | 14 ++++-- src/RHEO/fix_rheo_viscosity.cpp | 13 ++++- src/RHEO/fix_rheo_viscosity.h | 3 +- 4 files changed, 88 insertions(+), 26 deletions(-) diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index b77a35dd95..f5a5f8b151 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -21,6 +21,7 @@ #include "compute_rheo_vshift.h" #include "domain.h" #include "error.h" +#include "fix_store_peratom.h" #include "force.h" #include "modify.h" #include "update.h" @@ -33,15 +34,30 @@ using namespace FixConst; FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), compute_grad(nullptr), compute_kernel(nullptr), - compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr) + compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr), + fix_store_visc(nullptr), fix_store_pres(nullptr), fix_store_cond(nullptr), + fix_store_surf(nullptr), fix_store_fp(nullptr), surface(nullptr), conductivity(nullptr), + viscosity(nullptr), pressure(nullptr), f_pressure(nullptr) { + time_integrate = 1; + + viscosity_fix_defined = 0; + pressure_fix_defined = 0; + thermal_fix_defined = 0; + surface_fix_defined = 0; + thermal_flag = 0; rhosum_flag = 0; shift_flag = 0; - solid_flag = 0; + interface_flag = 0; + surface_flag = 0; + rho0 = 1.0; csq = 1.0; + if (igroup != 0) + error->all(FLERR,"fix rheo command requires group all"); + if (atom->rho_flag != 1) error->all(FLERR,"fix rheo command requires atom_style with density"); if (atom->status_flag != 1) @@ -68,6 +84,10 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : shift_flag = 1; } else if (strcmp(arg[iarg],"thermal") == 0) { thermal_flag = 1; + } else if (strcmp(arg[iarg],"surface/detection") == 0) { + surface_flag = 1; + } else if (strcmp(arg[iarg],"interface/reconstruction") == 0) { + interface_flag = 1; } else if (strcmp(arg[iarg],"rhosum") == 0) { rhosum_flag = 1; if(iarg + 1 >= narg) error->all(FLERR,"Illegal rhosum option in fix rheo"); @@ -86,17 +106,18 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : } iarg += 1; } - - time_integrate = 1; - thermal_fix_defined = 0; - viscosity_fix_defined = 0; - pressure_fix_defined = 0; } /* ---------------------------------------------------------------------- */ FixRHEO::~FixRHEO() { + if (fix_store_visc) modify->delete_fix("rheo_store_visc"); + if (fix_store_pres) modify->delete_fix("rheo_store_pres"); + if (fix_store_surf) modify->delete_fix("rheo_store_surf"); + if (fix_store_cond) modify->delete_fix("rheo_store_cond"); + if (fix_store_fp) modify->delete_fix("rheo_store_fp"); + if (compute_kernel) modify->delete_compute("rheo_kernel"); if (compute_grad) modify->delete_compute("rheo_grad"); if (compute_interface) modify->delete_compute("rheo_interface"); @@ -110,13 +131,18 @@ void FixRHEO::post_constructor() { compute_kernel = dynamic_cast(modify->add_compute(fmt::format("rheo_kernel all rheo/kernel {} {} {}", kernel_style, zmin_kernel, cut))); - if (thermal_flag) - compute_grad = dynamic_cast(modify->add_compute(fmt::format("rheo_grad all rheo/grad {} velocity rho viscosity temprature", cut))); - else - compute_grad = dynamic_cast(modify->add_compute(fmt::format("rheo_grad all rheo/grad {} velocity rho viscosity", cut))); - compute_grad->fix_rheo = this; + fix_store_visc = dynamic_cast(modify->add_fix("rheo_store_visc all STORE/PERATOM 0 1")) + fix_store_visc->disable = 1; + viscosity = fix_store_visc->vstore; + fix_store_pres = dynamic_cast(modify->add_fix("rheo_store_pres all STORE/PERATOM 0 1")) + pressure = fix_store_pres->vstore; + fix_store_pres->disable = 1; - compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface {}", cut))); + + std::string cmd = "rheo_grad all rheo/grad {} velocity rho viscosity"; + if (thermal_flag) cmd += "temperature"; + compute_grad = dynamic_cast(modify->add_compute(fmt::format(cmd, cut))); + compute_grad->fix_rheo = this; if (rhosum_flag) compute_rhosum = dynamic_cast(modify->add_compute(fmt::format("rheo_rhosum all rheo/rho/sum {} {}", cut, zmin_rhosum))); @@ -124,11 +150,25 @@ void FixRHEO::post_constructor() if (shift_flag) compute_vshift = dynamic_cast(modify->add_compute(fmt::format("rheo_vshift all rheo/vshift {}", cut))); + if (surface_flag) { + fix_store_surf = dynamic_cast(modify->add_fix("rheo_store_surf all STORE/PERATOM 0 1")) + surface = fix_store_surf->vstore; + fix_store_surf->disable = 1; + } - //todo here - //allocate memory for viscosity, pressure, etc - //don't want to save to restart/datafiles (could disable fix store/state) - //but do want it available for dupm files + if (thermal_flag) { + fix_store_cond = dynamic_cast(modify->add_fix("rheo_store_cond all STORE/PERATOM 0 1")) + conductivity = fix_store_cond->vstore; + fix_store_cond->disable = 1; + } + + if (interface_flag) { + compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface {}", cut))); + + fix_store_fp = dynamic_cast(modify->add_fix("rheo_store_fp all STORE/PERATOM 0 3")) + f_pressure = fix_store_fp->astore; + fix_store_fp->disable = 1; + } } /* ---------------------------------------------------------------------- */ @@ -158,19 +198,23 @@ void FixRHEO::init() void FixRHEO::setup_pre_force(int /*vflag*/) { // Check to confirm all accessory fixes are defined - if(!thermal_fix_defined && thermal_flag) - error->all(FLERR, "Missing fix rheo/thermal"); - if (!viscosity_fix_defined) error->all(FLERR, "Missing fix rheo/viscosity"); if (!pressure_fix_defined) error->all(FLERR, "Missing fix rheo/pressure"); + if(!thermal_fix_defined && thermal_flag) + error->all(FLERR, "Missing fix rheo/thermal"); + + if(!surface_fix_defined && surface_flag) + error->all(FLERR, "Missing fix rheo/surface"); + // Reset to zero for next run thermal_fix_defined = 0; viscosity_fix_defined = 0; pressure_fix_defined = 0; + surface_fix_defined = 0; pre_force(0); } diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 24be629efe..1e35701278 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -41,17 +41,25 @@ class FixRHEO : public Fix { int thermal_flag; int rhosum_flag; int shift_flag; - int solid_flag; + int interface_flag; + int surface_flag; - int thermal_fix_defined; int viscosity_fix_defined; int pressure_fix_defined; + int thermal_fix_defined; + int surface_fix_defined; - // Non-persistent per-atom arrays are initialized here + // Non-persistent per-atom arrays int *surface; double *conductivity, *viscosity, *pressure; double **f_pressure; + class FixStorePeratom *fix_store_visc; + class FixStorePeratom *fix_store_pres; + class FixStorePeratom *fix_store_cond; + class FixStorePeratom *fix_store_surf; + class FixStorePeratom *fix_store_fp; + class ComputeRHEOGrad *compute_grad; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 9f7d3cf23c..846eb0f97f 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -39,6 +39,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : viscosity_style = NONE; comm_forward = 1; + nmax = atom->nmax; int ntypes = atom->ntypes; int iarg = 3; @@ -107,8 +108,10 @@ void FixRHEOViscosity::init() void FixRHEOViscosity::setup_pre_force(int /*vflag*/) { - // Identify whether this is the last instance of fix viscosity - // Will handle communication + // Identify whether this is the first/last instance of fix viscosity + // First will handle growing arrays + // Last will handle communication + first_flag = 0 last_flag = 0; int i = 0; @@ -118,6 +121,7 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) i++; } + if (i == 0) first_flag = 1; if ((i + 1) == fixlist.size()) last_flag = 1; pre_force(0); @@ -138,6 +142,11 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) int nlocal = atom->nlocal; int dim = domain->dimension; + if (first_flag & nmax < atom->nmax) { + nmax = atom->nmax; + fix_rheo->fix_store_visc->grow_arrays(nmax); + } + for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (viscosity_style == CONSTANT) { diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index 130d4d8cc8..b907617477 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -38,7 +38,8 @@ class FixRHEOViscosity : public Fix { double *eta_type, eta; double npow, K, gd0, tau0; int viscosity_style; - int last_flag; + int first_flag, last_flag; + int nmax; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; }; From c73f9188ce5d26c78e4119436a44ebb582bc6792 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 20 Feb 2023 20:42:44 -0700 Subject: [PATCH 005/385] Initial thermal/pair files --- src/RHEO/fix_rheo_thermal.cpp | 382 +++++++++++++++++++++++++ src/RHEO/fix_rheo_thermal.h | 73 +++++ src/RHEO/pair_rheo.cpp | 517 ++++++++++++++++++++++++++++++++++ src/RHEO/pair_rheo.h | 59 ++++ 4 files changed, 1031 insertions(+) create mode 100644 src/RHEO/fix_rheo_thermal.cpp create mode 100644 src/RHEO/fix_rheo_thermal.h create mode 100644 src/RHEO/pair_rheo.cpp create mode 100644 src/RHEO/pair_rheo.h diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp new file mode 100644 index 0000000000..ed56d5a618 --- /dev/null +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -0,0 +1,382 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 "fix_rheo_thermal.h" +#include "fix_rheo.h" +#include "atom.h" +#include "memory.h" +#include "modify.h" +#include "error.h" +#include "update.h" +#include "force.h" +#include "math_extra.h" + +using namespace LAMMPS_NS; +using namespace FixConst; +enum {NONE, CONSTANT, TYPE, ALUMINUM}; + +/* ---------------------------------------------------------------------- */ + +FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (narg < 4) error->all(FLERR,"Illegal fix command"); + + Tc_style = NONE; + cv_style = NONE; + alpha_style = NONE; + conductivity_style = NONE; + dynamic_group_allow = 1; + + Tc_type = nullptr; + kappa_type = nullptr; + cv_type = nullptr; + alpha_type = nullptr; + + int ntypes = atom->ntypes; + int iarg = 3; + while (iarg < narg) { + if (strcmp(arg[iarg],"conductivity") == 0) { + // Conductivity arguments + if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); + if (strcmp(arg[iarg+1],"constant") == 0) { + if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); + conductivity_style = CONSTANT; + kappa = utils::numeric(FLERR,arg[iarg+2],false,lmp); + if (kappa < 0.0) error->all(FLERR,"Illegal fix command"); + iarg += 2; + } else if (strcmp(arg[iarg+1],"type") == 0) { + if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); + conductivity_style = TYPE; + memory->create(kappa_type,ntypes+1,"rheo_thermal:kappa_type"); + for (int i = 1; i <= ntypes; i++) { + kappa_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); + if (kappa_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); + } + iarg += 1+ntypes; + } else { + error->all(FLERR,"Illegal fix command"); + } + } else if (strcmp(arg[iarg],"cv") == 0) { + // Cv arguments + if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); + if (strcmp(arg[iarg+1],"constant") == 0) { + if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); + cv_style = CONSTANT; + cv = utils::numeric(FLERR,arg[iarg+2],false,lmp); + if (cv < 0.0) error->all(FLERR,"Illegal fix command"); + iarg += 2; + } else if (strcmp(arg[iarg+1],"type") == 0) { + if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); + cv_style = TYPE; + memory->create(cv_type,ntypes+1,"rheo_thermal:cv_type"); + for (int i = 1; i <= ntypes; i++) { + cv_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); + if (cv_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); + } + iarg += 1+ntypes; + } else { + error->all(FLERR,"Illegal fix command"); + } + } else if (strcmp(arg[iarg],"alpha") == 0) { + // Cv arguments + if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); + if (strcmp(arg[iarg+1],"constant") == 0) { + if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); + alpha_style = CONSTANT; + alpha = utils::numeric(FLERR,arg[iarg+2],false,lmp); + iarg += 2; + } else if (strcmp(arg[iarg+1],"type") == 0) { + if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); + alpha_style = TYPE; + memory->create(alpha_type,ntypes+1,"rheo_thermal:alpha_type"); + for (int i = 1; i <= ntypes; i++) { + alpha_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); + if (alpha_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); + } + iarg += 1+ntypes; + } else { + error->all(FLERR,"Illegal fix command"); + } + } else if (strcmp(arg[iarg],"Tfreeze") == 0) { + // T freeze arguments + if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); + if (strcmp(arg[iarg+1],"constant") == 0) { + if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); + Tc_style = CONSTANT; + Tc = utils::numeric(FLERR,arg[iarg+2],false,lmp); + if (Tc < 0.0) error->all(FLERR,"Illegal fix command"); + iarg += 2; + } else if (strcmp(arg[iarg+1],"type") == 0) { + if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); + Tc_style = TYPE; + memory->create(Tc_type,ntypes+1,"rheo_thermal:Tc_type"); + for (int i = 1; i <= ntypes; i++) { + Tc_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); + if (Tc_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); + } + iarg += 1+ntypes; + } else { + error->all(FLERR,"Illegal fix command"); + } + } else { + error->all(FLERR,"Illegal fix command"); + } + iarg += 1; + } + + if (cv_style == NONE || conductivity_style == NONE) + error->all(FLERR, "Must specify specific heat and conductivity styles\n"); +} + +/* ---------------------------------------------------------------------- */ + +FixRHEOThermal::~FixRHEOThermal() +{ + // If fix rheo is still defined, remove any set flags + if (fix_rheo) { + //fix_rheo->thermal_fix_defined = 0; + //if(viscosity_style != NONE) fix_rheo->viscosity_fix_defined = 0; + } + + memory->destroy(cv_type); + memory->destroy(Tc_type); + memory->destroy(kappa_type); + memory->destroy(alpha_type); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOThermal::setmask() +{ + int mask = 0; + mask |= PRE_FORCE; + mask |= INITIAL_INTEGRATE; + mask |= POST_INTEGRATE; + mask |= END_OF_STEP; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::init() +{ + int flag; + int ifix = modify->find_fix_by_style("rheo"); + if (ifix == -1) error->all(FLERR, "Need to define fix rheo to use fix rheo/thermal"); + fix_rheo = ((FixRHEO *) modify->fix[ifix]); + + if (!fix_rheo->thermal_flag) error->all(FLERR, "Need to define thermal setting in fix rheo"); + + if (fix_rheo->thermal_fix_defined) + error->all(FLERR, "Cannot define two rheo thermal evolution fixes"); + fix_rheo->thermal_fix_defined = 1; + + int ifix2 = modify->find_fix_by_style("rheo/thermal"); + if (ifix > ifix2) + error->all(FLERR, "Fix RHEO must be defined before fix RHEO/thermal"); + + dtf = 0.5 * update->dt * force->ftm2v; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::initial_integrate(int /*vflag*/) +{ + // update temperature from shifting + int i; + int *status = atom->status; + double **gradt = compute_grad->gradt; + double **vshift = compute_vshift->array_atom; + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + if (igroup == atom->firstgroup) + nlocal = atom->nfirst; + + if (shift_flag) { + compute_vshift->correct_surfaces(); + for (i = 0; i < nlocal; i++) { + + if (!(status[i] & STATUS_SHIFT)) continue; + + if (mask[i] & groupbit) { + for (a = 0; a < dim; a++) { + temperature[i] += dtv * vshift[i][a] * gradt[i][a]; + } + } + } + } +} + + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::setup_pre_force(int /*vflag*/) +{ + pre_force(0); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::post_integrate() +{ + //Post integrate teo ensure gradient up to date + int *phase = atom->phase; + double *temp = atom->temp; + double *heat = atom->heat; + double *rho = atom->rho; + int *mask = atom->mask; + + double cvi, Tc, Tci, Ti, alphai; + + //Integrate temperature and check phase + for (int i = 0; i < atom->nlocal; i++) { + if (mask[i] & groupbit) { + if (phase[i] == FixRHEO::FLUID_NO_FORCE) continue; + + cvi = calc_cv(i); + temp[i] += dtf*heat[i]/cvi; + + if (alpha_style != NONE && phase[i] <= FixRHEO::FLUID_MAX) { + alphai = calc_alpha(i); + rho[i] += dtf*heat[i]/cvi*alphai; + } + + if (Tc_style != NONE) { + Ti = temp[i]; + Tci = calc_Tc(i); + + if (Ti > Tci) { + phase[i] = FixRHEO::FLUID; + } else { + if (phase[i] == FixRHEO::SOLID) { + continue; + } else { + phase[i] = FixRHEO::FREEZING; + } + } + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::pre_force(int /*vflag*/) +{ + double *conductivity = atom->conductivity; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + // Calculate non-persistent quantities before pairstyles + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + conductivity[i] = calc_kappa(i); + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::end_of_step() +{ + double *temp = atom->temp; + double *heat = atom->heat; + int *phase = atom->phase; + int *mask = atom->mask; + double *rho = atom->rho; + + double cvi, alphai; + + //Integrate temperature and check phase + for (int i = 0; i < atom->nlocal; i++) { + if (mask[i] & groupbit) { + if (phase[i] == FixRHEO::FLUID_NO_FORCE) continue; + + cvi = calc_cv(i); + temp[i] += dtf*heat[i]/cvi; + + if (alpha_style != NONE && phase[i] <= FixRHEO::FLUID_MAX) { + alphai = calc_alpha(i); + rho[i] += dtf*heat[i]/cvi*alphai; + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::reset_dt() +{ + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; +} + +/* ---------------------------------------------------------------------- */ + +double FixRHEOThermal::calc_kappa(int i) +{ + if (conductivity_style == CONSTANT) { + return kappa; + } else if (conductivity_style == TYPE) { + int itype = atom->type[i]; + return(kappa_type[itype]); + } else { + error->all(FLERR, "Invalid style"); + } +} + +/* ---------------------------------------------------------------------- */ + +double FixRHEOThermal::calc_cv(int i) +{ + if (cv_style == CONSTANT) { + return cv; + } else if (cv_style == TYPE) { + int itype = atom->type[i]; + return(cv_type[itype]); + } else { + error->all(FLERR, "Invalid style"); + } +} + + +/* ---------------------------------------------------------------------- */ + +double FixRHEOThermal::calc_alpha(int i) +{ + if (alpha_style == CONSTANT) { + return alpha; + } else if (alpha_style == TYPE) { + int itype = atom->type[i]; + return(alpha_type[itype]); + } else { + error->all(FLERR, "Invalid style"); + } +} + +/* ---------------------------------------------------------------------- */ + +double FixRHEOThermal::calc_Tc(int i) +{ + if (Tc_style == CONSTANT) { + return Tc; + } else if (Tc_style == TYPE) { + int itype = atom->type[i]; + return(Tc_type[itype]); + } else { + error->all(FLERR, "Invalid style"); + } +} \ No newline at end of file diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h new file mode 100644 index 0000000000..d1dcdc6e4d --- /dev/null +++ b/src/RHEO/fix_rheo_thermal.h @@ -0,0 +1,73 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(rheo/thermal,FixRHEOThermal) + +#else + +#ifndef LMP_FIX_RHEO_THERMAL_H +#define LMP_FIX_RHEO_THERMAL_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixRHEOThermal : public Fix { + public: + FixRHEOThermal(class LAMMPS *, int, char **); + ~FixRHEOThermal(); + int setmask(); + void init(); + void setup_pre_force(int); + void initial_integrate(); + void post_integrate(); + void pre_force(int); + void end_of_step(); + void reset_dt(); + + private: + double *cv_type, cv; + double *Tc_type, Tc; + double *kappa_type, kappa; + double *alpha_type, alpha; + double dtf, dtv; + + double calc_kappa(int); + double calc_cv(int); + double calc_Tc(int); + double calc_alpha(int); + + int Tc_style; + int cv_style; + int alpha_style; + int conductivity_style; + + class FixRHEO *fix_rheo; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +*/ diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp new file mode 100644 index 0000000000..b0443933e1 --- /dev/null +++ b/src/RHEO/pair_rheo.cpp @@ -0,0 +1,517 @@ +/* ---------------------------------------------------------------------- + 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 "pair_rheo.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_grad.h" +#include "compute_rheo_interface.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "memory.h" +#include "modify.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "update.h" +#include "utils.h" + +#include + +using namespace LAMMPS_NS; + +#define EPSILON 1e-2 + +/* ---------------------------------------------------------------------- */ + +PairRHEO::PairRHEO(LAMMPS *lmp) : + Pair(lmp), compute_kernel(nullptr), compute_grad(nullptr), + compute_interface(nullptr), fix_rheo(nullptr) +{ + restartinfo = 0; + single_enable = 0; + + artificial_visc_flag = 0; + rho_damp_flag = 0; + thermal_flag = 0; +} + +/* ---------------------------------------------------------------------- */ + +PairRHEO::~PairRHEO() +{ + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + } +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEO::compute(int eflag, int vflag) +{ + int i, j, a, b, ii, jj, inum, jnum, itype, jtype; + int error_flag, pair_force_flag, pair_rho_flag, pair_avisc_flag; + double xtmp, ytmp, ztmp; + + int *ilist, *jlist, *numneigh, **firstneigh; + double imass, jmass, rsq, r, ir; + + double w, wp, rhoi, rhoj, voli, volj, Pi, Pj; + double *dWij, *dWji, *d2Wij, *d2Wji, *dW1ij, *dW1ji; + double vijeij, etai, etaj, kappai, kappaj; + double Ti, Tj, dT; + double drho_damp, fmag; + double mu, q, cs, fp_prefactor; + double dx[3] = {0}; + double fv[3] = {0}; + double dfp[3] = {0}; + double fsolid[3] = {0}; + double du[3] = {0}; + double vi[3] = {0}; + double vj[3] = {0}; + double dv[3] = {0}; + double psi_ij = 0.0; + double Fij = 0.0; + + ev_init(eflag, vflag); + + double **gradv = compute_grad->gradv; + double **gradt = compute_grad->gradt; + double **gradr = compute_grad->gradr; + double **gradn = compute_grad->gradn; + double **v = atom->v; + double **x = atom->x; + double **f = atom->f; + double **fp = atom->fp; + double *rho = atom->rho; + double *mass = atom->mass; + double *drho = atom->drho; + double *temp = atom->temp; + double *heat = atom->heat; + double *viscosity = atom->viscosity; + double *conductivity = atom->conductivity; + double *special_lj = force->special_lj; + tagint *tag = atom->tag; + int *type = atom->type; + int *phase = atom->phase; + + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + int dim = domain->dimension; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + imass = mass[itype]; + + kappai = conductivity[i]; + etai = viscosity[i]; + Ti = temp[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + factor_lj = special_lj[sbmask(j)]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; + jtype = type[j]; + jmass = mass[jtype]; + + if (rsq < cutsq[itype][jtype]) { + r = sqrt(rsq); + ir = 1/r; + + kappaj = conductivity[j]; + etaj = viscosity[j]; + Tj = temp[j]; + + pair_rho_flag = 0; + pair_force_flag = 0; + pair_avisc_flag = 0; + if (phase[i] <= FixRHEO::FLUID_MAX || phase[j] <= FixRHEO::FLUID_MAX) { + pair_force_flag = 1; + } + if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { + pair_avisc_flag = 1; + pair_rho_flag = 1; + } + + wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2], r); + dWij = compute_kernel->dWij; + dWji = compute_kernel->dWji; + + for (a = 0; a < dim; a ++) { + vi[a] = v[i][a]; + vj[a] = v[j][a]; + fsolid[a] = 0.0; + } + + // Add corrections for walls + rhoi = rho[i]; + rhoj = rho[j]; + if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { + compute_sinterpolation->correct_v(v[i], v[j], vi, i, j); + rhoj = compute_sinterpolation->correct_rho(j,i); + + // Repel if close to inner solid particle + if (compute_sinterpolation->chi[j] > 0.9 && r < (cut[itype][jtype] * 0.5)) { + fmag = (compute_sinterpolation->chi[j] - 0.9) * (cut[itype][jtype] * 0.5 - r); + fmag *= rho0[itype] * csq[itype] * cut[itype][jtype] * ir; + fsolid[0] = fmag * dx[0]; + fsolid[1] = fmag * dx[1]; + fsolid[2] = fmag * dx[2]; + } + } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { + compute_sinterpolation->correct_v(v[j], v[i], vj, j, i); + rhoi = compute_sinterpolation->correct_rho(i,j); + + // Repel if close to inner solid particle + if (compute_sinterpolation->chi[i] > 0.9 && r < (cut[itype][jtype] * 0.5)) { + fmag = (compute_sinterpolation->chi[i] - 0.9) * (cut[itype][jtype] * 0.5 - r); + fmag *= rho0[jtype] * csq[jtype] * cut[itype][jtype] * ir; + fsolid[0] = fmag * dx[0]; + fsolid[1] = fmag * dx[1]; + fsolid[2] = fmag * dx[2]; + } + } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { + rhoi = 1.0; + rhoj = 1.0; + } + + // Compute volume and pressure after reconstructing + voli = imass / rhoi; + volj = jmass / rhoj; + Pj = calc_pressure(rhoj, jtype); + Pi = calc_pressure(rhoi, itype); + + //Check if Second order kernels will be used for eta*Lap(v) + error_flag = 0; + if (laplacian_order == 2) { + error_flag = compute_kernel->calc_d2w(i, j, dx[0], dx[1], dx[2], r); + d2Wij = compute_kernel->d2Wij; + d2Wji = compute_kernel->d2Wji; + } + + //Thermal Evolution + if (thermal_flag) { + dT = 0.0; + for (a = 0; a < dim; a++) { + dT += (kappai + kappaj) * (Ti-Tj) * dx[a] * dWij[a] * ir * ir; + //Assumes heat capacity and density = 1, needs to be generalized + } + dT *= voli * volj; + heat[i] += dT; + } + + // If either particle is fluid, compute hydrostatic and viscous forces + // Compute eta*Lap(v) - different forms depending on order of RK correction + if (pair_force_flag) { + //Hydrostatic pressure forces + fp_prefactor = voli * volj * (Pj + Pi); + + //Add artificial viscous pressure if required + if (artificial_visc_flag && pair_avisc_flag){ + //Interpolate velocities to midpoint and use this difference for artificial viscosity + for (a = 0; a < dim; a++) { + du[a] = vi[a] - vj[a]; + for (b = 0; b < dim; b++) { + du[a] -= 0.5 * (gradv[i][a * dim + b] + gradv[j][a * dim + b]) * dx[b]; + } + } + mu = (du[0] * dx[0] + du[1] * dx[1]+ du[2] * dx[2]) * hinv3; + mu = mu / (rsq * hinv3 * hinv3 + EPSILON); + mu= MIN(0.0, mu); + cs = 0.5 * (sqrt(csq[itype]) + sqrt(csq[jtype])); + // "kinematic viscous pressure" q = Q/rho + q = av*(-2.0*cs*mu + 1.0*mu*mu); + fp_prefactor += voli*volj*q*(rhoj + rhoi); + } + + // -Grad[P + Q] + dfp[0] = - fp_prefactor*dWij[0]; + dfp[1] = - fp_prefactor*dWij[1]; + dfp[2] = - fp_prefactor*dWij[2]; + + // Now compute viscous eta*Lap[v] terms + for (a = 0; a < dim; a ++) { + fv[a] = 0.0; + for (b = 0; b < dim; b++) { + fv[a] += (etai+etaj)*(vi[a]-vj[a])*dx[b]*dWij[b]*ir*ir; + } + fv[a] *= voli*volj; + } + + } else { + for (a = 0; a < dim; a ++) { + fv[a] = 0; + dfp[a] = 0; + } + } + + if (pair_force_flag) { + f[i][0] += fv[0] + dfp[0] + fsolid[0]; + f[i][1] += fv[1] + dfp[1] + fsolid[1]; + f[i][2] += fv[2] + dfp[2] + fsolid[2]; + fp[i][0] += dfp[0]; + fp[i][1] += dfp[1]; + fp[i][2] += dfp[2]; + } + + // Density damping + // conventional for low-order h + // interpolated for RK 1 & 2 (Antuono et al, Computers & Fluids 2021) + if (rho_damp_flag && pair_rho_flag) { + if (laplacian_order>=1 && error_flag == 0){ + psi_ij = rhoj-rhoi; + Fij = 0.0; + for (a = 0; a < dim; a++){ + psi_ij += 0.5*(gradr[i][a]+gradr[j][a])*dx[a]; + Fij -= dx[a]*dWij[a]; + } + Fij *= ir*ir; + drho[i] += 2*rho_damp*psi_ij*Fij*volj; + } + else { + drho_damp = 2*rho_damp*(rhoj-rhoi)*ir*wp; + drho[i] -= drho_damp*volj; + } + } + + if (evflag) // Doesn't account for unbalanced forces + ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, fv[0]+dfp[0], fv[1]+dfp[1], fv[2]+dfp[2], dx[0], dx[1], dx[2]); + + // Newton neighbors + if (newton_pair || j < nlocal) { + + if (thermal_flag) { + dT = 0.0; + for(a = 0; a < dim; a++){ + //dT += kappai*dWji[a]*gradt[i][a]; + //dT -= kappaj*dWji[a]*gradt[j][a]; + dT += 1/1*(kappai+kappaj)*(Ti-Tj)*dx[a]*dWji[a]*ir*ir; //Assumes heat capacity and density = 1, needs to be generalized + } + dT *= -voli*volj; + heat[j] -= dT; + } + + for (a = 0; a < dim; a ++) { + fv[a] = 0.0; + for (b = 0; b < dim; b++) { + //fv[a] += etai*dWji[b]*(gradv[i][a*dim+b]+gradv[i][b*dim+a]); + //fv[a] -= etaj*dWji[b]*(gradv[j][a*dim+b]+gradv[j][b*dim+a]); + fv[a] += (etai+etaj)*(vi[a]-vj[a])*dx[b]*dWji[b]*ir*ir; + } + fv[a] *= -voli*volj; // flip sign here b/c -= at accummulator + } + + + + if (pair_force_flag) { + for (a = 0; a < dim; a++) + dfp[a] = fp_prefactor*dWji[a]; + } + + if (rho_damp_flag && pair_rho_flag){ + if (laplacian_order>=1 && error_flag == 0){ + Fij = 0.0; + for (a = 0; a < dim; a++){ + Fij += dx[a]*dWji[a]; + } + Fij *= ir*ir; + psi_ij *= -1; + drho[j] += 2*rho_damp*psi_ij*Fij*voli; + } + else { + drho_damp = 2*rho_damp*(rhoj-rhoi)*ir*wp; + drho[j] += drho_damp*voli; + } + } + if (pair_force_flag) { + f[j][0] -= fv[0] + dfp[0] + fsolid[0]; + f[j][1] -= fv[1] + dfp[1] + fsolid[1]; + f[j][2] -= fv[2] + dfp[2] + fsolid[2]; + + fp[j][0] -= dfp[0]; + fp[j][1] -= dfp[1]; + fp[j][2] -= dfp[2]; + } + } + } + } + } + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays + ------------------------------------------------------------------------- */ + +void PairRHEO::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag, n + 1, n + 1, "pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairRHEO::settings(int narg, char **arg) +{ + if(narg < 1) error->all(FLERR,"Illegal pair_style command"); + + int iarg = 0; + while (iarg < narg) { + if (strcmp(arg[iarg], "rho/damp") == 0) { + if (iarg+1 >= narg) error->all(FLERR,"Illegal pair_style command"); + + rho_damp_flag = 1; + rho_damp = utils::numeric(FLERR,arg[iarg+1],false,lmp); + iarg ++; + } else if (strcmp(arg[iarg], "artificial/visc") == 0) { + if (iarg+1 >= narg) error->all(FLERR,"Illegal pair_style command"); + + artificial_visc_flag = 1; + av = utils::numeric(FLERR,arg[iarg+1],false,lmp); + iarg ++; + } else error->all(FLERR,"Illegal pair_style command"); + iarg++; + } +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs + ------------------------------------------------------------------------- */ + +void PairRHEO::coeff(int narg, char **arg) +{ + if (narg != 4) + error->all(FLERR,"Incorrect number of args for pair_style llns coefficients"); + if (!allocated) + allocate(); + + int ilo, ihi, jlo, jhi; + utils::bounds(FLERR,arg[0],1, atom->ntypes, ilo, ihi,error); + utils::bounds(FLERR,arg[1],1, atom->ntypes, jlo, jhi,error); + + double rho0_one = utils::numeric(FLERR,arg[2],false,lmp); + double c_one = utils::numeric(FLERR,arg[3],false,lmp); + + if (c_one != 1.0) error->warning(FLERR, "Need c = 1 for assumption in compute rheo/solids"); + if (rho0_one != 1.0) error->warning(FLERR, "Need rho0 = 1 for assumption in compute rheo/solids"); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + rho0[i] = rho0_one; + csq[i] = c_one*c_one; + + for (int j = 0; j <= atom->ntypes; j++) { + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) + error->all(FLERR,"Incorrect args for pair llns coefficients"); +} + +/* ---------------------------------------------------------------------- + setup specific to this pair style + ------------------------------------------------------------------------- */ + +void PairRHEO::setup() +{ + int flag; + int ifix = modify->find_fix_by_style("rheo"); + if (ifix == -1) error->all(FLERR, "Using pair RHEO without fix RHEO"); + fix_rheo = ((FixRHEO *) modify->fix[ifix]); + + compute_kernel = fix_rheo->compute_kernel; + compute_grad = fix_rheo->compute_grad; + compute_sinterpolation = fix_rheo->compute_sinterpolation; + thermal_flag = fix_rheo->thermal_flag; + + + + + h = utils::numeric(FLERR,arg[0],false,lmp); + if (h <= 0.0) error->all(FLERR,"Illegal pair_style command"); + hinv = 1.0 / h; + hinv3 = 3.0 * hinv; + laplacian_order = -1; + + + if (comm->ghost_velocity == 0) + error->all(FLERR,"Pair RHEO requires ghost atoms store velocity"); + + if (laplacian_order == -1) { + if (fix_rheo->kernel_type == FixRHEO::CRK2) + laplacian_order = 2; + else if (fix_rheo->kernel_type == FixRHEO::CRK1) + laplacian_order = 1; + else + laplacian_order = 0; + } +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i + ------------------------------------------------------------------------- */ + +double PairRHEO::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + error->all(FLERR,"All pair rheo coeffs are not set"); + } + + cut[i][j] = h; + cut[j][i] = cut[i][j]; + + return cut[i][j]; +} + +/* ---------------------------------------------------------------------- */ + +double PairRHEO::single(int /*i*/, int /*j*/, int /*itype*/, int /*jtype*/, + double /*rsq*/, double /*factor_coul*/, double /*factor_lj*/, double &fforce) +{ + fforce = 0.0; + + return 0.0; +} diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h new file mode 100644 index 0000000000..ebe97cd542 --- /dev/null +++ b/src/RHEO/pair_rheo.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(rheo,PairRHEO) + +#else + +#ifndef LMP_PAIR_RHEO_H +#define LMP_PAIR_RHEO_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairRHEO : public Pair { + public: + PairRHEO(class LAMMPS *); + virtual ~PairRHEO(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + void setup(); + virtual double init_one(int, int); + virtual double single(int, int, int, int, double, double, double, double &); + + protected: + int laplacian_order; // From fix RHEO + double h, csq*, rho0*; // From fix RHEO + + double hsq, hinv, rho0, av, rho_damp; + + int artificial_visc_flag; + int rho_damp_flag; + int thermal_flag; + + void allocate(); + + class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOGrad *compute_grad; + class ComputeRHEOSolidInterpolation *compute_sinterpolation; + class FixRHEO *fix_rheo; +}; + +} + +#endif +#endif From 1adc66e82ba7c3252d28ab86771c1e3c2369caa3 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 20 Feb 2023 22:07:30 -0700 Subject: [PATCH 006/385] Beginning updates to thermal fix --- src/RHEO/compute_rheo_grad.h | 2 +- src/RHEO/fix_rheo.cpp | 1 + src/RHEO/fix_rheo.h | 22 +-- src/RHEO/fix_rheo_thermal.cpp | 330 +++++++++++++------------------- src/RHEO/fix_rheo_thermal.h | 53 ++--- src/RHEO/fix_rheo_viscosity.cpp | 60 ++++-- src/RHEO/fix_rheo_viscosity.h | 5 +- src/RHEO/pair_rheo.h | 14 +- 8 files changed, 222 insertions(+), 265 deletions(-) diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 35b50ca834..52c5d7c924 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -27,7 +27,7 @@ namespace LAMMPS_NS { class ComputeRHEOGrad : public Compute { public: ComputeRHEOGrad(class LAMMPS *, int, char **); - ~ComputeRHEOGrad(); + ~ComputeRHEOGrad() override; void init() override; void init_list(int, class NeighList *) override; void compute_peratom() override; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index f5a5f8b151..0c3f784c0e 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -197,6 +197,7 @@ void FixRHEO::init() void FixRHEO::setup_pre_force(int /*vflag*/) { + //Need to rethink and replan // Check to confirm all accessory fixes are defined if (!viscosity_fix_defined) error->all(FLERR, "Missing fix rheo/viscosity"); diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 1e35701278..432d319728 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -27,15 +27,15 @@ namespace LAMMPS_NS { class FixRHEO : public Fix { public: FixRHEO(class LAMMPS *, int, char **); - virtual ~FixRHEO(); - int setmask(); - virtual void post_constructor(); - virtual void init(); - virtual void setup_pre_force(int); - virtual void pre_force(int); - virtual void initial_integrate(int); - virtual void final_integrate(); - void reset_dt(); + ~FixRHEO() override; + int setmask() override; + void post_constructor() override; + void init() override; + void setup_pre_force(int) override; + void pre_force(int) override; + void initial_integrate(int) override; + void final_integrate() override; + void reset_dt() override; int kernel_style; int thermal_flag; @@ -71,7 +71,7 @@ class FixRHEO : public Fix { enum { // Phase status - STATUS_FLUID = 1 << 0, + STATUS_FLUID = 1 << 0, //Need to turn off other options STATUS_REACTIVE = 1 << 1, STATUS_SOLID = 1 << 2, STATUS_FREEZING = 1 << 3 @@ -81,7 +81,7 @@ class FixRHEO : public Fix { STATUS_NO_FORCE = 1 << 5, // Surface status - STATUS_BULK = 1 << 6, + STATUS_BULK = 1 << 6, //Need to turn off other options STATUS_LAYER = 1 << 7, STATUS_SURFACE = 1 << 8, STATUS_SPLASH = 1 << 9, diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index ed56d5a618..0fc4fe294b 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -1,136 +1,116 @@ /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov - 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. + 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. -------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ #include "fix_rheo_thermal.h" -#include "fix_rheo.h" + #include "atom.h" -#include "memory.h" -#include "modify.h" +#include "comm.h" +#include "compute_rheo_grad.h" +#include "compute_rheo_vshift.h" #include "error.h" -#include "update.h" +#include "fix_rheo.h" #include "force.h" #include "math_extra.h" +#include "memory.h" +#include "modify.h" +#include "update.h" using namespace LAMMPS_NS; using namespace FixConst; -enum {NONE, CONSTANT, TYPE, ALUMINUM}; +enum {NONE, CONSTANT, TYPE}; /* ---------------------------------------------------------------------- */ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg) + Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); Tc_style = NONE; cv_style = NONE; - alpha_style = NONE; conductivity_style = NONE; - dynamic_group_allow = 1; - Tc_type = nullptr; - kappa_type = nullptr; - cv_type = nullptr; - alpha_type = nullptr; + comm_forward = 0; + nmax = atom->nmax; int ntypes = atom->ntypes; int iarg = 3; while (iarg < narg) { if (strcmp(arg[iarg],"conductivity") == 0) { // Conductivity arguments - if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); - if (strcmp(arg[iarg+1],"constant") == 0) { - if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); + if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for conductivity option"); + if (strcmp(arg[iarg + 1],"constant") == 0) { + if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for conductivity option"); conductivity_style = CONSTANT; - kappa = utils::numeric(FLERR,arg[iarg+2],false,lmp); - if (kappa < 0.0) error->all(FLERR,"Illegal fix command"); + kappa = utils::numeric(FLERR,arg[iarg + 2],false,lmp); + if (kappa < 0.0) error->all(FLERR,"The conductivity must be positive"); iarg += 2; - } else if (strcmp(arg[iarg+1],"type") == 0) { - if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); + } else if (strcmp(arg[iarg + 1],"type") == 0) { + if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for conductivity option"); conductivity_style = TYPE; memory->create(kappa_type,ntypes+1,"rheo_thermal:kappa_type"); for (int i = 1; i <= ntypes; i++) { - kappa_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); - if (kappa_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); + kappa_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i],false,lmp); + if (kappa_type[i] < 0.0) error->all(FLERR,"The conductivity must be positive"); } - iarg += 1+ntypes; + iarg += 1 + ntypes; } else { - error->all(FLERR,"Illegal fix command"); + error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } } else if (strcmp(arg[iarg],"cv") == 0) { // Cv arguments - if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); - if (strcmp(arg[iarg+1],"constant") == 0) { - if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); + if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for cv option"); + if (strcmp(arg[iarg + 1],"constant") == 0) { + if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for cv option"); cv_style = CONSTANT; - cv = utils::numeric(FLERR,arg[iarg+2],false,lmp); - if (cv < 0.0) error->all(FLERR,"Illegal fix command"); + cv = utils::numeric(FLERR,arg[iarg + 2],false,lmp); + if (cv < 0.0) error->all(FLERR,"The specific heat must be positive"); iarg += 2; - } else if (strcmp(arg[iarg+1],"type") == 0) { - if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); + } else if (strcmp(arg[iarg + 1],"type") == 0) { + if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for cv option"); cv_style = TYPE; - memory->create(cv_type,ntypes+1,"rheo_thermal:cv_type"); + memory->create(cv_type,ntypes + 1,"rheo_thermal:cv_type"); for (int i = 1; i <= ntypes; i++) { - cv_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); - if (cv_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); + cv_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i],false,lmp); + if (cv_type[i] < 0.0) error->all(FLERR,"The specific heat must be positive"); } - iarg += 1+ntypes; + iarg += 1 + ntypes; } else { - error->all(FLERR,"Illegal fix command"); - } - } else if (strcmp(arg[iarg],"alpha") == 0) { - // Cv arguments - if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); - if (strcmp(arg[iarg+1],"constant") == 0) { - if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); - alpha_style = CONSTANT; - alpha = utils::numeric(FLERR,arg[iarg+2],false,lmp); - iarg += 2; - } else if (strcmp(arg[iarg+1],"type") == 0) { - if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); - alpha_style = TYPE; - memory->create(alpha_type,ntypes+1,"rheo_thermal:alpha_type"); - for (int i = 1; i <= ntypes; i++) { - alpha_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); - if (alpha_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); - } - iarg += 1+ntypes; - } else { - error->all(FLERR,"Illegal fix command"); + error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } } else if (strcmp(arg[iarg],"Tfreeze") == 0) { // T freeze arguments - if (iarg+1 >= narg) error->all(FLERR,"Illegal fix command"); - if (strcmp(arg[iarg+1],"constant") == 0) { - if (iarg+2 >= narg) error->all(FLERR,"Illegal fix command"); + if (iarg+1 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); + if (strcmp(arg[iarg + 1],"constant") == 0) { + if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); Tc_style = CONSTANT; - Tc = utils::numeric(FLERR,arg[iarg+2],false,lmp); - if (Tc < 0.0) error->all(FLERR,"Illegal fix command"); + Tc = utils::numeric(FLERR,arg[iarg + 2],false,lmp); + if (Tc < 0.0) error->all(FLERR,"The melting temperature must be positive"); iarg += 2; - } else if (strcmp(arg[iarg+1],"type") == 0) { - if (iarg+1+ntypes >= narg) error->all(FLERR,"Illegal fix command"); + } else if (strcmp(arg[iarg + 1],"type") == 0) { + if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); Tc_style = TYPE; - memory->create(Tc_type,ntypes+1,"rheo_thermal:Tc_type"); + memory->create(Tc_type,ntypes + 1,"rheo_thermal:Tc_type"); for (int i = 1; i <= ntypes; i++) { - Tc_type[i] = utils::numeric(FLERR,arg[iarg+1+i],false,lmp); - if (Tc_type[i] < 0.0) error->all(FLERR,"Illegal fix command"); + Tc_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i],false,lmp); + if (Tc_type[i] < 0.0) error->all(FLERR,"The melting temperature must be positive"); } - iarg += 1+ntypes; + iarg += 1 + ntypes; } else { - error->all(FLERR,"Illegal fix command"); + error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } } else { - error->all(FLERR,"Illegal fix command"); + error->all(FLERR,"Illegal fix command, {}", arg[iarg]); } iarg += 1; } @@ -143,16 +123,9 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : FixRHEOThermal::~FixRHEOThermal() { - // If fix rheo is still defined, remove any set flags - if (fix_rheo) { - //fix_rheo->thermal_fix_defined = 0; - //if(viscosity_style != NONE) fix_rheo->viscosity_fix_defined = 0; - } - memory->destroy(cv_type); memory->destroy(Tc_type); memory->destroy(kappa_type); - memory->destroy(alpha_type); } /* ---------------------------------------------------------------------- */ @@ -160,10 +133,11 @@ FixRHEOThermal::~FixRHEOThermal() int FixRHEOThermal::setmask() { int mask = 0; - mask |= PRE_FORCE; mask |= INITIAL_INTEGRATE; mask |= POST_INTEGRATE; - mask |= END_OF_STEP; + mask |= POST_NEIGHBOR; + mask |= PRE_FORCE; + mask |= FINAL_INTEGRATE; return mask; } @@ -171,29 +145,49 @@ int FixRHEOThermal::setmask() void FixRHEOThermal::init() { - int flag; - int ifix = modify->find_fix_by_style("rheo"); - if (ifix == -1) error->all(FLERR, "Need to define fix rheo to use fix rheo/thermal"); - fix_rheo = ((FixRHEO *) modify->fix[ifix]); + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); + fix_rheo = dynamic_cast(fixes[0]); - if (!fix_rheo->thermal_flag) error->all(FLERR, "Need to define thermal setting in fix rheo"); - - if (fix_rheo->thermal_fix_defined) - error->all(FLERR, "Cannot define two rheo thermal evolution fixes"); fix_rheo->thermal_fix_defined = 1; - - int ifix2 = modify->find_fix_by_style("rheo/thermal"); - if (ifix > ifix2) - error->all(FLERR, "Fix RHEO must be defined before fix RHEO/thermal"); + if (!fix_rheo->thermal_flag) + error->all(FLERR, "Need to define thermal setting in fix rheo"); + compute_grad = fix_rheo->compute_grad; + compute_vshift = fix_rheo->compute_vshift; dtf = 0.5 * update->dt * force->ftm2v; } /* ---------------------------------------------------------------------- */ +void FixRHEOThermal::setup_pre_force(int /*vflag*/) +{ + // Identify whether this is the first/last instance of fix thermal + // First will handle growing arrays + // Last will handle communication + first_flag = 0 + last_flag = 0; + + int i = 0; + auto fixlist = modify->get_fix_by_style("rheo/thermal"); + for (const auto &ifix : fixlist) { + if (strcmp(ifix->id, id) == 0) break; + i++; + } + + if (i == 0) first_flag = 1; + if ((i + 1) == fixlist.size()) last_flag = 1; + + post_neighbor(); + pre_force(0); +} + +/* ---------------------------------------------------------------------- */ + void FixRHEOThermal::initial_integrate(int /*vflag*/) { // update temperature from shifting + if (!fix_rheo->shift_flag) return; int i; int *status = atom->status; double **gradt = compute_grad->gradt; @@ -205,73 +199,58 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) if (igroup == atom->firstgroup) nlocal = atom->nfirst; - if (shift_flag) { - compute_vshift->correct_surfaces(); - for (i = 0; i < nlocal; i++) { + for (i = 0; i < nlocal; i++) { + if (!(status[i] & STATUS_SHIFT)) continue; - if (!(status[i] & STATUS_SHIFT)) continue; - - if (mask[i] & groupbit) { - for (a = 0; a < dim; a++) { - temperature[i] += dtv * vshift[i][a] * gradt[i][a]; - } + if (mask[i] & groupbit) { + for (a = 0; a < dim; a++) { + temperature[i] += dtv * vshift[i][a] * gradt[i][a]; } } } } - -/* ---------------------------------------------------------------------- */ - -void FixRHEOThermal::setup_pre_force(int /*vflag*/) -{ - pre_force(0); -} - /* ---------------------------------------------------------------------- */ void FixRHEOThermal::post_integrate() { - //Post integrate teo ensure gradient up to date - int *phase = atom->phase; - double *temp = atom->temp; + int *status = atom->status; + double *temperature = atom->temperature; double *heat = atom->heat; double *rho = atom->rho; int *mask = atom->mask; + int *type = aotm->type; - double cvi, Tc, Tci, Ti, alphai; + double cvi, Tci, Ti; - //Integrate temperature and check phase + //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { - if (phase[i] == FixRHEO::FLUID_NO_FORCE) continue; + if (status[i] == FixRHEO::FLUID_NO_FORCE) continue; cvi = calc_cv(i); - temp[i] += dtf*heat[i]/cvi; - - if (alpha_style != NONE && phase[i] <= FixRHEO::FLUID_MAX) { - alphai = calc_alpha(i); - rho[i] += dtf*heat[i]/cvi*alphai; - } + temperature[i] += dtf*heat[i]/cvi; if (Tc_style != NONE) { - Ti = temp[i]; - Tci = calc_Tc(i); + Ti = temperature[i]; + if (Tc_style == CONSTANT) { + Tci = Tc; + } else if (Tc_style == TYPE) { + Tci = Tc_type[type[i]]); + } - if (Ti > Tci) { - phase[i] = FixRHEO::FLUID; - } else { - if (phase[i] == FixRHEO::SOLID) { - continue; - } else { - phase[i] = FixRHEO::FREEZING; - } + if (Ti > Tci) { //Need to untoggle other phase options + status[i] |= FixRHEO::STATUS_FLUID; + } else if (!(status[i] & FixRHEO::STATUS_SOLID)) + status[i] |= FixRHEO::STATUS_FREEZING; } } } } } + +add post neighbor then update preforce below /* ---------------------------------------------------------------------- */ void FixRHEOThermal::pre_force(int /*vflag*/) @@ -286,32 +265,35 @@ void FixRHEOThermal::pre_force(int /*vflag*/) conductivity[i] = calc_kappa(i); } } + + if (conductivity_style == CONSTANT) { + return kappa; + } else if (conductivity_style == TYPE) { + int itype = atom->type[i]; + return(kappa_type[itype]); + } else { + error->all(FLERR, "Invalid style"); + } } /* ---------------------------------------------------------------------- */ -void FixRHEOThermal::end_of_step() +void FixRHEOThermal::final_integrate() { - double *temp = atom->temp; + double *temperature = atom->temperature; double *heat = atom->heat; - int *phase = atom->phase; + int *status = atom->status; int *mask = atom->mask; - double *rho = atom->rho; - double cvi, alphai; + double cvi; - //Integrate temperature and check phase + //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { - if (phase[i] == FixRHEO::FLUID_NO_FORCE) continue; + if (status[i] & FixRHEO::STATUS_NO_FORCE) continue; cvi = calc_cv(i); - temp[i] += dtf*heat[i]/cvi; - - if (alpha_style != NONE && phase[i] <= FixRHEO::FLUID_MAX) { - alphai = calc_alpha(i); - rho[i] += dtf*heat[i]/cvi*alphai; - } + temperature[i] += dtf * heat[i] / cvi; } } } @@ -326,57 +308,11 @@ void FixRHEOThermal::reset_dt() /* ---------------------------------------------------------------------- */ -double FixRHEOThermal::calc_kappa(int i) -{ - if (conductivity_style == CONSTANT) { - return kappa; - } else if (conductivity_style == TYPE) { - int itype = atom->type[i]; - return(kappa_type[itype]); - } else { - error->all(FLERR, "Invalid style"); - } -} - -/* ---------------------------------------------------------------------- */ - double FixRHEOThermal::calc_cv(int i) { if (cv_style == CONSTANT) { return cv; } else if (cv_style == TYPE) { - int itype = atom->type[i]; - return(cv_type[itype]); - } else { - error->all(FLERR, "Invalid style"); + return(cv_type[atom->type[i]]); } } - - -/* ---------------------------------------------------------------------- */ - -double FixRHEOThermal::calc_alpha(int i) -{ - if (alpha_style == CONSTANT) { - return alpha; - } else if (alpha_style == TYPE) { - int itype = atom->type[i]; - return(alpha_type[itype]); - } else { - error->all(FLERR, "Invalid style"); - } -} - -/* ---------------------------------------------------------------------- */ - -double FixRHEOThermal::calc_Tc(int i) -{ - if (Tc_style == CONSTANT) { - return Tc; - } else if (Tc_style == TYPE) { - int itype = atom->type[i]; - return(Tc_type[itype]); - } else { - error->all(FLERR, "Invalid style"); - } -} \ No newline at end of file diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index d1dcdc6e4d..c0b5255caa 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -1,7 +1,7 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 @@ -12,9 +12,9 @@ ------------------------------------------------------------------------- */ #ifdef FIX_CLASS - +// clang-format off FixStyle(rheo/thermal,FixRHEOThermal) - +// clang-format on #else #ifndef LMP_FIX_RHEO_THERMAL_H @@ -27,47 +27,36 @@ namespace LAMMPS_NS { class FixRHEOThermal : public Fix { public: FixRHEOThermal(class LAMMPS *, int, char **); - ~FixRHEOThermal(); - int setmask(); - void init(); - void setup_pre_force(int); - void initial_integrate(); - void post_integrate(); - void pre_force(int); - void end_of_step(); - void reset_dt(); + ~FixRHEOThermal() override; + int setmask() override; + void init() override; + void setup_pre_force(int) override; + void initial_integrate() override; + void post_integrate() override; + void post_neighbor() override; + void pre_force(int) override; + void final_integrate() override; + void reset_dt() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; private: double *cv_type, cv; double *Tc_type, Tc; double *kappa_type, kappa; - double *alpha_type, alpha; double dtf, dtv; - - double calc_kappa(int); - double calc_cv(int); - double calc_Tc(int); - double calc_alpha(int); - int Tc_style; int cv_style; - int alpha_style; int conductivity_style; + int first_flag, last_flag; + int nmax; class FixRHEO *fix_rheo; + + double calc_cv(int); }; -} +} // namespace LAMMPS_NS #endif #endif - -/* ERROR/WARNING messages: - -E: Illegal ... command - -Self-explanatory. Check the input script syntax and compare to the -documentation for the command. You can use -echo screen as a -command-line option when running LAMMPS to see the offending line. - -*/ diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 846eb0f97f..72168b2ee9 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -38,35 +38,36 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : viscosity_style = NONE; - comm_forward = 1; + comm_forward = 0; nmax = atom->nmax; int ntypes = atom->ntypes; int iarg = 3; if (strcmp(arg[iarg],"constant") == 0) { - if (iarg+1 >= narg) error->all(FLERR,"Insufficient arguments for fix rheo/viscosity"); + if (iarg+1 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); viscosity_style = CONSTANT; eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); - if (eta < 0.0) error->all(FLERR,"The viscosity must be positive in fix rheo/viscosity"); + if (eta < 0.0) error->all(FLERR,"The viscosity must be positive"); iarg += 1; } else if (strcmp(arg[iarg],"type") == 0) { - if(iarg+ntypes >= narg) error->all(FLERR,"Insufficient arguments for fix rheo/viscosity"); + if(iarg+ntypes >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); viscosity_style = TYPE; memory->create(eta_type, ntypes + 1, "rheo_thermal:eta_type"); for (int i = 1; i <= ntypes; i++) { eta_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i], false, lmp); - if (eta_type[i] < 0.0) error->all(FLERR,"The viscosity must be positive in fix rheo/viscosity"); + if (eta_type[i] < 0.0) error->all(FLERR,"The viscosity must be positive"); } iarg += ntypes; } else if (strcmp(arg[iarg],"power") == 0) { - if (iarg+4 >= narg) error->all(FLERR,"Insufficient arguments for fix rheo/viscosity"); + if (iarg+4 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); viscosity_style = POWER; + comm_forward = 1; eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); gd0 = utils::numeric(FLERR,arg[iarg + 2],false,lmp); K = utils::numeric(FLERR,arg[iarg + 3],false,lmp); npow = utils::numeric(FLERR,arg[iarg + 4],false,lmp); tau0 = eta * gd0 - K * pow(gd0, npow); - if (eta < 0.0) error->all(FLERR,"The viscosity must be positive in fix rheo/viscosity"); + if (eta < 0.0) error->all(FLERR,"The viscosity must be positive"); iarg += 5; } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg]); @@ -88,6 +89,7 @@ FixRHEOViscosity::~FixRHEOViscosity() int FixRHEOViscosity::setmask() { int mask = 0; + mask |= POST_NEIGHBOR; mask |= PRE_FORCE; return mask; } @@ -124,9 +126,40 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) if (i == 0) first_flag = 1; if ((i + 1) == fixlist.size()) last_flag = 1; + post_neighbor(); pre_force(0); } + +/* ---------------------------------------------------------------------- */ + +void FixRHEOViscosity::post_neighbor() +{ + int i; + + int *type = atom->type; + double *viscosity = fix_rheo->viscosity; + int *mask = atom->mask; + + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + if (first_flag & nmax < atom->nmax) { + nmax = atom->nmax; + fix_rheo->fix_store_visc->grow_arrays(nmax); + } + + // Update non-evolving viscosity styles only after atoms can exchange + if (viscosity_style == CONSTANT) { + for (i = 0; i < nall; i++) + if (mask[i] & groupbit) viscosity[i] = eta; + } else if (viscosity_style == TYPE) { + for (i = 0; i < nall; i++) + if (mask[i] & groupbit) viscosity[i] = eta_type[type[i]]; + } + } +} + /* ---------------------------------------------------------------------- */ void FixRHEOViscosity::pre_force(int /*vflag*/) @@ -147,13 +180,10 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) fix_rheo->fix_store_visc->grow_arrays(nmax); } - for (i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) { - if (viscosity_style == CONSTANT) { - viscosity[i] = eta; - } else if (viscosity_style == TYPE) { - viscosity[i] = eta_type[type[i]]; - } else if (viscosity_style == POWER) { + // Update viscosity styles that evolve in time every timestep + if (viscosity_style == POWER) { + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { gdot = 0.0; for (a = 0; a < dim; a++) { for (b = a; b < dim; b++) { @@ -173,7 +203,7 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) } } - if (last_flag) comm->forward_comm(this); + if (last_flag && comm_forward) comm->forward_comm(this); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index b907617477..31c1441e40 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -27,10 +27,11 @@ namespace LAMMPS_NS { class FixRHEOViscosity : public Fix { public: FixRHEOViscosity(class LAMMPS *, int, char **); - ~FixRHEOViscosity(); + ~FixRHEOViscosity() override; int setmask() override; void init() override; - virtual void setup_pre_force(int) override; + void setup_pre_force(int) override; + void post_neighbor() override; void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index ebe97cd542..9a9d751d45 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -27,13 +27,13 @@ namespace LAMMPS_NS { class PairRHEO : public Pair { public: PairRHEO(class LAMMPS *); - virtual ~PairRHEO(); - virtual void compute(int, int); - void settings(int, char **); - void coeff(int, char **); - void setup(); - virtual double init_one(int, int); - virtual double single(int, int, int, int, double, double, double, double &); + ~PairRHEO() override; + void compute(int, int) override; + void settings(int, char **) override; + void coeff(int, char **) override; + void setup() override; + double init_one(int, int) override; + double single(int, int, int, int, double, double, double, double &) override; protected: int laplacian_order; // From fix RHEO From c715552f7e77ea0575869749f728293e37b14abd Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 21 Feb 2023 10:17:15 -0700 Subject: [PATCH 007/385] Ensuring fix order --- src/RHEO/fix_rheo.cpp | 18 +++++++++++++++--- src/RHEO/fix_rheo_thermal.cpp | 3 ++- src/RHEO/fix_rheo_viscosity.cpp | 3 ++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 0c3f784c0e..5ff72045f7 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -197,8 +197,22 @@ void FixRHEO::init() void FixRHEO::setup_pre_force(int /*vflag*/) { - //Need to rethink and replan + // Check to confirm no accessory fixes are yet defined + // FixRHEO must be the first fix + // Note: these fixes set this flag in setup_pre_force() + if (viscosity_fix_defined || pressure_fix_defined || thermal_fix_defined || surface_fix_defined) + error->all(FLERR, "Fix RHEO must be defined before all other RHEO fixes"); + + pre_force(0); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEO::setup() +{ // Check to confirm all accessory fixes are defined + // Does not ensure fixes correctly cover all atoms (could be a subset group) + // Note: these fixes set this flag in setup_pre_force() if (!viscosity_fix_defined) error->all(FLERR, "Missing fix rheo/viscosity"); @@ -216,8 +230,6 @@ void FixRHEO::setup_pre_force(int /*vflag*/) viscosity_fix_defined = 0; pressure_fix_defined = 0; surface_fix_defined = 0; - - pre_force(0); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 0fc4fe294b..37290e3951 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -149,7 +149,6 @@ void FixRHEOThermal::init() if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); - fix_rheo->thermal_fix_defined = 1; if (!fix_rheo->thermal_flag) error->all(FLERR, "Need to define thermal setting in fix rheo"); compute_grad = fix_rheo->compute_grad; @@ -162,6 +161,8 @@ void FixRHEOThermal::init() void FixRHEOThermal::setup_pre_force(int /*vflag*/) { + fix_rheo->thermal_fix_defined = 1; + // Identify whether this is the first/last instance of fix thermal // First will handle growing arrays // Last will handle communication diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 72168b2ee9..8ac32cd1dc 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -102,7 +102,6 @@ void FixRHEOViscosity::init() if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); - fix_rheo->viscosity_fix_defined = 1; compute_grad = fix_rheo->compute_grad; } @@ -110,6 +109,8 @@ void FixRHEOViscosity::init() void FixRHEOViscosity::setup_pre_force(int /*vflag*/) { + fix_rheo->viscosity_fix_defined = 1; + // Identify whether this is the first/last instance of fix viscosity // First will handle growing arrays // Last will handle communication From 99e7673e8ea44429a52c3b0c53f68dde001b75a4 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 21 Feb 2023 19:41:52 -0700 Subject: [PATCH 008/385] Starting pair style, various clean ups --- src/RHEO/fix_rheo.cpp | 23 +++++------ src/RHEO/fix_rheo.h | 63 +++++++++++++++-------------- src/RHEO/fix_rheo_thermal.cpp | 70 +++++++++++++++++++++++---------- src/RHEO/fix_rheo_viscosity.cpp | 12 +++--- src/RHEO/pair_rheo.cpp | 58 ++++++++------------------- src/RHEO/pair_rheo.h | 15 ++++--- 6 files changed, 126 insertions(+), 115 deletions(-) diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 5ff72045f7..e2819ad320 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -66,7 +66,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : if (narg < 5) error->all(FLERR,"Insufficient arguments for fix rheo command"); - cut = utils::numeric(FLERR,arg[3],false,lmp); + h = utils::numeric(FLERR,arg[3],false,lmp); if (strcmp(arg[4],"Quintic") == 0) { kernel_style = QUINTIC; } else if (strcmp(arg[4],"CRK0") == 0) { @@ -125,11 +125,14 @@ FixRHEO::~FixRHEO() if (compute_vshift) modify->delete_compute("rheo_vshift"); } -/* ---------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Create necessary internal computes +------------------------------------------------------------------------- */ void FixRHEO::post_constructor() { - compute_kernel = dynamic_cast(modify->add_compute(fmt::format("rheo_kernel all rheo/kernel {} {} {}", kernel_style, zmin_kernel, cut))); + compute_kernel = dynamic_cast(modify->add_compute(fmt::format("rheo_kernel all rheo/kernel {} {} {}", kernel_style, zmin_kernel, h))); fix_store_visc = dynamic_cast(modify->add_fix("rheo_store_visc all STORE/PERATOM 0 1")) fix_store_visc->disable = 1; @@ -141,14 +144,14 @@ void FixRHEO::post_constructor() std::string cmd = "rheo_grad all rheo/grad {} velocity rho viscosity"; if (thermal_flag) cmd += "temperature"; - compute_grad = dynamic_cast(modify->add_compute(fmt::format(cmd, cut))); + compute_grad = dynamic_cast(modify->add_compute(fmt::format(cmd, h))); compute_grad->fix_rheo = this; if (rhosum_flag) - compute_rhosum = dynamic_cast(modify->add_compute(fmt::format("rheo_rhosum all rheo/rho/sum {} {}", cut, zmin_rhosum))); + compute_rhosum = dynamic_cast(modify->add_compute(fmt::format("rheo_rhosum all rheo/rho/sum {} {}", h, zmin_rhosum))); if (shift_flag) - compute_vshift = dynamic_cast(modify->add_compute(fmt::format("rheo_vshift all rheo/vshift {}", cut))); + compute_vshift = dynamic_cast(modify->add_compute(fmt::format("rheo_vshift all rheo/vshift {}", h))); if (surface_flag) { fix_store_surf = dynamic_cast(modify->add_fix("rheo_store_surf all STORE/PERATOM 0 1")) @@ -163,7 +166,7 @@ void FixRHEO::post_constructor() } if (interface_flag) { - compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface {}", cut))); + compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface {}", h))); fix_store_fp = dynamic_cast(modify->add_fix("rheo_store_fp all STORE/PERATOM 0 3")) f_pressure = fix_store_fp->astore; @@ -197,8 +200,7 @@ void FixRHEO::init() void FixRHEO::setup_pre_force(int /*vflag*/) { - // Check to confirm no accessory fixes are yet defined - // FixRHEO must be the first fix + // Check to confirm accessory fixes do not preceed FixRHEO // Note: these fixes set this flag in setup_pre_force() if (viscosity_fix_defined || pressure_fix_defined || thermal_fix_defined || surface_fix_defined) error->all(FLERR, "Fix RHEO must be defined before all other RHEO fixes"); @@ -210,8 +212,7 @@ void FixRHEO::setup_pre_force(int /*vflag*/) void FixRHEO::setup() { - // Check to confirm all accessory fixes are defined - // Does not ensure fixes correctly cover all atoms (could be a subset group) + // Confirm all accessory fixes are defined, may not cover group all // Note: these fixes set this flag in setup_pre_force() if (!viscosity_fix_defined) error->all(FLERR, "Missing fix rheo/viscosity"); diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 432d319728..3487dd7273 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -32,12 +32,45 @@ class FixRHEO : public Fix { void post_constructor() override; void init() override; void setup_pre_force(int) override; + void setup() override; void pre_force(int) override; void initial_integrate(int) override; void final_integrate() override; void reset_dt() override; + // Model parameters + double h, rho0, csq; + int zmin_kernel, rhosum_zmin; int kernel_style; + enum {QUINTIC, CRK0, CRK1, CRK2}; + + // Non-persistent per-atom arrays + int *surface; + double *conductivity, *viscosity, *pressure; + double **f_pressure; + + // Status variables + enum { + // Phase status + STATUS_FLUID = 1 << 0, + STATUS_REACTIVE = 1 << 1, + STATUS_SOLID = 1 << 2, + STATUS_FREEZING = 1 << 3 + + // Surface status + STATUS_BULK = 1 << 4, + STATUS_LAYER = 1 << 5, + STATUS_SURFACE = 1 << 6, + STATUS_SPLASH = 1 << 7, + + // Temporary status options - reset in preforce + STATUS_SHIFT = 1 << 8, + STATUS_NO_FORCE = 1 << 9, + }; + int phasemask = FFFFFFF0; + int surfacemask = FFFFFF0F; + + // Accessory fixes/computes int thermal_flag; int rhosum_flag; int shift_flag; @@ -47,13 +80,9 @@ class FixRHEO : public Fix { int viscosity_fix_defined; int pressure_fix_defined; int thermal_fix_defined; + int interface_fix_defined; int surface_fix_defined; - // Non-persistent per-atom arrays - int *surface; - double *conductivity, *viscosity, *pressure; - double **f_pressure; - class FixStorePeratom *fix_store_visc; class FixStorePeratom *fix_store_pres; class FixStorePeratom *fix_store_cond; @@ -66,31 +95,7 @@ class FixRHEO : public Fix { class ComputeRHEORhoSum *compute_rhosum; class ComputeRHEOVShift *compute_vshift; - enum {QUINTIC, CRK0, CRK1, CRK2}; - enum {LINEAR, CUBIC, TAITWATER}; - - enum { - // Phase status - STATUS_FLUID = 1 << 0, //Need to turn off other options - STATUS_REACTIVE = 1 << 1, - STATUS_SOLID = 1 << 2, - STATUS_FREEZING = 1 << 3 - - // Temporary status options - reset in preforce - STATUS_SHIFT = 1 << 4, - STATUS_NO_FORCE = 1 << 5, - - // Surface status - STATUS_BULK = 1 << 6, //Need to turn off other options - STATUS_LAYER = 1 << 7, - STATUS_SURFACE = 1 << 8, - STATUS_SPLASH = 1 << 9, - }; - protected: - double cut, rho0, csq; - int zmin_kernel, rhosum_zmin; - double dtv, dtf; }; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 37290e3951..406439f93e 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -240,9 +240,11 @@ void FixRHEOThermal::post_integrate() Tci = Tc_type[type[i]]); } - if (Ti > Tci) { //Need to untoggle other phase options + if (Ti > Tci) { + status[i] &= phasemask; status[i] |= FixRHEO::STATUS_FLUID; } else if (!(status[i] & FixRHEO::STATUS_SOLID)) + status[i] &= phasemask; status[i] |= FixRHEO::STATUS_FREEZING; } } @@ -250,31 +252,59 @@ void FixRHEOThermal::post_integrate() } } +/* ---------------------------------------------------------------------- + Only need to update non-evolving conductivity styles after atoms exchange +------------------------------------------------------------------------- */ -add post neighbor then update preforce below -/* ---------------------------------------------------------------------- */ +void FixRHEOThermal::post_neighbor() +{ + int i; + int *type = atom->type; + double *conductivity = fix_rheo->conductivity; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + if (first_flag & nmax < atom->nmax) { + nmax = atom->nmax; + fix_rheo->fix_store_cond->grow_arrays(nmax); + } + + if (conductivity_style == CONSTANT) { + for (i = 0; i < nall; i++) + if (mask[i] & groupbit) conductivity[i] = kappa; + } else if (conductivity_style == TYPE) { + for (i = 0; i < nall; i++) + if (mask[i] & groupbit) conductivity[i] = kappa_type[type[i]]; + } + } +} + +/* ---------------------------------------------------------------------- + Update (and forward) evolving conductivity styles every timestep +------------------------------------------------------------------------- */ void FixRHEOThermal::pre_force(int /*vflag*/) { - double *conductivity = atom->conductivity; - int *mask = atom->mask; - int nlocal = atom->nlocal; + // So far, none exist + //int i; + //double *conductivity = fix_rheo->conductivity; + //int *mask = atom->mask; + //int nlocal = atom->nlocal; - // Calculate non-persistent quantities before pairstyles - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) { - conductivity[i] = calc_kappa(i); - } - } + //if (first_flag & nmax < atom->nmax) { + // nmax = atom->nmax; + // fix_rheo->fix_store_cond->grow_arrays(nmax); + //} - if (conductivity_style == CONSTANT) { - return kappa; - } else if (conductivity_style == TYPE) { - int itype = atom->type[i]; - return(kappa_type[itype]); - } else { - error->all(FLERR, "Invalid style"); - } + //if (conductivity_style == TBD) { + // for (i = 0; i < nlocal; i++) { + // if (mask[i] & groupbit) { + // } + // } + //} + + //if (last_flag && comm_forward) comm->forward_comm(this); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 8ac32cd1dc..f57410783c 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -131,8 +131,9 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) pre_force(0); } - -/* ---------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Only need to update non-evolving viscosity styles after atoms exchange +------------------------------------------------------------------------- */ void FixRHEOViscosity::post_neighbor() { @@ -150,7 +151,6 @@ void FixRHEOViscosity::post_neighbor() fix_rheo->fix_store_visc->grow_arrays(nmax); } - // Update non-evolving viscosity styles only after atoms can exchange if (viscosity_style == CONSTANT) { for (i = 0; i < nall; i++) if (mask[i] & groupbit) viscosity[i] = eta; @@ -161,14 +161,15 @@ void FixRHEOViscosity::post_neighbor() } } -/* ---------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Update (and forward) evolving viscosity styles every timestep +------------------------------------------------------------------------- */ void FixRHEOViscosity::pre_force(int /*vflag*/) { int i, a, b; double tmp, gdot; - int *type = atom->type; double *viscosity = fix_rheo->viscosity; int *mask = atom->mask; double **gradv = compute_grad->gradv; @@ -181,7 +182,6 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) fix_rheo->fix_store_visc->grow_arrays(nmax); } - // Update viscosity styles that evolve in time every timestep if (viscosity_style == POWER) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index b0443933e1..c796db208a 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -394,23 +394,23 @@ void PairRHEO::allocate() void PairRHEO::settings(int narg, char **arg) { - if(narg < 1) error->all(FLERR,"Illegal pair_style command"); + if (narg < 1) error->all(FLERR,"Illegal pair_style command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg], "rho/damp") == 0) { - if (iarg+1 >= narg) error->all(FLERR,"Illegal pair_style command"); + if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_style command"); rho_damp_flag = 1; - rho_damp = utils::numeric(FLERR,arg[iarg+1],false,lmp); - iarg ++; + rho_damp = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + iarg++; } else if (strcmp(arg[iarg], "artificial/visc") == 0) { - if (iarg+1 >= narg) error->all(FLERR,"Illegal pair_style command"); + if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_style command"); artificial_visc_flag = 1; av = utils::numeric(FLERR,arg[iarg+1],false,lmp); - iarg ++; - } else error->all(FLERR,"Illegal pair_style command"); + iarg++; + } else error->all(FLERR,"Illegal pair_style command, {}", arg[iarg]); iarg++; } } @@ -421,8 +421,8 @@ void PairRHEO::settings(int narg, char **arg) void PairRHEO::coeff(int narg, char **arg) { - if (narg != 4) - error->all(FLERR,"Incorrect number of args for pair_style llns coefficients"); + if (narg != 2) + error->all(FLERR,"Incorrect number of args for pair_style rheo coefficients"); if (!allocated) allocate(); @@ -430,17 +430,8 @@ void PairRHEO::coeff(int narg, char **arg) utils::bounds(FLERR,arg[0],1, atom->ntypes, ilo, ihi,error); utils::bounds(FLERR,arg[1],1, atom->ntypes, jlo, jhi,error); - double rho0_one = utils::numeric(FLERR,arg[2],false,lmp); - double c_one = utils::numeric(FLERR,arg[3],false,lmp); - - if (c_one != 1.0) error->warning(FLERR, "Need c = 1 for assumption in compute rheo/solids"); - if (rho0_one != 1.0) error->warning(FLERR, "Need rho0 = 1 for assumption in compute rheo/solids"); - int count = 0; for (int i = ilo; i <= ihi; i++) { - rho0[i] = rho0_one; - csq[i] = c_one*c_one; - for (int j = 0; j <= atom->ntypes; j++) { setflag[i][j] = 1; count++; @@ -448,7 +439,7 @@ void PairRHEO::coeff(int narg, char **arg) } if (count == 0) - error->all(FLERR,"Incorrect args for pair llns coefficients"); + error->all(FLERR,"Incorrect args for pair rheo coefficients"); } /* ---------------------------------------------------------------------- @@ -457,26 +448,21 @@ void PairRHEO::coeff(int narg, char **arg) void PairRHEO::setup() { - int flag; - int ifix = modify->find_fix_by_style("rheo"); - if (ifix == -1) error->all(FLERR, "Using pair RHEO without fix RHEO"); - fix_rheo = ((FixRHEO *) modify->fix[ifix]); + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); + fix_rheo = dynamic_cast(fixes[0]); compute_kernel = fix_rheo->compute_kernel; compute_grad = fix_rheo->compute_grad; - compute_sinterpolation = fix_rheo->compute_sinterpolation; + compute_interface = fix_rheo->compute_interface; thermal_flag = fix_rheo->thermal_flag; + h = fix_rheo->h; + csq = fix_rheo->csq; + rho0 = fix_rheo->rho0; - - - - h = utils::numeric(FLERR,arg[0],false,lmp); - if (h <= 0.0) error->all(FLERR,"Illegal pair_style command"); hinv = 1.0 / h; - hinv3 = 3.0 * hinv; laplacian_order = -1; - if (comm->ghost_velocity == 0) error->all(FLERR,"Pair RHEO requires ghost atoms store velocity"); @@ -505,13 +491,3 @@ double PairRHEO::init_one(int i, int j) return cut[i][j]; } - -/* ---------------------------------------------------------------------- */ - -double PairRHEO::single(int /*i*/, int /*j*/, int /*itype*/, int /*jtype*/, - double /*rsq*/, double /*factor_coul*/, double /*factor_lj*/, double &fforce) -{ - fforce = 0.0; - - return 0.0; -} diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index 9a9d751d45..026bc16527 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -12,9 +12,9 @@ ------------------------------------------------------------------------- */ #ifdef PAIR_CLASS - +// clang-format off PairStyle(rheo,PairRHEO) - +// clang-format on #else #ifndef LMP_PAIR_RHEO_H @@ -33,14 +33,13 @@ class PairRHEO : public Pair { void coeff(int, char **) override; void setup() override; double init_one(int, int) override; - double single(int, int, int, int, double, double, double, double &) override; protected: - int laplacian_order; // From fix RHEO - double h, csq*, rho0*; // From fix RHEO + double h, csq, rho0; // From fix RHEO - double hsq, hinv, rho0, av, rho_damp; + double hsq, hinv, av, rho_damp; + int laplacian_order; int artificial_visc_flag; int rho_damp_flag; int thermal_flag; @@ -49,11 +48,11 @@ class PairRHEO : public Pair { class ComputeRHEOKernel *compute_kernel; class ComputeRHEOGrad *compute_grad; - class ComputeRHEOSolidInterpolation *compute_sinterpolation; + class ComputeRHEOInterface *compute_interface; class FixRHEO *fix_rheo; }; -} +} // namespace LAMMPS_NS #endif #endif From ecf43524d4ff2320b226d381af0090f0fd4e3aff Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 21 Feb 2023 22:07:11 -0700 Subject: [PATCH 009/385] Most updates to pair --- src/RHEO/pair_rheo.cpp | 199 +++++++++++++++++++---------------------- src/RHEO/pair_rheo.h | 2 +- 2 files changed, 91 insertions(+), 110 deletions(-) diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index c796db208a..1bed3f1d3e 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -22,6 +22,7 @@ #include "error.h" #include "fix_rheo.h" #include "force.h" +#include "math_extra.h" #include "memory.h" #include "modify.h" #include "neighbor.h" @@ -32,6 +33,7 @@ #include using namespace LAMMPS_NS; +using namespace MathExtra; #define EPSILON 1e-2 @@ -66,16 +68,17 @@ void PairRHEO::compute(int eflag, int vflag) int i, j, a, b, ii, jj, inum, jnum, itype, jtype; int error_flag, pair_force_flag, pair_rho_flag, pair_avisc_flag; double xtmp, ytmp, ztmp; + int fluidi, fluidj; int *ilist, *jlist, *numneigh, **firstneigh; - double imass, jmass, rsq, r, ir; + double imass, jmass, rsq, r, rinv; double w, wp, rhoi, rhoj, voli, volj, Pi, Pj; double *dWij, *dWji, *d2Wij, *d2Wji, *dW1ij, *dW1ji; double vijeij, etai, etaj, kappai, kappaj; double Ti, Tj, dT; double drho_damp, fmag; - double mu, q, cs, fp_prefactor; + double mu, q, fp_prefactor; double dx[3] = {0}; double fv[3] = {0}; double dfp[3] = {0}; @@ -96,18 +99,20 @@ void PairRHEO::compute(int eflag, int vflag) double **v = atom->v; double **x = atom->x; double **f = atom->f; - double **fp = atom->fp; double *rho = atom->rho; double *mass = atom->mass; double *drho = atom->drho; - double *temp = atom->temp; - double *heat = atom->heat; - double *viscosity = atom->viscosity; - double *conductivity = atom->conductivity; + double *temperature = atom->temperature; + double *heatflow = atom->heatflow; + double *chi = compute_interface->chi; + double **f_pressure = fix_rheo->f_pressure; + double *viscosity = fix_rheo->viscosity; + double *conductivity = fix_rheo->conductivity; + double *pressure = fix_rheo->pressure; double *special_lj = force->special_lj; tagint *tag = atom->tag; int *type = atom->type; - int *phase = atom->phase; + int *status = atom->status; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; @@ -132,7 +137,8 @@ void PairRHEO::compute(int eflag, int vflag) kappai = conductivity[i]; etai = viscosity[i]; - Ti = temp[i]; + Ti = temperature[i]; + fluidi = status[i] & FixRHEO::STATUS_FLUID; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -142,25 +148,26 @@ void PairRHEO::compute(int eflag, int vflag) dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; + rsq = lensq3(dx); jtype = type[j]; jmass = mass[jtype]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); - ir = 1/r; + rinv = 1 / r; kappaj = conductivity[j]; etaj = viscosity[j]; - Tj = temp[j]; + Tj = temperature[j]; + fluidj = status[j] & FixRHEO::STATUS_FLUID; pair_rho_flag = 0; pair_force_flag = 0; pair_avisc_flag = 0; - if (phase[i] <= FixRHEO::FLUID_MAX || phase[j] <= FixRHEO::FLUID_MAX) { + if (fluidi || fluidj) { pair_force_flag = 1; } - if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { + if (fluidi && fluidj) { pair_avisc_flag = 1; pair_rho_flag = 1; } @@ -169,51 +176,45 @@ void PairRHEO::compute(int eflag, int vflag) dWij = compute_kernel->dWij; dWji = compute_kernel->dWji; - for (a = 0; a < dim; a ++) { + for (a = 0; a < dim; a++) { vi[a] = v[i][a]; vj[a] = v[j][a]; - fsolid[a] = 0.0; } + // TODO: search for fix pressure and add calculate P function // Add corrections for walls rhoi = rho[i]; rhoj = rho[j]; - if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { - compute_sinterpolation->correct_v(v[i], v[j], vi, i, j); - rhoj = compute_sinterpolation->correct_rho(j,i); + Pi = pressure[i]; + Pj = pressure[j]; + fmag = 0; + if (fluidi && (!fluidj)) { + compute_interface->correct_v(v[i], v[j], vi, i, j); + rhoj = compute_interface->correct_rho(j, i); + Pj = fix_pressure->calculate_P(rhoj); + if ((chi[j] > 0.9) && (r < (h * 0.5))) + fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; - // Repel if close to inner solid particle - if (compute_sinterpolation->chi[j] > 0.9 && r < (cut[itype][jtype] * 0.5)) { - fmag = (compute_sinterpolation->chi[j] - 0.9) * (cut[itype][jtype] * 0.5 - r); - fmag *= rho0[itype] * csq[itype] * cut[itype][jtype] * ir; - fsolid[0] = fmag * dx[0]; - fsolid[1] = fmag * dx[1]; - fsolid[2] = fmag * dx[2]; - } - } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { - compute_sinterpolation->correct_v(v[j], v[i], vj, j, i); - rhoi = compute_sinterpolation->correct_rho(i,j); + } else if ((!fluidi) && fluidj) { + compute_interface->correct_v(v[j], v[i], vj, j, i); + rhoi = compute_interface->correct_rho(i,j); + Pi = fix_pressure->calculate_P(rhoi); + if ((chi[i] > 0.9) && (r < (h * 0.5))) + fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; - // Repel if close to inner solid particle - if (compute_sinterpolation->chi[i] > 0.9 && r < (cut[itype][jtype] * 0.5)) { - fmag = (compute_sinterpolation->chi[i] - 0.9) * (cut[itype][jtype] * 0.5 - r); - fmag *= rho0[jtype] * csq[jtype] * cut[itype][jtype] * ir; - fsolid[0] = fmag * dx[0]; - fsolid[1] = fmag * dx[1]; - fsolid[2] = fmag * dx[2]; - } - } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { + } else if ((!fluidi) && (!fluidj)) { rhoi = 1.0; rhoj = 1.0; } - // Compute volume and pressure after reconstructing + // Repel if close to inner solid particle + scale3(fmag, dx, fsolid); + + // Compute volume after reconstructing voli = imass / rhoi; volj = jmass / rhoj; - Pj = calc_pressure(rhoj, jtype); - Pi = calc_pressure(rhoi, itype); - //Check if Second order kernels will be used for eta*Lap(v) + //Check if Second order kernels will be used for eta * Lap(v) error_flag = 0; if (laplacian_order == 2) { error_flag = compute_kernel->calc_d2w(i, j, dx[0], dx[1], dx[2], r); @@ -221,15 +222,13 @@ void PairRHEO::compute(int eflag, int vflag) d2Wji = compute_kernel->d2Wji; } - //Thermal Evolution + // Thermal Evolution if (thermal_flag) { dT = 0.0; - for (a = 0; a < dim; a++) { - dT += (kappai + kappaj) * (Ti-Tj) * dx[a] * dWij[a] * ir * ir; - //Assumes heat capacity and density = 1, needs to be generalized - } - dT *= voli * volj; - heat[i] += dT; + for (a = 0; a < dim; a++) dT += dx[a] * dWij[a]; + //TODO: Assumes heat capacity and density = 1, needs to be generalized + dT *= voli * volj * (kappai + kappaj) * (Ti - Tj) * rinv * rinv; + heatflow[i] += dT; } // If either particle is fluid, compute hydrostatic and viscous forces @@ -247,62 +246,56 @@ void PairRHEO::compute(int eflag, int vflag) du[a] -= 0.5 * (gradv[i][a * dim + b] + gradv[j][a * dim + b]) * dx[b]; } } - mu = (du[0] * dx[0] + du[1] * dx[1]+ du[2] * dx[2]) * hinv3; - mu = mu / (rsq * hinv3 * hinv3 + EPSILON); + // TODO is hinv3 supposed to be 3.0/h? + mu = lensq3(du) * 3 * hinv; + mu /= (rsq * 9 * hinv * hinv + EPSILON); mu= MIN(0.0, mu); - cs = 0.5 * (sqrt(csq[itype]) + sqrt(csq[jtype])); + // "kinematic viscous pressure" q = Q/rho - q = av*(-2.0*cs*mu + 1.0*mu*mu); - fp_prefactor += voli*volj*q*(rhoj + rhoi); + q = av * (-2.0 * cs * mu + 1.0 * mu * mu); //TODO is 1.0 supposed to be something? + fp_prefactor += voli * volj * q * (rhoj + rhoi); } // -Grad[P + Q] - dfp[0] = - fp_prefactor*dWij[0]; - dfp[1] = - fp_prefactor*dWij[1]; - dfp[2] = - fp_prefactor*dWij[2]; + scale3(-fp_prefactor, dWij, dfp); - // Now compute viscous eta*Lap[v] terms + // Now compute viscous eta * Lap[v] terms for (a = 0; a < dim; a ++) { fv[a] = 0.0; - for (b = 0; b < dim; b++) { - fv[a] += (etai+etaj)*(vi[a]-vj[a])*dx[b]*dWij[b]*ir*ir; - } - fv[a] *= voli*volj; + for (b = 0; b < dim; b++) fv[a] += (vi[a] - vj[a]) * dx[b] * dWij[b]; + fv[a] *= voli * volj * rinv * rinv * (etai + etaj); } } else { - for (a = 0; a < dim; a ++) { - fv[a] = 0; - dfp[a] = 0; - } + zero3(fv); + zero3(dfp); } if (pair_force_flag) { f[i][0] += fv[0] + dfp[0] + fsolid[0]; f[i][1] += fv[1] + dfp[1] + fsolid[1]; f[i][2] += fv[2] + dfp[2] + fsolid[2]; - fp[i][0] += dfp[0]; - fp[i][1] += dfp[1]; - fp[i][2] += dfp[2]; + f_pressure[i][0] += dfp[0]; + f_pressure[i][1] += dfp[1]; + f_pressure[i][2] += dfp[2]; } // Density damping // conventional for low-order h // interpolated for RK 1 & 2 (Antuono et al, Computers & Fluids 2021) if (rho_damp_flag && pair_rho_flag) { - if (laplacian_order>=1 && error_flag == 0){ - psi_ij = rhoj-rhoi; + if ((laplacian_order >= 1) && (error_flag == 0)) { + psi_ij = rhoj - rhoi; Fij = 0.0; for (a = 0; a < dim; a++){ - psi_ij += 0.5*(gradr[i][a]+gradr[j][a])*dx[a]; - Fij -= dx[a]*dWij[a]; + psi_ij += 0.5 * (gradr[i][a] + gradr[j][a]) * dx[a]; + Fij -= dx[a] * dWij[a]; } - Fij *= ir*ir; - drho[i] += 2*rho_damp*psi_ij*Fij*volj; - } - else { - drho_damp = 2*rho_damp*(rhoj-rhoi)*ir*wp; - drho[i] -= drho_damp*volj; + Fij *= rinv * rinv; + drho[i] += 2 * rho_damp * psi_ij * Fij * volj; + } else { + drho_damp = 2 * rho_damp * (rhoj - rhoi) * rinv * wp; + drho[i] -= drho_damp * volj; } } @@ -314,55 +307,42 @@ void PairRHEO::compute(int eflag, int vflag) if (thermal_flag) { dT = 0.0; - for(a = 0; a < dim; a++){ - //dT += kappai*dWji[a]*gradt[i][a]; - //dT -= kappaj*dWji[a]*gradt[j][a]; - dT += 1/1*(kappai+kappaj)*(Ti-Tj)*dx[a]*dWji[a]*ir*ir; //Assumes heat capacity and density = 1, needs to be generalized - } - dT *= -voli*volj; + for (a = 0; a < dim; a++) dT += dx[a] * dWji[a]; //TODO csq and h terms + dT *= -voli * volj * (kappai + kappaj) * (Ti - Tj) * rinv * rinv; heat[j] -= dT; } for (a = 0; a < dim; a ++) { fv[a] = 0.0; - for (b = 0; b < dim; b++) { - //fv[a] += etai*dWji[b]*(gradv[i][a*dim+b]+gradv[i][b*dim+a]); - //fv[a] -= etaj*dWji[b]*(gradv[j][a*dim+b]+gradv[j][b*dim+a]); - fv[a] += (etai+etaj)*(vi[a]-vj[a])*dx[b]*dWji[b]*ir*ir; - } - fv[a] *= -voli*volj; // flip sign here b/c -= at accummulator + for (b = 0; b < dim; b++) fv[a] += (vi[a] - vj[a]) * dx[b] * dWji[b]; + fv[a] *= -voli * volj * (etai + etaj) * rinv * rinv; + // flip sign here b/c -= at accummulator } - - if (pair_force_flag) { for (a = 0; a < dim; a++) - dfp[a] = fp_prefactor*dWji[a]; + dfp[a] = fp_prefactor * dWji[a]; } if (rho_damp_flag && pair_rho_flag){ - if (laplacian_order>=1 && error_flag == 0){ + if ((laplacian_order >= 1) && (error_flag == 0)) { Fij = 0.0; - for (a = 0; a < dim; a++){ - Fij += dx[a]*dWji[a]; - } - Fij *= ir*ir; + for (a = 0; a < dim; a++) Fij += dx[a] * dWji[a]; + Fij *= rinv * rinv; psi_ij *= -1; - drho[j] += 2*rho_damp*psi_ij*Fij*voli; - } - else { - drho_damp = 2*rho_damp*(rhoj-rhoi)*ir*wp; - drho[j] += drho_damp*voli; + drho[j] += 2 * rho_damp * psi_ij * Fij * voli; + } else { + drho_damp = 2 * rho_damp * (rhoj - rhoi) * rinv * wp; + drho[j] += drho_damp * voli; } } if (pair_force_flag) { f[j][0] -= fv[0] + dfp[0] + fsolid[0]; f[j][1] -= fv[1] + dfp[1] + fsolid[1]; f[j][2] -= fv[2] + dfp[2] + fsolid[2]; - - fp[j][0] -= dfp[0]; - fp[j][1] -= dfp[1]; - fp[j][2] -= dfp[2]; + f_pressure[j][0] -= dfp[0]; + f_pressure[j][1] -= dfp[1]; + f_pressure[j][2] -= dfp[2]; } } } @@ -461,6 +441,7 @@ void PairRHEO::setup() rho0 = fix_rheo->rho0; hinv = 1.0 / h; + cs = sqrt(csq); laplacian_order = -1; if (comm->ghost_velocity == 0) diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index 026bc16527..42172be3a4 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -37,7 +37,7 @@ class PairRHEO : public Pair { protected: double h, csq, rho0; // From fix RHEO - double hsq, hinv, av, rho_damp; + double cs, hsq, hinv, av, rho_damp; int laplacian_order; int artificial_visc_flag; From 6e65d13ad31f36a9b30b8852c676e1efd8a9bd57 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 26 Feb 2023 21:13:32 -0700 Subject: [PATCH 010/385] Adding vshift + pressure, various fixes --- src/RHEO/compute_rheo_grad.cpp | 2 +- src/RHEO/compute_rheo_vshift.cpp | 294 +++++++++++++++++++++++++++++++ src/RHEO/compute_rheo_vshift.h | 57 ++++++ src/RHEO/fix_rheo.cpp | 45 ++++- src/RHEO/fix_rheo_pressure.cpp | 206 ++++++++++++++++++++++ src/RHEO/fix_rheo_pressure.h | 49 ++++++ src/RHEO/fix_rheo_thermal.cpp | 2 +- src/RHEO/fix_rheo_viscosity.cpp | 6 +- src/RHEO/pair_rheo.cpp | 51 +++--- src/RHEO/pair_rheo.h | 1 + 10 files changed, 669 insertions(+), 44 deletions(-) create mode 100644 src/RHEO/compute_rheo_vshift.cpp create mode 100644 src/RHEO/compute_rheo_vshift.h create mode 100644 src/RHEO/fix_rheo_pressure.cpp create mode 100644 src/RHEO/fix_rheo_pressure.h diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index e87d39aa53..0cefd2ac6a 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -41,7 +41,7 @@ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : velocity_flag = temperature_flag = rho_flag = eta_flag = 0; - for (int iarg = 3; iarg < narg; iarg ++) { + for (int iarg = 3; iarg < narg; iarg++) { if (strcmp(arg[iarg],"velocity") == 0) velocity_flag = 1; else if (strcmp(arg[iarg],"rho") == 0) rho_flag = 1; else if (strcmp(arg[iarg],"temperature") == 0) temperature_flag = 1; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp new file mode 100644 index 0000000000..42fa1e8c82 --- /dev/null +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -0,0 +1,294 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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_rheo_vshift.h" +#include "fix_rheo.h" +#include "compute_rheo_solids.h" +#include "compute_rheo_grad.h" +#include "compute_rheo_kernel.h" +#include "fix_rheo_surface.h" +#include +#include +#include "atom.h" +#include "modify.h" +#include "domain.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "force.h" +#include "pair.h" +#include "comm.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOVShift::ComputeRHEOVShift(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), vshift(nullptr), fix_rheo(nullptr), compute_kernel(nullptr), + compute_grad(nullptr), compute_surface(nullptr), compute_interface(nullptr) +{ + if (narg != 3) error->all(FLERR,"Illegal compute RHEO/VShift command"); + + comm_reverse = 3; + surface_flag = 0; + + nmax = atom->nmax; + memory->create(vshift, nmax, 3, "rheo/vshift:vshift"); + array_atom = vshift; + peratom_flag = 1; + size_peratom_cols = 3; +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOVShift::~ComputeRHEOVShift() +{ + memory->destroy(vshift); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOVShift::init() +{ + neighbor->add_request(this, NeighConst::REQ_DEFAULT); + + surface_flag = 0; + if (fix_rheo->surface_flag) { + surface_flag = 1; + fix_rheo_surface = fix_rheo->fix_rheo_surface; + } + + compute_kernel = fix_rheo->compute_kernel; + compute_grad = fix_rheo->compute_grad; + compute_interface = fix_rheo->compute_interface; + + cut = fix_rheo->cut; + cutsq = cut * cut; + cutthird = cut / 3.0; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOVShift::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOVShift::compute_peratom() +{ + int i, j, a, b, ii, jj, jnum, itype, jtype; + int fluidi, fluidj; + double xtmp, ytmp, ztmp, rsq, r, rinv; + double w, wp, dr, w0, w4, vmag, prefactor; + double imass, jmass, voli, volj, rhoi, rhoj; + double dx[3], vi[3], vj[3] = {0}; + int dim = domain->dimension; + + int *jlist; + int inum, *ilist, *numneigh, **firstneigh; + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + double **x = atom->x; + double **v = atom->v; + int *type = atom->type; + int *status = atom->status; + int *surface = atom->surface; + double *rho = atom->rho; + double *mass = atom->mass; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + if (nall > nmax) { + nmax = nall; + memory->destroy(vshift); + memory->create(vshift, nmax, 3, "rheo/vshift:vshift"); + array_atom = vshift; + } + + for (i = 0; i < nall; i++) + for (a = 0; a < dim; a++) + vshift[i][a] = 0.0; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + imass = mass[itype]; + fluidi = status[i] & FixRHEO::STATUS_FLUID; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + fluidj = status[j] & FixRHEO::STATUS_FLUID; + if ((!fluidi) && (!fluidj)) continue; + if (!(status[i] & FixRHEO::STATUS_SHIFT) && !(status[j] & FixRHEO::STATUS_SHIFT)) continue; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; + + if (rsq < cutsq) { + jtype = type[j]; + jmass = mass[jtype]; + + r = sqrt(rsq); + rinv = 1 / r; + + for (a = 0; a < dim; a ++) { + vi[a] = v[i][a]; + vj[a] = v[j][a]; + } + + rhoi = rho[i]; + rhoj = rho[j]; + + // Add corrections for walls + if (fluidi && (!fluidj)) { + compute_interface->correct_v(v[i], v[j], vi, i, j); + rhoj = compute_interface->correct_rho(j,i); + } else if ((!fluidi) && fluidj) { + compute_interface->correct_v(v[j], v[i], vj, j, i); + rhoi = compute_interface->correct_rho(i,j); + } else if ((!fluidi) && (!fluidj)) { + rhoi = 1.0; + rhoj = 1.0; + } + + voli = imass / rhoi; + volj = jmass / rhoj; + + wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2], r); + w = compute_kernel->calc_w(i, j, dx[0], dx[1], dx[2], r); + w0 = compute_kernel->calc_w(i, j, 0, 0, 0, cutthird); // dx, dy, dz irrelevant + w4 = w * w * w * w / (w0 * w0 * w0 * w0); + dr = -2 * cutthird * (1 + 0.2 * w4) * wp * rinv; + + if (mask[i] & groupbit) { + vmag = sqrt(vi[0] * vi[0] + vi[1] * vi[1] + vi[2] * vi[2]); + prefactor = vmag * volj * dr; + vshift[i][0] += prefactor * dx[0]; + vshift[i][1] += prefactor * dx[1]; + vshift[i][2] += prefactor * dx[2]; + } + + if (newton_pair || j < nlocal) { + if (mask[j] & groupbit) { + vmag = sqrt(vj[0] * vj[0] + vj[1] * vj[1] + vj[2] * vj[2]); + prefactor = vmag * voli * dr; + vshift[j][0] -= prefactor * dx[0]; + vshift[j][1] -= prefactor * dx[1]; + vshift[j][2] -= prefactor * dx[2]; + } + } + } + } + } + + if (newton_pair) comm->reverse_comm_compute(this); +} + + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOVShift::correct_surfaces() +{ + if (!surface_flag) return; + + int *status = atom->status; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int i, a, b; + int dim = domain->dimension; + int *surface = atom->surface; + + double **nsurf; + nsurf = fix_rheo_surface->n_surface; + double nx,ny,nz,vx,vy,vz; + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + if (surface[i] == 1 || surface[i] == 2) { + nx = nsurf[i][0]; + ny = nsurf[i][1]; + vx = vshift[i][0]; + vy = vshift[i][1]; + vz = vshift[i][2]; + vshift[i][0] = (1 - nx * nx) * vx - nx * ny * vy; + vshift[i][1] = (1 - ny * ny) * vy - nx * ny * vx; + if (dim > 2) { + nz = nsurf[i][2]; + vshift[i][0] -= nx * nz * vz; + vshift[i][1] -= ny * nz * vz; + vshift[i][2] = (1 - nz * nz) * vz - nz * ny * vy - nx * nz * vx; + } else { + vshift[i][2] = 0.0; + } + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOVShift::pack_reverse_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = vshift[i][0]; + buf[m++] = vshift[i][1]; + buf[m++] = vshift[i][2]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOVShift::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + vshift[j][0] += buf[m++]; + vshift[j][1] += buf[m++]; + vshift[j][2] += buf[m++]; + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeRHEOVShift::memory_usage() +{ + double bytes = 3 * nmax * sizeof(double); + return bytes; +} diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h new file mode 100644 index 0000000000..fceb287510 --- /dev/null +++ b/src/RHEO/compute_rheo_vshift.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(rheo/vshift,ComputeRHEOVShift) +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_VSHIFT_H +#define LMP_COMPUTE_RHEO_VSHIFT_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEOVShift : public Compute { + public: + ComputeRHEOVShift(class LAMMPS *, int, char **); + ~ComputeRHEOVShift() override; + void init() override; + void init_list(int, class NeighList *) override; + void compute_peratom() override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; + double memory_usage() override; + void correct_surfaces(); + + private: + int nmax; + double dtv, cut, cutsq, cutthird; + int surface_flag; + + double **vshift; + + class NeighList *list; + class FixRHEO *fix_rheo; + class FixRHEOSurface *fix_rheo_surface; + class ComputeRHEOInterface *compute_interface ; + class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOGrad *compute_grad; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index e2819ad320..12185b549c 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -132,7 +132,7 @@ FixRHEO::~FixRHEO() void FixRHEO::post_constructor() { - compute_kernel = dynamic_cast(modify->add_compute(fmt::format("rheo_kernel all rheo/kernel {} {} {}", kernel_style, zmin_kernel, h))); + compute_kernel = dynamic_cast(modify->add_compute("rheo_kernel all rheo/kernel")); fix_store_visc = dynamic_cast(modify->add_fix("rheo_store_visc all STORE/PERATOM 0 1")) fix_store_visc->disable = 1; @@ -142,16 +142,18 @@ void FixRHEO::post_constructor() fix_store_pres->disable = 1; - std::string cmd = "rheo_grad all rheo/grad {} velocity rho viscosity"; + std::string cmd = "rheo_grad all rheo/grad velocity rho viscosity"; if (thermal_flag) cmd += "temperature"; - compute_grad = dynamic_cast(modify->add_compute(fmt::format(cmd, h))); + compute_grad = dynamic_cast(modify->add_compute(cmd)); compute_grad->fix_rheo = this; if (rhosum_flag) - compute_rhosum = dynamic_cast(modify->add_compute(fmt::format("rheo_rhosum all rheo/rho/sum {} {}", h, zmin_rhosum))); + compute_rhosum = dynamic_cast(modify->add_compute("rheo_rhosum all rheo/rho/sum")); - if (shift_flag) - compute_vshift = dynamic_cast(modify->add_compute(fmt::format("rheo_vshift all rheo/vshift {}", h))); + if (shift_flag) { + compute_vshift = dynamic_cast(modify->add_compute("rheo_vshift all rheo/vshift")); + compute_vshift->fix_rheo = this; + } if (surface_flag) { fix_store_surf = dynamic_cast(modify->add_fix("rheo_store_surf all STORE/PERATOM 0 1")) @@ -166,7 +168,7 @@ void FixRHEO::post_constructor() } if (interface_flag) { - compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface {}", h))); + compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface"))); fix_store_fp = dynamic_cast(modify->add_fix("rheo_store_fp all STORE/PERATOM 0 3")) f_pressure = fix_store_fp->astore; @@ -212,7 +214,7 @@ void FixRHEO::setup_pre_force(int /*vflag*/) void FixRHEO::setup() { - // Confirm all accessory fixes are defined, may not cover group all + // Confirm all accessory fixes are defined // Note: these fixes set this flag in setup_pre_force() if (!viscosity_fix_defined) error->all(FLERR, "Missing fix rheo/viscosity"); @@ -231,6 +233,33 @@ void FixRHEO::setup() viscosity_fix_defined = 0; pressure_fix_defined = 0; surface_fix_defined = 0; + + // Check fixes cover all atoms (doesnt ensure user covers atoms created midrun) + // (pressure is currently required to be group all) + auto visc_fixes = modify->get_fix_by_style("rheo/viscosity"); + auto therm_fixes = modify->get_fix_by_style("rheo/thermal"); + + int *mask = atom->mask; + int v_coverage_flag = 1; + int t_coverage_flag = 1; + int covered; + for (int i = 0; i < atom->nlocal; i++) { + covered = 0; + for (auto fix in visc_fixes) + if (mask[i] & fix->groupbit) covered = 1; + if (!covered) v_coverage_flag = 0; + if (thermal_flag) { + covered = 0; + for (auto fix in therm_fixes) + if (mask[i] & fix->groupbit) covered = 1; + if (!covered) v_coverage_flag = 0; + } + } + + if (!v_coverage_flag) + error->one(FLERR, "Fix rheo/viscosity does not fully cover all atoms"); + if (!t_coverage_flag) + error->one(FLERR, "Fix rheo/thermal does not fully cover all atoms"); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp new file mode 100644 index 0000000000..8f42e22239 --- /dev/null +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -0,0 +1,206 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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 "fix_rheo_pressure.h" + +#include "atom.h" +#include "comm.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "memory.h" +#include "modify.h" +#include "update.h" + +#include + +using namespace LAMMPS_NS; +using namespace FixConst; +enum {NONE, LINEAR, CUBIC, TAITWATER}; + +/* ---------------------------------------------------------------------- */ + +FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (narg < 4) error->all(FLERR,"Illegal fix command"); + + pressure_style = NONE; + + comm_forward = 1; + nmax = atom->nmax; + + // Currently can only have one instance of fix rheo/pressure + if (igroup != 0) + error->all(FLERR,"fix rheo/pressure command requires group all"); + + int ntypes = atom->ntypes; + int iarg = 3; + if (strcmp(arg[iarg],"linear") == 0) { + pressure_style = LINEAR; + } else if (strcmp(arg[iarg],"taitwater") == 0) { + pressure_style = TAITWATER; + } else if (strcmp(arg[iarg],"cubic") == 0) { + pressure_style = CUBIC; + if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for pressure option"); + c_cubic = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + } else { + error->all(FLERR,"Illegal fix command, {}", arg[iarg]); + } + + if (pressure_style == NONE) + error->all(FLERR,"Must specify pressure style for fix/rheo/pressure"); +} + +/* ---------------------------------------------------------------------- */ + +FixRHEOPressure::~FixRHEOPressure() {} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOPressure::setmask() +{ + int mask = 0; + mask |= PRE_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOPressure::init() +{ + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/pressure"); + fix_rheo = dynamic_cast(fixes[0]); + + csq = fix_rheo->csq; + rho0 = fix_rheo->rho0; + rho0inv = 1.0 / rho0; + + // Cannot define multiple as pair rheo cannot currently distinguish + if (modify->get_fix_by_style("rheo/pressure").size() > 1) + error->all(FLERR,"Can only specify one instance of fix rheo/pressure"); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOPressure::setup_pre_force(int /*vflag*/) +{ + fix_rheo->pressure_fix_defined = 1; + + // Identify whether this is the first/last instance of fix pressure + // First will handle growing arrays + // Last will handle communication + first_flag = 0 + last_flag = 0; + + int i = 0; + auto fixlist = modify->get_fix_by_style("rheo/pressure"); + for (const auto &ifix : fixlist) { + if (strcmp(ifix->id, id) == 0) break; + i++; + } + + if (i == 0) first_flag = 1; + if ((i + 1) == fixlist.size()) last_flag = 1; + + pre_force(0); +} + +/* ---------------------------------------------------------------------- + Update (and forward) pressure every timestep +------------------------------------------------------------------------- */ + +void FixRHEOPressure::pre_force(int /*vflag*/) +{ + int i; + double dr, rr3, rho_ratio; + + double *p = fix_rheo->pressure; + int *mask = atom->mask; + double *rho = atom->rho; + + int nlocal = atom->nlocal; + int dim = domain->dimension; + + if (first_flag & nmax < atom->nmax) { + nmax = atom->nmax; + fix_rheo->fix_store_visc->grow_arrays(nmax); + } + + if (pressure_style == TAITWATER) inv7 = 1.0 / 7.0; + + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + if (pressure_style == LINEAR) { + p[i] = csq * (rho[i] - rho0); + } else if (pressure_style == CUBIC) { + dr = rho[i] - rho0; + p[i] = csq * (dr + c_cubic * dr * dr * dr); + } else if (pressure_style == TAITWATER) { + rho_ratio = rho[i] / rho0inv; + rr3 = rho_ratio * rho_ratio * rho_ratio; + p[i] = csq * rho0 * inv7 * (rr3 * rr3 * rho_ratio - 1.0); + } + } + } + + + if (last_flag && comm_forward) comm->forward_comm(this); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOPressure::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,k,m; + double *pressure = fix_rheo->pressure; + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = pressure[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOPressure::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double *pressure = fix_rheo->pressure; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + pressure[i] = buf[m++]; + } +} + +double FixRHEOPressure::calculate_p(double rho) +{ + double rho; + if (pressure_style == LINEAR) { + p = csq * (rho - rho0); + } else if (pressure_style == CUBIC) { + dr = rho - rho0; + p = csq * (dr + c_cubic * dr * dr * dr); + } else if (pressure_style == TAITWATER) { + rho_ratio = rho / rho0inv; + rr3 = rho_ratio * rho_ratio * rho_ratio; + p = csq * rho0 * inv7 * (rr3 * rr3 * rho_ratio - 1.0); + } + return rho; +} \ No newline at end of file diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h new file mode 100644 index 0000000000..45217c7f75 --- /dev/null +++ b/src/RHEO/fix_rheo_pressure.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS +// clang-format off +FixStyle(rheo/pressure,FixRHEOPressure) +// clang-format on +#else + +#ifndef LMP_FIX_RHEO_PRESSURE_H +#define LMP_FIX_RHEO_PRESSURE_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixRHEOPressure : public Fix { + public: + FixRHEOPressure(class LAMMPS *, int, char **); + ~FixRHEOPressure() override; + int setmask() override; + void init() override; + void setup_pre_force(int) override; + void pre_force(int) override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + double calculate_p(double); + private: + double c_cubic, csq, rho0, rho0inv; + int pressure_style; + int first_flag, last_flag; + int nmax; + class FixRHEO *fix_rheo; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 406439f93e..8f4094527e 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -230,7 +230,7 @@ void FixRHEOThermal::post_integrate() if (status[i] == FixRHEO::FLUID_NO_FORCE) continue; cvi = calc_cv(i); - temperature[i] += dtf*heat[i]/cvi; + temperature[i] += dtf * heat[i] / cvi; if (Tc_style != NONE) { Ti = temperature[i]; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index f57410783c..0774eff731 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -44,13 +44,13 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : int ntypes = atom->ntypes; int iarg = 3; if (strcmp(arg[iarg],"constant") == 0) { - if (iarg+1 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); + if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); viscosity_style = CONSTANT; eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); if (eta < 0.0) error->all(FLERR,"The viscosity must be positive"); iarg += 1; } else if (strcmp(arg[iarg],"type") == 0) { - if(iarg+ntypes >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); + if (iarg + ntypes >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); viscosity_style = TYPE; memory->create(eta_type, ntypes + 1, "rheo_thermal:eta_type"); for (int i = 1; i <= ntypes; i++) { @@ -59,7 +59,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : } iarg += ntypes; } else if (strcmp(arg[iarg],"power") == 0) { - if (iarg+4 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); + if (iarg + 4 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); viscosity_style = POWER; comm_forward = 1; eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 1bed3f1d3e..edb3bb313e 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -21,6 +21,7 @@ #include "domain.h" #include "error.h" #include "fix_rheo.h" +#include "fix_rheo_pressure.h" #include "force.h" #include "math_extra.h" #include "memory.h" @@ -41,7 +42,7 @@ using namespace MathExtra; PairRHEO::PairRHEO(LAMMPS *lmp) : Pair(lmp), compute_kernel(nullptr), compute_grad(nullptr), - compute_interface(nullptr), fix_rheo(nullptr) + compute_interface(nullptr), fix_rheo(nullptr), fix_rheo_pressure(nullptr) { restartinfo = 0; single_enable = 0; @@ -69,33 +70,15 @@ void PairRHEO::compute(int eflag, int vflag) int error_flag, pair_force_flag, pair_rho_flag, pair_avisc_flag; double xtmp, ytmp, ztmp; int fluidi, fluidj; - - int *ilist, *jlist, *numneigh, **firstneigh; - double imass, jmass, rsq, r, rinv; - + double imass, jmass, rsq, r, rinv, psi_ij, Fij; double w, wp, rhoi, rhoj, voli, volj, Pi, Pj; - double *dWij, *dWji, *d2Wij, *d2Wji, *dW1ij, *dW1ji; - double vijeij, etai, etaj, kappai, kappaj; - double Ti, Tj, dT; - double drho_damp, fmag; - double mu, q, fp_prefactor; - double dx[3] = {0}; - double fv[3] = {0}; - double dfp[3] = {0}; - double fsolid[3] = {0}; - double du[3] = {0}; - double vi[3] = {0}; - double vj[3] = {0}; - double dv[3] = {0}; - double psi_ij = 0.0; - double Fij = 0.0; + double *dWij, *dWji, *d2Wij, *d2Wji; + double Ti, Tj, dT, etai, etaj, kappai, kappaj; + double drho_damp, fmag, mu, q, fp_prefactor; + double dx[3], fv[3], dfp[3], fsolid[3], du[3], vi[3], vj[3]; ev_init(eflag, vflag); - double **gradv = compute_grad->gradv; - double **gradt = compute_grad->gradt; - double **gradr = compute_grad->gradr; - double **gradn = compute_grad->gradn; double **v = atom->v; double **x = atom->x; double **f = atom->f; @@ -104,16 +87,20 @@ void PairRHEO::compute(int eflag, int vflag) double *drho = atom->drho; double *temperature = atom->temperature; double *heatflow = atom->heatflow; + double **gradv = compute_grad->gradv; + double **gradt = compute_grad->gradt; + double **gradr = compute_grad->gradr; + double **gradn = compute_grad->gradn; double *chi = compute_interface->chi; double **f_pressure = fix_rheo->f_pressure; double *viscosity = fix_rheo->viscosity; double *conductivity = fix_rheo->conductivity; double *pressure = fix_rheo->pressure; - double *special_lj = force->special_lj; tagint *tag = atom->tag; int *type = atom->type; int *status = atom->status; + int *ilist, *jlist, *numneigh, **firstneigh; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; int dim = domain->dimension; @@ -142,7 +129,6 @@ void PairRHEO::compute(int eflag, int vflag) for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - factor_lj = special_lj[sbmask(j)]; j &= NEIGHMASK; dx[0] = xtmp - x[j][0]; @@ -152,7 +138,7 @@ void PairRHEO::compute(int eflag, int vflag) jtype = type[j]; jmass = mass[jtype]; - if (rsq < cutsq[itype][jtype]) { + if (rsq < hsq) { r = sqrt(rsq); rinv = 1 / r; @@ -181,7 +167,6 @@ void PairRHEO::compute(int eflag, int vflag) vj[a] = v[j][a]; } - // TODO: search for fix pressure and add calculate P function // Add corrections for walls rhoi = rho[i]; rhoj = rho[j]; @@ -191,14 +176,14 @@ void PairRHEO::compute(int eflag, int vflag) if (fluidi && (!fluidj)) { compute_interface->correct_v(v[i], v[j], vi, i, j); rhoj = compute_interface->correct_rho(j, i); - Pj = fix_pressure->calculate_P(rhoj); + Pj = fix_rheo_pressure->calculate_p(rhoj); if ((chi[j] > 0.9) && (r < (h * 0.5))) fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; } else if ((!fluidi) && fluidj) { compute_interface->correct_v(v[j], v[i], vj, j, i); rhoi = compute_interface->correct_rho(i,j); - Pi = fix_pressure->calculate_P(rhoi); + Pi = fix_rheo_pressure->calculate_p(rhoi); if ((chi[i] > 0.9) && (r < (h * 0.5))) fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; @@ -429,9 +414,13 @@ void PairRHEO::coeff(int narg, char **arg) void PairRHEO::setup() { auto fixes = modify->get_fix_by_style("rheo"); - if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use pair rheo"); fix_rheo = dynamic_cast(fixes[0]); + fixes = modify->get_fix_by_style("rheo/pressure"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo/pressure to use pair rheo"); + fix_rheo_pressure = dynamic_cast(fixes[0]); + compute_kernel = fix_rheo->compute_kernel; compute_grad = fix_rheo->compute_grad; compute_interface = fix_rheo->compute_interface; diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index 42172be3a4..ab7d796a74 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -50,6 +50,7 @@ class PairRHEO : public Pair { class ComputeRHEOGrad *compute_grad; class ComputeRHEOInterface *compute_interface; class FixRHEO *fix_rheo; + class FixRHEOPressure *fix_rheo_pressure; }; } // namespace LAMMPS_NS From bad1188c526672b2055caf6be5e01da1875c89b6 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 22 Mar 2023 17:27:51 -0600 Subject: [PATCH 011/385] Reorganizing peratom arrays --- src/RHEO/compute_rheo_grad.cpp | 160 ++++++++++++++++---------------- src/RHEO/compute_rheo_grad.h | 4 +- src/RHEO/fix_rheo.cpp | 2 +- src/RHEO/fix_rheo_thermal.cpp | 49 ++++++---- src/RHEO/fix_rheo_thermal.h | 2 +- src/RHEO/fix_rheo_viscosity.cpp | 44 ++++++--- src/RHEO/fix_rheo_viscosity.h | 6 +- src/RHEO/pair_rheo.cpp | 13 ++- 8 files changed, 162 insertions(+), 118 deletions(-) diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index e87d39aa53..f963485157 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -23,11 +23,9 @@ #include "force.h" #include "neighbor.h" #include "neigh_list.h" -#include "modify.h" #include "update.h" #include -#include using namespace LAMMPS_NS; enum{COMMGRAD, COMMFIELD}; @@ -35,11 +33,11 @@ enum{COMMGRAD, COMMFIELD}; /* ---------------------------------------------------------------------- */ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), compute_interface(nullptr), compute_kernel(nullptr) + Compute(lmp, narg, arg), compute_interface(nullptr), compute_kernel(nullptr), + gradv(nullptr), gradr(nullptr), gradt(nullptr), gradn(nullptr) { if (narg < 4) error->all(FLERR,"Illegal compute rheo/grad command"); - velocity_flag = temperature_flag = rho_flag = eta_flag = 0; for (int iarg = 3; iarg < narg; iarg ++) { if (strcmp(arg[iarg],"velocity") == 0) velocity_flag = 1; @@ -53,70 +51,62 @@ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : ncomm_field = 0; comm_reverse = 0; - std::string fix_cmd = "rheo_grad_property_atom all property/atom" - int dim = domain->dimension; if (velocity_flag) { ncomm_grad += dim * dim; ncomm_field += dim; comm_reverse += dim * dim; - fix_cmd += " d2_gradv 9" + indexv = atom->add_custom("rheo_grad_v", 1, dim * dim); + gradv = atom->darray[indexv]; } if (rho_flag) { ncomm_grad += dim; ncomm_field += 1; comm_reverse += dim; - fix_cmd += " d2_gradr 3" + indexr = atom->add_custom("rheo_grad_rho", 1, dim); + gradr = atom->darray[indexr]; } if (temperature_flag) { ncomm_grad += dim; ncomm_field += 1; comm_reverse += dim; - fix_cmd += " d2_gradt 3" + indext= atom->add_custom("rheo_grad_temp", 1, dim); + gradt = atom->darray[indext]; } if (eta_flag) { ncomm_grad += dim; comm_reverse += dim; - fix_cmd += " d2_gradn 3" + indexn = atom->add_custom("rheo_grad_eta", 1, dim); + gradn = atom->darray[indexn]; } + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded + comm_forward = ncomm_grad; - - modify->add_fix(fix_cmd); - - int tmp1, tmp2, index; - if (velocity_flag) { - index = atom->find_custom("gradv", tmp1, tmp2); - gradv = atom->darray[index]; - } - - if (rho_flag) { - index = atom->find_custom("gradr", tmp1, tmp2); - gradr = atom->darray[index]; - } - - if (temperature_flag) { - index = atom->find_custom("gradt", tmp1, tmp2); - gradt = atom->darray[index]; - } - - if (eta_flag) { - index = atom->find_custom("gradn", tmp1, tmp2); - gradn = atom->darray[index]; - } + nmax_old = 0; + grow_arrays(atom->nmax); } /* ---------------------------------------------------------------------- */ ComputeRHEOGrad::~ComputeRHEOGrad() { - modify->delete_fix("rheo_grad_property_atom"); + int dim = domain->dimension; + if (velocity_flag) + atom->remove_custom(indexv, 1, dim * dim); + if (rho_flag) + atom->remove_custom(indexr, 1, dim); + if (temperature_flag) + atom->remove_custom(indext, 1, dim); + if (eta_flag) + atom->remove_custom(indexn, 1, dim); } - /* ---------------------------------------------------------------------- */ void ComputeRHEOGrad::init() @@ -169,6 +159,8 @@ void ComputeRHEOGrad::compute_peratom() firstneigh = list->firstneigh; // initialize arrays + if (nmax > nmax_old) grow_arrays(nmax); + for (i = 0; i < nmax; i++) { if (velocity_flag) { for (k = 0; k < dim * dim; k++) @@ -315,39 +307,33 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, j = list[i]; if (comm_stage == COMMGRAD) { - if (velocity_flag){ + if (velocity_flag) for (k = 0; k < dim * dim; k++) buf[m++] = gradv[j][k]; - } - if (rho_flag) { + if (rho_flag) for (k = 0; k < dim; k++) buf[m++] = gradr[j][k]; - } - if (temperature_flag) { + if (temperature_flag) for (k = 0; k < dim; k++) buf[m++] = gradt[j][k]; - } - if (eta_flag){ + if (eta_flag) for (k = 0; k < dim; k++) buf[m++] = gradn[j][k]; - } + } else if (comm_stage == COMMFIELD) { - if (velocity_flag) { + if (velocity_flag) for (k = 0; k < dim; k++) buf[m++] = v[j][k]; - } - if (rho_flag) { + if (rho_flag) buf[m++] = rho[j]; - } - if (temperature_flag) { + if (temperature_flag) buf[m++] = temperature[j]; - } } } return m; @@ -367,33 +353,32 @@ void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) last = first + n; for (i = first; i < last; i++) { if (comm_stage == COMMGRAD) { - if (velocity_flag) { + if (velocity_flag) for (k = 0; k < dim * dim; k++) gradv[i][k] = buf[m++]; - } - if (rho_flag) { + + if (rho_flag) for (k = 0; k < dim; k++) gradr[i][k] = buf[m++]; - } - if (temperature_flag) { + + if (temperature_flag) for (k = 0; k < dim; k++) gradt[i][k] = buf[m++]; - } - if (eta_flag) { + + if (eta_flag) for (k = 0; k < dim; k++) gradn[i][k] = buf[m++]; - } + } else if (comm_stage == COMMFIELD) { - if (velocity_flag) { + if (velocity_flag) for (k = 0; k < dim; k++) v[i][k] = buf[m++]; - } - if (rho_flag) { + + if (rho_flag) rho[i] = buf[m++]; - } - if (temperature_flag) { + + if (temperature_flag) temperature[i] = buf[m++]; - } } } } @@ -408,22 +393,21 @@ int ComputeRHEOGrad::pack_reverse_comm(int n, int first, double *buf) m = 0; last = first + n; for (i = first; i < last; i++) { - if (velocity_flag) { + if (velocity_flag) for (k = 0; k < dim * dim; k++) buf[m++] = gradv[i][k]; - } - if (rho_flag) { + + if (rho_flag) for (k = 0; k < dim; k++) buf[m++] = gradr[i][k]; - } - if (temperature_flag) { + + if (temperature_flag) for (k = 0; k < dim; k++) buf[m++] = gradt[i][k]; - } - if (eta_flag) { + + if (eta_flag) for (k = 0; k < dim; k++) buf[m++] = gradn[i][k]; - } } return m; } @@ -438,21 +422,39 @@ void ComputeRHEOGrad::unpack_reverse_comm(int n, int *list, double *buf) m = 0; for (i = 0; i < n; i++) { j = list[i]; - if (velocity_flag) { + if (velocity_flag) for (k = 0; k < dim * dim; k++) gradv[j][k] += buf[m++]; - } - if (rho_flag) { + + if (rho_flag) for (k = 0; k < dim; k++) gradr[j][k] += buf[m++]; - } - if (temperature_flag) { + + if (temperature_flag) for (k = 0; k < dim; k++) gradt[j][k] += buf[m++]; - } - if (eta_flag) { + + if (eta_flag) for (k = 0; k < dim; k++) gradn[j][k] += buf[m++]; - } } } + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOGrad::grow_arrays(int nmax) +{ + int dim = domain->dimension; + if (velocity_flag) + memory->grow(gradv, nmax, dim * dim, "atom:rheo_grad_v"); + + if (rho_flag) + memory->grow(gradr, nmax, dim, "atom:rheo_grad_rho"); + + if (temperature_flag) + memory->grow(gradt, nmax, dim, "atom:rheo_grad_temp"); + + if (eta_flag) + memory->grow(gradn, nmax, dim, "atom:rheo_grad_eta"); + nmax_old = nmax; +} \ No newline at end of file diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 52c5d7c924..220b5813e3 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -44,8 +44,8 @@ class ComputeRHEOGrad : public Compute { int stage; private: - int comm_stage; - int ncomm_grad, ncomm_field; + int comm_stage, ncomm_grad, ncomm_field, nmax_old; + int indexv, indexr, indext, indexn; double cut, cutsq, rho0; class NeighList *list; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index e2819ad320..d142af6483 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -313,7 +313,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) // Shifting atoms if (shift_flag) { - compute_vshift->correct_surfaces(); + compute_vshift->correct_surfaces(); // COuld this be moved to preforce after the surface fix runs? for (i = 0; i < nlocal; i++) { if (!(status[i] & STATUS_SHIFT)) continue; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 406439f93e..f000bf65cc 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -32,7 +32,8 @@ enum {NONE, CONSTANT, TYPE}; /* ---------------------------------------------------------------------- */ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr) + Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), + conductivity(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -40,8 +41,8 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : cv_style = NONE; conductivity_style = NONE; - comm_forward = 0; - nmax = atom->nmax; + comm_forward = 1; + nmax_old = 0; int ntypes = atom->ntypes; int iarg = 3; @@ -123,6 +124,11 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : FixRHEOThermal::~FixRHEOThermal() { + // Remove custom property if it exists + int tmp1, tmp2, index; + index = atom->find_custom("rheo_conductivity", tmp1, tmp2); + if (index != -1) atom->remove_custom(index_cond, 1, 0); + memory->destroy(cv_type); memory->destroy(Tc_type); memory->destroy(kappa_type); @@ -164,8 +170,7 @@ void FixRHEOThermal::setup_pre_force(int /*vflag*/) fix_rheo->thermal_fix_defined = 1; // Identify whether this is the first/last instance of fix thermal - // First will handle growing arrays - // Last will handle communication + // First will grow arrays, last will communicate first_flag = 0 last_flag = 0; @@ -179,6 +184,18 @@ void FixRHEOThermal::setup_pre_force(int /*vflag*/) if (i == 0) first_flag = 1; if ((i + 1) == fixlist.size()) last_flag = 1; + // Create conductivity array if it doesn't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded + + int tmp1, tmp2; + index_cond = atom->find_custom("rheo_conductivity", tmp1, tmp2); + if (index_cond == -1) { + index_cond = atom->add_custom("rheo_conductivity", 1, 0); + nmax_old = atom->nmax; + } + post_neighbor(); pre_force(0); } @@ -230,7 +247,7 @@ void FixRHEOThermal::post_integrate() if (status[i] == FixRHEO::FLUID_NO_FORCE) continue; cvi = calc_cv(i); - temperature[i] += dtf*heat[i]/cvi; + temperature[i] += dtf * heat[i] / cvi; if (Tc_style != NONE) { Ti = temperature[i]; @@ -260,15 +277,14 @@ void FixRHEOThermal::post_neighbor() { int i; int *type = atom->type; - double *conductivity = fix_rheo->conductivity; + double *conductivity = atom->dvector[index_cond]; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (first_flag & nmax < atom->nmax) { - nmax = atom->nmax; - fix_rheo->fix_store_cond->grow_arrays(nmax); - } + if (first_flag && (nmax_old < atom->nmax)) + memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); + nmax_old = atom->nmax; if (conductivity_style == CONSTANT) { for (i = 0; i < nall; i++) @@ -286,16 +302,15 @@ void FixRHEOThermal::post_neighbor() void FixRHEOThermal::pre_force(int /*vflag*/) { - // So far, none exist + // Not needed yet, when needed add (un)pack_forward_comm() methods //int i; - //double *conductivity = fix_rheo->conductivity; + //double *conductivity = atom->dvector[index_cond]; //int *mask = atom->mask; //int nlocal = atom->nlocal; - //if (first_flag & nmax < atom->nmax) { - // nmax = atom->nmax; - // fix_rheo->fix_store_cond->grow_arrays(nmax); - //} + //if (first_flag && (nmax_old < atom->nmax)) + // memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); + //nmax_old = atom->nmax; //if (conductivity_style == TBD) { // for (i = 0; i < nlocal; i++) { diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index c0b5255caa..e4ed426fb4 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -49,7 +49,7 @@ class FixRHEOThermal : public Fix { int cv_style; int conductivity_style; int first_flag, last_flag; - int nmax; + int nmax_old, index_cond; class FixRHEO *fix_rheo; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index f57410783c..3dfbfc1058 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -39,7 +39,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : viscosity_style = NONE; comm_forward = 0; - nmax = atom->nmax; + nmax_old = 0; int ntypes = atom->ntypes; int iarg = 3; @@ -81,6 +81,11 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : FixRHEOViscosity::~FixRHEOViscosity() { + // Remove custom property if it exists + int tmp1, tmp2, index; + index = atom->find_custom("rheo_viscosity", tmp1, tmp2); + if (index != -1) atom->remove_custom(index_visc, 1, 0); + memory->destroy(eta_type); } @@ -112,8 +117,7 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) fix_rheo->viscosity_fix_defined = 1; // Identify whether this is the first/last instance of fix viscosity - // First will handle growing arrays - // Last will handle communication + // First will grow arrays, last will communicate first_flag = 0 last_flag = 0; @@ -127,6 +131,18 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) if (i == 0) first_flag = 1; if ((i + 1) == fixlist.size()) last_flag = 1; + // Create viscosity array if it doesn't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded + + int tmp1, tmp2; + index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); + if (index_cond == -1) { + index_visc = atom->add_custom("rheo_viscosity", 1, 0); + nmax_old = atom->nmax; + } + post_neighbor(); pre_force(0); } @@ -140,16 +156,15 @@ void FixRHEOViscosity::post_neighbor() int i; int *type = atom->type; - double *viscosity = fix_rheo->viscosity; + double *viscosity = atom->dvector[index_visc]; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (first_flag & nmax < atom->nmax) { - nmax = atom->nmax; - fix_rheo->fix_store_visc->grow_arrays(nmax); - } + if (first_flag && (nmax_old < atom->nmax)) + memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); + nmax_old = atom->nmax; if (viscosity_style == CONSTANT) { for (i = 0; i < nall; i++) @@ -170,17 +185,16 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) int i, a, b; double tmp, gdot; - double *viscosity = fix_rheo->viscosity; + double *viscosity = atom->dvector[index_visc]; int *mask = atom->mask; double **gradv = compute_grad->gradv; int nlocal = atom->nlocal; int dim = domain->dimension; - if (first_flag & nmax < atom->nmax) { - nmax = atom->nmax; - fix_rheo->fix_store_visc->grow_arrays(nmax); - } + if (first_flag && (nmax_old < atom->nmax)) + memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); + nmax_old = atom->nmax; if (viscosity_style == POWER) { for (i = 0; i < nlocal; i++) { @@ -213,7 +227,7 @@ int FixRHEOViscosity::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,k,m; - double *viscosity = fix_rheo->viscosity; + double *viscosity = atom->dvector[index_visc]; m = 0; for (i = 0; i < n; i++) { @@ -228,7 +242,7 @@ int FixRHEOViscosity::pack_forward_comm(int n, int *list, double *buf, void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; - double *viscosity = fix_rheo->viscosity; + double *viscosity = atom->dvector[index_visc]; m = 0; last = first + n; diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index 31c1441e40..d531507a72 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -35,12 +35,14 @@ class FixRHEOViscosity : public Fix { void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; + private: double *eta_type, eta; - double npow, K, gd0, tau0; + double npow, K, gd0, tau0; int viscosity_style; int first_flag, last_flag; - int nmax; + int nmax_old, index_visc; + class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; }; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index c796db208a..fd4e525b34 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -92,7 +92,6 @@ void PairRHEO::compute(int eflag, int vflag) double **gradv = compute_grad->gradv; double **gradt = compute_grad->gradt; double **gradr = compute_grad->gradr; - double **gradn = compute_grad->gradn; double **v = atom->v; double **x = atom->x; double **f = atom->f; @@ -109,6 +108,18 @@ void PairRHEO::compute(int eflag, int vflag) int *type = atom->type; int *phase = atom->phase; + int tmp1, tmp2; + int index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); + if (index_visc == -1) error->all(FLERR, "Cannot find rheo viscosity"); + double *viscosity = atom->dvector[index_visc]; + + double *conductivity; + if (thermal_flag) { + int index_cond = atom->find_custom("rheo_conductivity", tmp1, tmp2); + if (index_cond == -1) error->all(FLERR, "Cannot find rheo conductivity"); + conductivity = atom->dvector[index_cond]; + } + int nlocal = atom->nlocal; int newton_pair = force->newton_pair; int dim = domain->dimension; From 886c642e0155e97bf51d81475978ddcf74526a87 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 22 Mar 2023 21:15:54 -0600 Subject: [PATCH 012/385] Cleaning up pairstyle --- src/RHEO/pair_rheo.cpp | 291 +++++++++++++++++------------------------ src/RHEO/pair_rheo.h | 2 +- 2 files changed, 119 insertions(+), 174 deletions(-) diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index fd4e525b34..06913e45e6 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -22,6 +22,7 @@ #include "error.h" #include "fix_rheo.h" #include "force.h" +#include "math_extra.h" #include "memory.h" #include "modify.h" #include "neighbor.h" @@ -32,6 +33,7 @@ #include using namespace LAMMPS_NS; +using namespace MathExtra; #define EPSILON 1e-2 @@ -64,28 +66,15 @@ PairRHEO::~PairRHEO() void PairRHEO::compute(int eflag, int vflag) { int i, j, a, b, ii, jj, inum, jnum, itype, jtype; - int error_flag, pair_force_flag, pair_rho_flag, pair_avisc_flag; - double xtmp, ytmp, ztmp; + int pair_force_flag, pair_rho_flag, pair_avisc_flag; + double xtmp, ytmp, ztmp, w, wp, Ti, Tj, dT; + double rhoi, rhoj, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj; + double mu, q, fp_prefactor, drho_damp, fmag, psi_ij, Fij; + double *dWij, *dWji, *dW1ij, *dW1ji; + double dx[3], du[3], fv[3], dfp[3], fsolid[3], ft[3], vi[3], vj[3]; int *ilist, *jlist, *numneigh, **firstneigh; - double imass, jmass, rsq, r, ir; - - double w, wp, rhoi, rhoj, voli, volj, Pi, Pj; - double *dWij, *dWji, *d2Wij, *d2Wji, *dW1ij, *dW1ji; - double vijeij, etai, etaj, kappai, kappaj; - double Ti, Tj, dT; - double drho_damp, fmag; - double mu, q, cs, fp_prefactor; - double dx[3] = {0}; - double fv[3] = {0}; - double dfp[3] = {0}; - double fsolid[3] = {0}; - double du[3] = {0}; - double vi[3] = {0}; - double vj[3] = {0}; - double dv[3] = {0}; - double psi_ij = 0.0; - double Fij = 0.0; + double imass, jmass, rsq, r, rinv; ev_init(eflag, vflag); @@ -95,18 +84,17 @@ void PairRHEO::compute(int eflag, int vflag) double **v = atom->v; double **x = atom->x; double **f = atom->f; - double **fp = atom->fp; + double **fp = atom->fp; // rewrite later + double *pressure = atom->pressure; // rewrite later double *rho = atom->rho; double *mass = atom->mass; double *drho = atom->drho; double *temp = atom->temp; double *heat = atom->heat; - double *viscosity = atom->viscosity; - double *conductivity = atom->conductivity; double *special_lj = force->special_lj; tagint *tag = atom->tag; int *type = atom->type; - int *phase = atom->phase; + int *status = atom->status; int tmp1, tmp2; int index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); @@ -140,10 +128,11 @@ void PairRHEO::compute(int eflag, int vflag) jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; - - kappai = conductivity[i]; etai = viscosity[i]; - Ti = temp[i]; + if (thermal_flag) { + kappai = conductivity[i]; + Ti = temp[i]; + } for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -153,25 +142,27 @@ void PairRHEO::compute(int eflag, int vflag) dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; + rsq = lensq3(dx); jtype = type[j]; - jmass = mass[jtype]; if (rsq < cutsq[itype][jtype]) { r = sqrt(rsq); - ir = 1/r; + rinv = 1 / r; - kappaj = conductivity[j]; + jmass = mass[jtype]; etaj = viscosity[j]; - Tj = temp[j]; + if (thermal_flag) { + Tj = temp[j]; + kappaj = conductivity[j]; + } pair_rho_flag = 0; pair_force_flag = 0; pair_avisc_flag = 0; - if (phase[i] <= FixRHEO::FLUID_MAX || phase[j] <= FixRHEO::FLUID_MAX) { + if (status[i] <= FixRHEO::FLUID_MAX || status[j] <= FixRHEO::FLUID_MAX) { pair_force_flag = 1; } - if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { + if (status[i] <= FixRHEO::FLUID_MAX && status[j] <= FixRHEO::FLUID_MAX) { pair_avisc_flag = 1; pair_rho_flag = 1; } @@ -189,31 +180,31 @@ void PairRHEO::compute(int eflag, int vflag) // Add corrections for walls rhoi = rho[i]; rhoj = rho[j]; - if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { - compute_sinterpolation->correct_v(v[i], v[j], vi, i, j); - rhoj = compute_sinterpolation->correct_rho(j,i); + Pi = pressure[i]; + Pj = pressure[j]; + if ((status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { + compute_interface->correct_v(vi, vj, i, j); + rhoj = compute_interface->correct_rho(j, i); + Pj = calc_pressure(rhoj, jtype); // Repel if close to inner solid particle - if (compute_sinterpolation->chi[j] > 0.9 && r < (cut[itype][jtype] * 0.5)) { - fmag = (compute_sinterpolation->chi[j] - 0.9) * (cut[itype][jtype] * 0.5 - r); - fmag *= rho0[itype] * csq[itype] * cut[itype][jtype] * ir; - fsolid[0] = fmag * dx[0]; - fsolid[1] = fmag * dx[1]; - fsolid[2] = fmag * dx[2]; + if (compute_interface->chi[j] > 0.9 && r < (h * 0.5)) { + fmag = (compute_interface->chi[j] - 0.9) * (h * 0.5 - r); + fmag *= rho0 * csq * h * ir; + scale3(fmag, dx, fsolid); } - } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { - compute_sinterpolation->correct_v(v[j], v[i], vj, j, i); - rhoi = compute_sinterpolation->correct_rho(i,j); + } else if (!(status[i] & STATUS_FLUID) && (status[j] & STATUS_FLUID)) { + compute_interface->correct_v(vj, vi, j, i); + rhoi = compute_interface->correct_rho(i, j); + Pi = calc_pressure(rhoi, itype); // Repel if close to inner solid particle - if (compute_sinterpolation->chi[i] > 0.9 && r < (cut[itype][jtype] * 0.5)) { - fmag = (compute_sinterpolation->chi[i] - 0.9) * (cut[itype][jtype] * 0.5 - r); - fmag *= rho0[jtype] * csq[jtype] * cut[itype][jtype] * ir; - fsolid[0] = fmag * dx[0]; - fsolid[1] = fmag * dx[1]; - fsolid[2] = fmag * dx[2]; + if (compute_interface->chi[i] > 0.9 && r < (h * 0.5)) { + fmag = (compute_interface->chi[i] - 0.9) * (h * 0.5 - r); + fmag *= rho0 * csq * h * ir; + scale3(fmag, dx, fsolid); } - } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { + } else if (!(status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { rhoi = 1.0; rhoj = 1.0; } @@ -221,26 +212,19 @@ void PairRHEO::compute(int eflag, int vflag) // Compute volume and pressure after reconstructing voli = imass / rhoi; volj = jmass / rhoj; - Pj = calc_pressure(rhoj, jtype); - Pi = calc_pressure(rhoi, itype); - - //Check if Second order kernels will be used for eta*Lap(v) - error_flag = 0; - if (laplacian_order == 2) { - error_flag = compute_kernel->calc_d2w(i, j, dx[0], dx[1], dx[2], r); - d2Wij = compute_kernel->d2Wij; - d2Wji = compute_kernel->d2Wji; - } //Thermal Evolution if (thermal_flag) { - dT = 0.0; - for (a = 0; a < dim; a++) { - dT += (kappai + kappaj) * (Ti-Tj) * dx[a] * dWij[a] * ir * ir; - //Assumes heat capacity and density = 1, needs to be generalized - } - dT *= voli * volj; + dT = dot3(dx, dWij); + dT *= (kappai + kappaj) * (Ti - Tj) * rinv * rinv * voli * volj; + //Assumes heat capacity and density = 1, needs to be generalized heat[i] += dT; + + if (newton_pair || j < nlocal) { + dT = dot3(dx, dWji); + dT *= (kappai + kappaj) * (Tj - Ti) * rinv * rinv * voli * volj; + heat[j] -= dT; + } } // If either particle is fluid, compute hydrostatic and viscous forces @@ -248,133 +232,94 @@ void PairRHEO::compute(int eflag, int vflag) if (pair_force_flag) { //Hydrostatic pressure forces fp_prefactor = voli * volj * (Pj + Pi); + sub3(v1, vj, du); //Add artificial viscous pressure if required if (artificial_visc_flag && pair_avisc_flag){ //Interpolate velocities to midpoint and use this difference for artificial viscosity - for (a = 0; a < dim; a++) { - du[a] = vi[a] - vj[a]; - for (b = 0; b < dim; b++) { + for (a = 0; a < dim; a++) + for (b = 0; b < dim; b++) du[a] -= 0.5 * (gradv[i][a * dim + b] + gradv[j][a * dim + b]) * dx[b]; - } - } - mu = (du[0] * dx[0] + du[1] * dx[1]+ du[2] * dx[2]) * hinv3; + + mu = dot3(du, dx) * hinv3; mu = mu / (rsq * hinv3 * hinv3 + EPSILON); - mu= MIN(0.0, mu); - cs = 0.5 * (sqrt(csq[itype]) + sqrt(csq[jtype])); - // "kinematic viscous pressure" q = Q/rho - q = av*(-2.0*cs*mu + 1.0*mu*mu); - fp_prefactor += voli*volj*q*(rhoj + rhoi); + mu = MIN(0.0, mu); + q = av * (-2.0 * cs * mu + mu * mu); + fp_prefactor += voli * volj * q * (rhoj + rhoi); } // -Grad[P + Q] - dfp[0] = - fp_prefactor*dWij[0]; - dfp[1] = - fp_prefactor*dWij[1]; - dfp[2] = - fp_prefactor*dWij[2]; + scale3(-fp_prefactor, dWij, dfp); // Now compute viscous eta*Lap[v] terms - for (a = 0; a < dim; a ++) { + for (a = 0; a < dim; a++) { fv[a] = 0.0; - for (b = 0; b < dim; b++) { - fv[a] += (etai+etaj)*(vi[a]-vj[a])*dx[b]*dWij[b]*ir*ir; - } - fv[a] *= voli*volj; + for (b = 0; b < dim; b++) + fv[a] += du[a] * dx[b] * dWij[b]; + fv[a] *= (etai + etaj) * voli * volj * rinv * rinv; } - } else { - for (a = 0; a < dim; a ++) { - fv[a] = 0; - dfp[a] = 0; - } - } + add3(fv, dfp, ft); + add3(fsolid, ft, ft); - if (pair_force_flag) { - f[i][0] += fv[0] + dfp[0] + fsolid[0]; - f[i][1] += fv[1] + dfp[1] + fsolid[1]; - f[i][2] += fv[2] + dfp[2] + fsolid[2]; + f[i][0] += ft[0]; + f[i][1] += ft[1]; + f[i][2] += ft[2]; fp[i][0] += dfp[0]; fp[i][1] += dfp[1]; fp[i][2] += dfp[2]; - } - // Density damping - // conventional for low-order h - // interpolated for RK 1 & 2 (Antuono et al, Computers & Fluids 2021) - if (rho_damp_flag && pair_rho_flag) { - if (laplacian_order>=1 && error_flag == 0){ - psi_ij = rhoj-rhoi; - Fij = 0.0; - for (a = 0; a < dim; a++){ - psi_ij += 0.5*(gradr[i][a]+gradr[j][a])*dx[a]; - Fij -= dx[a]*dWij[a]; + if (newton_pair || j < nlocal) { + for (a = 0; a < dim; a ++) { + fv[a] = 0.0; + for (b = 0; b < dim; b++) + fv[a] += (vi[a] - vj[a]) * dx[b] * dWji[b]; + fv[a] *= -(etai + etaj) * voli * volj * rinv * rinv; + // flip sign here b/c -= at accummulator } - Fij *= ir*ir; - drho[i] += 2*rho_damp*psi_ij*Fij*volj; - } - else { - drho_damp = 2*rho_damp*(rhoj-rhoi)*ir*wp; - drho[i] -= drho_damp*volj; - } - } - if (evflag) // Doesn't account for unbalanced forces - ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, fv[0]+dfp[0], fv[1]+dfp[1], fv[2]+dfp[2], dx[0], dx[1], dx[2]); + scale3(fp_prefact,r dWji, dfp); - // Newton neighbors - if (newton_pair || j < nlocal) { + add3(fv, dfp, ft); + add3(fsolid, ft, ft); - if (thermal_flag) { - dT = 0.0; - for(a = 0; a < dim; a++){ - //dT += kappai*dWji[a]*gradt[i][a]; - //dT -= kappaj*dWji[a]*gradt[j][a]; - dT += 1/1*(kappai+kappaj)*(Ti-Tj)*dx[a]*dWji[a]*ir*ir; //Assumes heat capacity and density = 1, needs to be generalized - } - dT *= -voli*volj; - heat[j] -= dT; - } - - for (a = 0; a < dim; a ++) { - fv[a] = 0.0; - for (b = 0; b < dim; b++) { - //fv[a] += etai*dWji[b]*(gradv[i][a*dim+b]+gradv[i][b*dim+a]); - //fv[a] -= etaj*dWji[b]*(gradv[j][a*dim+b]+gradv[j][b*dim+a]); - fv[a] += (etai+etaj)*(vi[a]-vj[a])*dx[b]*dWji[b]*ir*ir; - } - fv[a] *= -voli*volj; // flip sign here b/c -= at accummulator - } - - - - if (pair_force_flag) { - for (a = 0; a < dim; a++) - dfp[a] = fp_prefactor*dWji[a]; - } - - if (rho_damp_flag && pair_rho_flag){ - if (laplacian_order>=1 && error_flag == 0){ - Fij = 0.0; - for (a = 0; a < dim; a++){ - Fij += dx[a]*dWji[a]; - } - Fij *= ir*ir; - psi_ij *= -1; - drho[j] += 2*rho_damp*psi_ij*Fij*voli; - } - else { - drho_damp = 2*rho_damp*(rhoj-rhoi)*ir*wp; - drho[j] += drho_damp*voli; - } - } - if (pair_force_flag) { - f[j][0] -= fv[0] + dfp[0] + fsolid[0]; - f[j][1] -= fv[1] + dfp[1] + fsolid[1]; - f[j][2] -= fv[2] + dfp[2] + fsolid[2]; + f[j][0] -= ft[0]; + f[j][1] -= ft[1]; + f[j][2] -= ft[2]; fp[j][0] -= dfp[0]; fp[j][1] -= dfp[1]; fp[j][2] -= dfp[2]; } + + if (evflag) // Doesn't account for unbalanced forces + ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); + } + + // Density damping + // conventional for low-order h + // interpolated for RK 1 & 2 (Antuono et al., Computers & Fluids 2021) + if (rho_damp_flag && pair_rho_flag) { + if (laplacian_order >= 1) { + psi_ij = rhoj - rhoi; + Fij = -rinv * rinv * dot3(dx, dWij); + for (a = 0; a < dim; a++) + psi_ij += 0.5 * (gradr[i][a] + gradr[j][a]) * dx[a]; + drho[i] += 2 * rho_damp * psi_ij * Fij * volj; + } else { + drho_damp = 2 * rho_damp * (rhoj - rhoi) * rinv * wp; + drho[i] -= drho_damp * volj; + } + + if (newton_pair || j < nlocal) { + if (laplacian_order >= 1) { + Fij = rinv * rinv * dot3(dx, dWji); + psi_ij *= -1; + drho[j] += 2 * rho_damp * psi_ij * Fij * voli; + } else { + drho[j] += drho_damp * voli; + } + } } } } @@ -411,15 +356,13 @@ void PairRHEO::settings(int narg, char **arg) while (iarg < narg) { if (strcmp(arg[iarg], "rho/damp") == 0) { if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_style command"); - rho_damp_flag = 1; rho_damp = utils::numeric(FLERR,arg[iarg + 1],false,lmp); iarg++; } else if (strcmp(arg[iarg], "artificial/visc") == 0) { if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_style command"); - artificial_visc_flag = 1; - av = utils::numeric(FLERR,arg[iarg+1],false,lmp); + av = utils::numeric(FLERR,arg[iarg + 1],false,lmp); iarg++; } else error->all(FLERR,"Illegal pair_style command, {}", arg[iarg]); iarg++; @@ -438,8 +381,8 @@ void PairRHEO::coeff(int narg, char **arg) allocate(); int ilo, ihi, jlo, jhi; - utils::bounds(FLERR,arg[0],1, atom->ntypes, ilo, ihi,error); - utils::bounds(FLERR,arg[1],1, atom->ntypes, jlo, jhi,error); + utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); + utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); int count = 0; for (int i = ilo; i <= ihi; i++) { @@ -472,6 +415,8 @@ void PairRHEO::setup() rho0 = fix_rheo->rho0; hinv = 1.0 / h; + hinv3 = hinv * 3.0; + cs = sqrt(csq); laplacian_order = -1; if (comm->ghost_velocity == 0) diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index 026bc16527..18458048f6 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -37,7 +37,7 @@ class PairRHEO : public Pair { protected: double h, csq, rho0; // From fix RHEO - double hsq, hinv, av, rho_damp; + double cs, hsq, hinv, hinv3, av, rho_damp; int laplacian_order; int artificial_visc_flag; From beb6f934f8e34a4a5bd55ff057500f095009245d Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 22 Mar 2023 21:44:11 -0600 Subject: [PATCH 013/385] adding new peratom storage to pressure --- src/RHEO/fix_rheo_pressure.cpp | 52 ++++++++++++++++----------------- src/RHEO/fix_rheo_pressure.h | 3 +- src/RHEO/fix_rheo_viscosity.cpp | 2 +- src/RHEO/pair_rheo.cpp | 9 +++--- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 8f42e22239..e4c1c44163 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -38,7 +38,7 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : pressure_style = NONE; comm_forward = 1; - nmax = atom->nmax; + nmax_old = 0; // Currently can only have one instance of fix rheo/pressure if (igroup != 0) @@ -64,7 +64,13 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : /* ---------------------------------------------------------------------- */ -FixRHEOPressure::~FixRHEOPressure() {} +FixRHEOPressure::~FixRHEOPressure() +{ + // Remove custom property if it exists + int tmp1, tmp2, index; + index = atom->find_custom("rheo_pressure", tmp1, tmp2); + if (index != -1) atom->remove_custom(index_pres, 1, 0); +} /* ---------------------------------------------------------------------- */ @@ -98,22 +104,18 @@ void FixRHEOPressure::setup_pre_force(int /*vflag*/) { fix_rheo->pressure_fix_defined = 1; - // Identify whether this is the first/last instance of fix pressure - // First will handle growing arrays - // Last will handle communication - first_flag = 0 - last_flag = 0; + // Create pressure array if it doesn't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded - int i = 0; - auto fixlist = modify->get_fix_by_style("rheo/pressure"); - for (const auto &ifix : fixlist) { - if (strcmp(ifix->id, id) == 0) break; - i++; + int tmp1, tmp2; + index_pres = atom->find_custom("rheo_pressure", tmp1, tmp2); + if (index_pres == -1) { + index_pres = atom->add_custom("rheo_pressure", 1, 0); + nmax_old = atom->nmax; } - if (i == 0) first_flag = 1; - if ((i + 1) == fixlist.size()) last_flag = 1; - pre_force(0); } @@ -126,16 +128,15 @@ void FixRHEOPressure::pre_force(int /*vflag*/) int i; double dr, rr3, rho_ratio; - double *p = fix_rheo->pressure; + double *pressure = atom->dvector[index_pres]; int *mask = atom->mask; double *rho = atom->rho; int nlocal = atom->nlocal; - int dim = domain->dimension; - if (first_flag & nmax < atom->nmax) { - nmax = atom->nmax; - fix_rheo->fix_store_visc->grow_arrays(nmax); + if (nmax_old < atom->nmax) { + memory->grow(pressure, atom->nmax, "atom:rheo_pressure"); + nmax_old = atom->nmax; } if (pressure_style == TAITWATER) inv7 = 1.0 / 7.0; @@ -143,19 +144,18 @@ void FixRHEOPressure::pre_force(int /*vflag*/) for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (pressure_style == LINEAR) { - p[i] = csq * (rho[i] - rho0); + pressure[i] = csq * (rho[i] - rho0); } else if (pressure_style == CUBIC) { dr = rho[i] - rho0; - p[i] = csq * (dr + c_cubic * dr * dr * dr); + pressure[i] = csq * (dr + c_cubic * dr * dr * dr); } else if (pressure_style == TAITWATER) { rho_ratio = rho[i] / rho0inv; rr3 = rho_ratio * rho_ratio * rho_ratio; - p[i] = csq * rho0 * inv7 * (rr3 * rr3 * rho_ratio - 1.0); + pressure[i] = csq * rho0 * inv7 * (rr3 * rr3 * rho_ratio - 1.0); } } } - if (last_flag && comm_forward) comm->forward_comm(this); } @@ -165,7 +165,7 @@ int FixRHEOPressure::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,k,m; - double *pressure = fix_rheo->pressure; + double *pressure = atom->dvector[index_pres]; m = 0; for (i = 0; i < n; i++) { @@ -180,7 +180,7 @@ int FixRHEOPressure::pack_forward_comm(int n, int *list, double *buf, void FixRHEOPressure::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; - double *pressure = fix_rheo->pressure; + double *pressure = atom->dvector[index_pres]; m = 0; last = first + n; diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index 45217c7f75..6c7ee73370 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -39,7 +39,8 @@ class FixRHEOPressure : public Fix { double c_cubic, csq, rho0, rho0inv; int pressure_style; int first_flag, last_flag; - int nmax; + int nmax_old, index_pressure; + class FixRHEO *fix_rheo; }; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 0fe9c7796e..2b63c7633b 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -138,7 +138,7 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) int tmp1, tmp2; index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index_cond == -1) { + if (index_visc == -1) { index_visc = atom->add_custom("rheo_viscosity", 1, 0); nmax_old = atom->nmax; } diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index d3ac28d3d5..d1a30d3b40 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -229,9 +229,8 @@ void PairRHEO::compute(int eflag, int vflag) } } - // If either particle is fluid, compute hydrostatic and viscous forces - // Compute eta*Lap(v) - different forms depending on order of RK correction if (pair_force_flag) { + //Hydrostatic pressure forces fp_prefactor = voli * volj * (Pj + Pi); sub3(v1, vj, du); @@ -271,6 +270,9 @@ void PairRHEO::compute(int eflag, int vflag) fp[i][1] += dfp[1]; fp[i][2] += dfp[2]; + if (evflag) // Does not account for unbalanced forces + ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); + if (newton_pair || j < nlocal) { for (a = 0; a < dim; a ++) { fv[a] = 0.0; @@ -293,9 +295,6 @@ void PairRHEO::compute(int eflag, int vflag) fp[j][1] -= dfp[1]; fp[j][2] -= dfp[2]; } - - if (evflag) // Doesn't account for unbalanced forces - ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); } // Density damping From bf669d526bfcce31d40f7f58ff95ff62dc186c34 Mon Sep 17 00:00:00 2001 From: EricPalermo Date: Fri, 24 Mar 2023 15:38:26 -0400 Subject: [PATCH 014/385] test adding file --- src/RHEO/test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/RHEO/test.txt diff --git a/src/RHEO/test.txt b/src/RHEO/test.txt new file mode 100644 index 0000000000..e69de29bb2 From 0a3a4c527d987c0b250d208d3559fe5849188c5e Mon Sep 17 00:00:00 2001 From: EricPalermo Date: Fri, 24 Mar 2023 16:43:34 -0400 Subject: [PATCH 015/385] generalized density in dT calculation --- src/RHEO/pair_rheo.cpp | 3 +-- src/RHEO/test.txt | 0 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 src/RHEO/test.txt diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index d1a30d3b40..f03e2b25cd 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -218,8 +218,7 @@ void PairRHEO::compute(int eflag, int vflag) // Thermal Evolution if (thermal_flag) { dT = dot3(dx, dWij); - dT *= (kappai + kappaj) * (Ti - Tj) * rinv * rinv * voli * volj; - //TODO: Assumes heat capacity and density = 1, needs to be generalized + dT *= (kappai + kappaj) * (Ti - Tj) * rinv * rinv * voli * volj / rho0; // Assumes heat capacity = 1 heatflow[i] += dT; if (newton_pair || j < nlocal) { diff --git a/src/RHEO/test.txt b/src/RHEO/test.txt deleted file mode 100644 index e69de29bb2..0000000000 From 29edfc45d7d7c55342b3e4c1f890b27401d869ad Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 24 Mar 2023 21:59:17 -0600 Subject: [PATCH 016/385] Adding heat/temperature checks/zeroing to thermal fix --- src/GRANULAR/fix_heat_flow.cpp | 4 +- src/RHEO/fix_rheo_thermal.cpp | 81 +++++++++++++++++++++++++++++++--- src/RHEO/fix_rheo_thermal.h | 2 + src/RHEO/pair_rheo.cpp | 1 - 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/GRANULAR/fix_heat_flow.cpp b/src/GRANULAR/fix_heat_flow.cpp index a9c110a2e7..1b2e55e673 100644 --- a/src/GRANULAR/fix_heat_flow.cpp +++ b/src/GRANULAR/fix_heat_flow.cpp @@ -80,9 +80,9 @@ void FixHeatFlow::init() dt = update->dt; if (!atom->temperature_flag) - error->all(FLERR,"Fix temp/integrate requires atom style with temperature property"); + error->all(FLERR,"Fix temp/integrate requires atoms store temperature property"); if (!atom->heatflow_flag) - error->all(FLERR,"Fix temp/integrate requires atom style with heatflow property"); + error->all(FLERR,"Fix temp/integrate requires atoms store heatflow property"); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index f000bf65cc..272daf9bd0 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -161,6 +161,11 @@ void FixRHEOThermal::init() compute_vshift = fix_rheo->compute_vshift; dtf = 0.5 * update->dt * force->ftm2v; + + if (atom->temperature_flag != 1) + error->all(FLERR,"fix rheo/thermal command requires atoms store temperature property"); + if (atom->heatflow_flag != 1) + error->all(FLERR,"fix rheo/thermal command requires atoms store heatflow property"); } /* ---------------------------------------------------------------------- */ @@ -234,7 +239,7 @@ void FixRHEOThermal::post_integrate() { int *status = atom->status; double *temperature = atom->temperature; - double *heat = atom->heat; + double *heatflow = atom->heatflow; double *rho = atom->rho; int *mask = atom->mask; int *type = aotm->type; @@ -247,7 +252,7 @@ void FixRHEOThermal::post_integrate() if (status[i] == FixRHEO::FLUID_NO_FORCE) continue; cvi = calc_cv(i); - temperature[i] += dtf * heat[i] / cvi; + temperature[i] += dtf * heatflow[i] / cvi; if (Tc_style != NONE) { Ti = temperature[i]; @@ -298,11 +303,20 @@ void FixRHEOThermal::post_neighbor() /* ---------------------------------------------------------------------- Update (and forward) evolving conductivity styles every timestep + Zero heat flow ------------------------------------------------------------------------- */ void FixRHEOThermal::pre_force(int /*vflag*/) { - // Not needed yet, when needed add (un)pack_forward_comm() methods + // send updated temperatures to ghosts if first instance of fix + // then clear heatflow for next force calculation + double *heatflow = atom->heatflow; + if (first_flag) { + comm->forward_comm(this); + for (int i = 0; i < atom->nmax; i++) heatflow[i] = 0.0; + } + + // Not needed yet, when needed add stage check for (un)pack_forward_comm() methods //int i; //double *conductivity = atom->dvector[index_cond]; //int *mask = atom->mask; @@ -327,7 +341,7 @@ void FixRHEOThermal::pre_force(int /*vflag*/) void FixRHEOThermal::final_integrate() { double *temperature = atom->temperature; - double *heat = atom->heat; + double *heatflow = atom->heatflow; int *status = atom->status; int *mask = atom->mask; @@ -339,7 +353,7 @@ void FixRHEOThermal::final_integrate() if (status[i] & FixRHEO::STATUS_NO_FORCE) continue; cvi = calc_cv(i); - temperature[i] += dtf * heat[i] / cvi; + temperature[i] += dtf * heatflow[i] / cvi; } } } @@ -362,3 +376,60 @@ double FixRHEOThermal::calc_cv(int i) return(cv_type[atom->type[i]]); } } + +/* ---------------------------------------------------------------------- */ + +int FixRHEOThermal::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) +{ + int i, j, m; + + double *temperature = atom->temperature; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = temperature[j]; + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::unpack_forward_comm(int n, int first, double *buf) +{ + int i, m, last; + + m = 0; + last = first + n; + + double *temperature = atom->temperature; + + for (i = first; i < last; i++) temperature[i] = buf[m++]; +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOThermal::pack_reverse_comm(int n, int first, double *buf) +{ + int m = 0; + int last = first + n; + double *heatflow = atom->heatflow; + + for (int i = first; i < last; i++) { + buf[m++] = heatflow[i]; + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::unpack_reverse_comm(int n, int *list, double *buf) +{ + int m = 0; + double *heatflow = atom->heatflow; + + for (int i = 0; i < n; i++) + heatflow[list[i]] += buf[m++]; +} diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index e4ed426fb4..d9a17ebd60 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -39,6 +39,8 @@ class FixRHEOThermal : public Fix { void reset_dt() override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; private: double *cv_type, cv; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index d1a30d3b40..d78af46249 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -219,7 +219,6 @@ void PairRHEO::compute(int eflag, int vflag) if (thermal_flag) { dT = dot3(dx, dWij); dT *= (kappai + kappaj) * (Ti - Tj) * rinv * rinv * voli * volj; - //TODO: Assumes heat capacity and density = 1, needs to be generalized heatflow[i] += dT; if (newton_pair || j < nlocal) { From 908c32788cab5c2f3b7dbeaec208c26577ead8b2 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sat, 25 Mar 2023 20:17:17 -0600 Subject: [PATCH 017/385] Cleaning up fix rheo, initial sketch of kernel compute --- src/RHEO/compute_rheo_kernel.cpp | 870 +++++++++++++++++++++++++++++++ src/RHEO/compute_rheo_kernel.h | 71 +++ src/RHEO/fix_rheo.cpp | 42 +- src/RHEO/fix_rheo.h | 11 - src/RHEO/fix_rheo_thermal.cpp | 3 +- 5 files changed, 948 insertions(+), 49 deletions(-) create mode 100644 src/RHEO/compute_rheo_kernel.cpp create mode 100644 src/RHEO/compute_rheo_kernel.h diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp new file mode 100644 index 0000000000..116ac08745 --- /dev/null +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -0,0 +1,870 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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_rheo_kernel.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_solids.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "math_extra.h" +#include "memory.h" +#include "modify.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "pair.h" +#include "update.h" +#include "utils.h" + +#include +#include +#include +#include +#include +#include + +using namespace LAMMPS_NS; +enum {QUINTIC, CRK0, CRK1, CRK2}; +#define DELTA 2000 + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), + C(nullptr), C0(nullptr), compute_solids(nullptr); +{ + if (narg != 3) error->all(FLERR,"Illegal compute rheo/kernel command"); + + comm_forward = 1; // For coordination + solid_flag = 0; +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOKernel::~ComputeRHEOKernel() +{ + // Remove custom property if it exists + int tmp1, tmp2, index; + index = atom->find_custom("rheo_coordination", tmp1, tmp2); + if (index != -1) atom->remove_custom(index_coord, 1, 0); + + memory->destroy(C); + memory->destroy(C0); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::init() +{ + neighbor->add_request(this, NeighConst::REQ_FULL); + + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use compute rheo/kernel"); + fix_rheo = dynamic_cast(fixes[0]); + + int icompute = modify->find_compute("rheo_solids"); + if (icompute != -1) { + compute_solids = ((ComputeRHEOSolids *) modify->compute[icompute]); + solid_flag = 1; + } + + + N2min = utils::inumeric(FLERR,arg[4],false,lmp); + + cutsq = cut*cut; + cutinv = 1.0/cut; + h = cut/3.0; + ih = 1.0/h; + ihsq = ih*ih; + + kernel_type = QUINTIC; + correction_order = -1; + } else if (strcmp(arg[3],"CRK0") == 0) { + kernel_type = CRK0; + correction_order = 0; + } else if (strcmp(arg[3],"CRK1") == 0) { + kernel_type = CRK1; + correction_order = 1; + } else if (strcmp(arg[3],"CRK2") == 0) { + kernel_type = CRK2; + correction_order = 2; + + if (dim == 3) { + pre_w = 0.002652582384864922*ihsq*ih; + pre_wp = pre_w*ih; + } else { + pre_w = 0.004661441847879780*ihsq; + pre_wp = pre_w*ih; + } + + //Use property atom, can fix store save integers? + char **fixarg = new char*[4]; + fixarg[0] = (char *) "PROPERTY_ATOM_RHEO_KERNEL"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "property/atom"; + fixarg[3] = (char *) "i_coordination"; + modify->add_fix(4,fixarg,1); + + + nmax = atom->nmax; + + if (kernel_type == CRK0) { + memory->create(C0, nmax, "rheo/kernel:C0"); + comm_forward = 1; + } + + if (kernel_type == CRK1) { + Mdim = 1 + dim; + ncor = 1 + dim; + memory->create(C, nmax, ncor, Mdim, "rheo/kernel:C"); + comm_forward = ncor*Mdim; + } + + if (kernel_type == CRK2) { + //Polynomial basis size (up to quadratic order) + Mdim = 1 + dim + dim*(dim+1)/2; + //Number of sets of correction coefficients (1 x y xx yy) + z zz (3D) + ncor = 1 + 2*dim; + //variables that require forwarding + memory->create(C, nmax, ncor, Mdim, "rheo/kernel:C"); + comm_forward = ncor*Mdim; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOKernel::check_corrections(int i) +{ + int corrections = 1; + + if (gsl_error_flag) { + // If there were errors, check to see if it occured for this atom + if (gsl_error_tags.find(atom->tag[i]) != gsl_error_tags.end()) + corrections = 0; + } + + coordination = atom->ivector[index_coord]; + if (coordination[i] < N2min) corrections = 0; + + return corrections; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double delz, double r) +{ + double w; + + int corrections_i = check_corrections(i); + int corrections_j = check_corrections(j); + int corrections = corrections_i & corrections_j; + + if (memory_flag) { + long long key; + int v_index; + tagint tag1 = atom->tag[i]; + tagint tag2 = atom->tag[j]; + + // Use Szudzik's pairing function to define unique index for two tags + // szudzik.com/elegantpairing.pdf + if (tag1 > tag2) key = (long long) tag1*tag1 + tag2; + else key = (long long) tag2*tag2 + tag1; + + if (locations_w.find(key) != locations_w.end()){ + v_index = locations_w[key]; + w = stored_w[v_index]; + } else { + if (kernel_type == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); + else if (kernel_type == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); + else if (kernel_type == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); + else if (kernel_type == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); + + locations_w[key] = nstored_w; + stored_w[nstored_w] = w; + nstored_w ++; + if (nstored_w >= max_nstored) grow_memory(); + } + } else { + if (kernel_type == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); + else if (kernel_type == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); + else if (kernel_type == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); + else if (kernel_type == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); + } + + return w; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double delz, double r) +{ + double wp; + + int corrections_i = check_corrections(i); + int corrections_j = check_corrections(j); + + // Calc wp and default dW's, a bit inefficient but can redo later + wp = calc_dw_quintic(i,j,delx,dely,delz,r,dWij,dWji); + if(kernel_type == CRK1) { + //check if kernel correction calculated successfully. If not, revert to quintic + if (corrections_i) calc_dw_crk1(i,j,delx,dely,delz,r,dWij); + if (corrections_j) calc_dw_crk1(j,i,-delx,-dely,-delz,r,dWji); + } else if(kernel_type == CRK2) { + if (corrections_i) calc_dw_crk2(i,j,delx,dely,delz,r,dWij); + if (corrections_j) calc_dw_crk2(j,i,-delx,-dely,-delz,r,dWji); + } + + return wp; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_w_quintic(int i, int j, double delx, double dely, double delz, double r) +{ + double w, tmp1, tmp2, tmp3, tmp1sq, tmp2sq, tmp3sq, s; + s = r*ih; + + if (s>3.0) { + w = 0.0; + } + + if (s <= 3.0) { + tmp3 = 3 - s; + tmp3sq = tmp3*tmp3; + w = tmp3sq*tmp3sq*tmp3; + } + if (s <= 2.0) { + tmp2 = 2 - s; + tmp2sq = tmp2*tmp2; + w -= 6*tmp2sq*tmp2sq*tmp2; + } + if (s <= 1.0) { + tmp1 = 1 - s; + tmp1sq = tmp1*tmp1; + w += 15*tmp1sq*tmp1sq*tmp1; + } + + w *= pre_w; + + Wij = w; + Wji = w; + + return w; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_dw_quintic(int i, int j, double delx, double dely, double delz, double r, double *dW1, double *dW2) +{ + double wp, tmp1, tmp2, tmp3, tmp1sq, tmp2sq, tmp3sq, s, wprinv; + double *mass = atom->mass; + int *type = atom->type; + + s = r*ih; + + if (s>3.0) { + wp = 0.0; + } + if (s <= 3.0) { + tmp3 = 3 - s; + tmp3sq = tmp3*tmp3; + wp = -5.0*tmp3sq*tmp3sq; + } + if (s <= 2.0) { + tmp2 = 2 - s; + tmp2sq = tmp2*tmp2; + wp += 30.0*tmp2sq*tmp2sq; + } + if (s <= 1.0) { + tmp1 = 1 - s; + tmp1sq = tmp1*tmp1; + wp -= 75.0*tmp1sq*tmp1sq; + } + + wp *= pre_wp; + wprinv = wp/r; + dW1[0] = delx*wprinv; + dW1[1] = dely*wprinv; + dW1[2] = delz*wprinv; + + dW2[0] = -delx*wprinv; + dW2[1] = -dely*wprinv; + dW2[2] = -delz*wprinv; + + return wp; +} + + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_w_crk0(int i, int j, double delx, double dely, double delz, double r) +{ + double w; + + w = calc_w_quintic(i,j,delx,dely,delz,r); + + Wij = C0[i]*w; + Wji = C0[j]*w; + + return w; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_w_crk1(int i, int j, double delx, double dely, double delz, double r) +{ + int b; + double w, wR, dx[3], H[Mdim]; + + dx[0] = delx; + dx[1] = dely; + dx[2] = delz; + w = calc_w_quintic(i,j,delx,dely,delz,r); + + if (dim == 2) { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + } else { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + H[3] = dx[2]*cutinv; + } + Wij = 0; + for (b = 0; b < Mdim; b++) { + Wij += C[i][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + } + Wij *= w; + + //Now compute Wji + H[1] *= -1; + H[2] *= -1; + if (dim == 3) H[3] *= -1; + + Wji = 0; + for (b = 0; b < Mdim; b++) { + Wji += C[j][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + } + Wji *= w; + + return w; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_w_crk2(int i, int j, double delx, double dely, double delz, double r) +{ + int b; + double w, wR, dx[3], H[Mdim]; + dx[0] = delx; + dx[1] = dely; + dx[2] = delz; + w = calc_w_quintic(i,j,delx,dely,delz,r); + + + if (dim == 2) { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + H[3] = 0.5*dx[0]*dx[0]*cutinv*cutinv; + H[4] = 0.5*dx[1]*dx[1]*cutinv*cutinv; + H[5] = dx[0]*dx[1]*cutinv*cutinv; + } else { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + H[3] = dx[2]*cutinv; + H[4] = 0.5*dx[0]*dx[0]*cutinv*cutinv; + H[5] = 0.5*dx[1]*dx[1]*cutinv*cutinv; + H[6] = 0.5*dx[2]*dx[2]*cutinv*cutinv; + H[7] = dx[0]*dx[1]*cutinv*cutinv; + H[8] = dx[0]*dx[2]*cutinv*cutinv; + H[9] = dx[1]*dx[2]*cutinv*cutinv; + } + Wij = 0; + for (b = 0; b < Mdim; b++) { + Wij += C[i][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + } + Wij *= w; + + //Now compute Wji + H[1] *= -1; + H[2] *= -1; + if (dim == 3) H[3] *= -1; + + Wji = 0; + for (b = 0; b < Mdim; b++) { + Wji += C[j][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + } + Wji *= w; + + return w; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::calc_dw_crk1(int i, int j, double delx, double dely, double delz, double r, double *dW) +{ + int a, b; + double w, dx[3], H[Mdim]; + dx[0] = delx; + dx[1] = dely; + dx[2] = delz; + + w = calc_w_quintic(i,j,delx,dely,delz,r); + //Populate correction basis + if (dim == 2) { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + } else { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + H[3] = dx[2]*cutinv; + } + // dWij[] = dWx dWy (dWz) + //compute derivative operators + for (a = 0; a < dim; a++) { + dW[a] = 0.0; + for (b = 0; b < Mdim; b++) { + //First derivative kernels + dW[a] += C[i][1+a][b]*H[b]; // C columns: 1 x y (z) + } + dW[a] *= w; + } +} + + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::calc_dw_crk2(int i, int j, double delx, double dely, double delz, double r, double *dW) +{ + int a, b; + double w, dx[3], H[Mdim]; + dx[0] = delx; + dx[1] = dely; + dx[2] = delz; + + w = calc_w_quintic(i,j,delx,dely,delz,r); + + //Populate correction basis + if (dim == 2) { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + H[3] = 0.5*dx[0]*dx[0]*cutinv*cutinv; + H[4] = 0.5*dx[1]*dx[1]*cutinv*cutinv; + H[5] = dx[0]*dx[1]*cutinv*cutinv; + } else { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + H[3] = dx[2]*cutinv; + H[4] = 0.5*dx[0]*dx[0]*cutinv*cutinv; + H[5] = 0.5*dx[1]*dx[1]*cutinv*cutinv; + H[6] = 0.5*dx[2]*dx[2]*cutinv*cutinv; + H[7] = dx[0]*dx[1]*cutinv*cutinv; + H[8] = dx[0]*dx[2]*cutinv*cutinv; + H[9] = dx[1]*dx[2]*cutinv*cutinv; + } + + // dWij[] = dWx dWy (dWz) + //compute derivative operators + for (a = 0; a < dim; a++) { + dW[a] = 0.0; + for (b = 0; b < Mdim; b++) { + //First derivative kernels + dW[a] += C[i][1+a][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + } + dW[a] *= w; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::compute_peratom() +{ + gsl_error_flag = 0; + gsl_error_tags.clear(); + + int i, j, ii, jj, jnum, itype, jtype; + double xtmp, ytmp, ztmp, delx, dely, delz; + double r, rinv, rsq, imass, jmass; + double dx[3]; + double w, wp, s, vi, vj, M, vjw; + double vjdw[3] = {0}; + bool sflag; + + double **x = atom->x; + int *type = atom->type; + double *mass = atom->mass; + double *rho = atom->rho; + int *phase = atom->phase; + tagint *tag = atom->tag; + coordination = atom->ivector[index_coord]; + + int inum, *ilist, *jlist, *numneigh, **firstneigh; + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + if (kernel_type == QUINTIC) { + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; // Will be ignored in 2D + + jlist = firstneigh[i]; + jnum = numneigh[i]; + itype = type[i]; + coordination[i] = 0; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + + rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; + r = sqrt(rsq); + rinv = 1/r; + + if (rsq < cutsq) { + coordination[i] += 1; + } + } + } + + comm->forward_comm_compute(this); + + } else if (kernel_type == CRK0) { + if (atom->nmax > nmax){ + nmax = atom->nmax; + memory->destroy(C0); + memory->create(C0, nmax, "rheo/kernel:C"); + } + + //The moment Matrix array has to be 1D to be compatible with gsl + // Solve linear system for each atom + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; // Will be ignored in 2D + + jlist = firstneigh[i]; + jnum = numneigh[i]; + itype = type[i]; + + //Initialize M and H to zero: + M = 0; + + //variable for insufficient neighbors + coordination[i] = 0; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + + rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; + r = sqrt(rsq); + rinv = 1/r; + + if (rsq < cutsq) { + //Compute Wij + w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); + if (phase[j] > FixRHEO::FLUID_MAX && solid_flag) + vj = mass[type[j]]/compute_solids->correct_rho(j,i); + else vj = mass[type[j]]/rho[j]; + coordination[i] += 1; // Increment contributing neighbor + + M += w*vj; + } + } + + if (coordination[i] < N2min) continue; + //Get inverse of 1x1 matrix + M = 1.0/M; + C0[i] = M; + } + + // communicate densities - maybe not needed for ghost atoms but just to be safe + // can remove in future once we determine they aren't necessary + comm->forward_comm_compute(this); + + } else if (correction_order > 0) { + + int i, j, ii, jj, jnum, itype, jtype; + int g, a, b, c, d, ib, ic, id, nperm; + double xtmp, ytmp, ztmp, delx, dely, delz; + double dx[3] = {0}; + + //Turn off GSL error handler so we can check and revert RK to Quintic + //when inssuficient neighbors + gsl_set_error_handler_off(); + + // Create Moment matrix M and polynomial basis vector H + //The moment Matrix array has to be 1D to be compatible with gsl + double H[Mdim], M[Mdim*Mdim]; + + if (atom->nmax > nmax){ + nmax = atom->nmax; + memory->destroy(C); + memory->create(C, nmax,ncor,Mdim, "rheo/kernel:C"); + } + + // Solve linear system for each atom + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; // Will be ignored in 2D + + jlist = firstneigh[i]; + jnum = numneigh[i]; + itype = type[i]; + + //Initialize M and H to zero: + for (a = 0; a < Mdim; a++) { + for (b = a; b < Mdim; b++) { + //Just zero upper-triangle of M since it will be symmetric + M[a*Mdim+b] = 0; + } + } + //Zero moment + //variables for switching off RK caclulation if insufficient neighbors + sflag = 0; + coordination[i] = 0; + // Loop over neighbors to populate elements of L + //m0[i] = 0.0; + + //Self contribution + //w = calc_w_quintic(i,i,0.,0.,0.,0.); + //m0[i] += w; + //vi = 1/vw[i]; + + vi = mass[type[i]]/rho[i]; // Overwritten if i is solid + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + + rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; + r = sqrt(rsq); + rinv = 1/r; + + if (rsq < cutsq) { + //Compute Wij + w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); + //vj = 1/vw[j]; // + + if (phase[i] > FixRHEO::FLUID_MAX && solid_flag) + vi = mass[type[i]]/compute_solids->correct_rho(i,j); + + if (phase[j] > FixRHEO::FLUID_MAX && solid_flag) + vj = mass[type[j]]/compute_solids->correct_rho(j,i); + else vj = mass[type[j]]/rho[j]; + //m0[i] += w; + + //Populate the H-vector of polynomials (2D) + if (dim == 2) { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + if (kernel_type == CRK2) { + H[3] = 0.5*dx[0]*dx[0]*cutinv*cutinv; + H[4] = 0.5*dx[1]*dx[1]*cutinv*cutinv; + H[5] = dx[0]*dx[1]*cutinv*cutinv; + } + } else { + H[0] = 1.0; + H[1] = dx[0]*cutinv; + H[2] = dx[1]*cutinv; + H[3] = dx[2]*cutinv; + if (kernel_type == CRK2) { + H[4] = 0.5*dx[0]*dx[0]*cutinv*cutinv; + H[5] = 0.5*dx[1]*dx[1]*cutinv*cutinv; + H[6] = 0.5*dx[2]*dx[2]*cutinv*cutinv; + H[7] = dx[0]*dx[1]*cutinv*cutinv; + H[8] = dx[0]*dx[2]*cutinv*cutinv; + H[9] = dx[1]*dx[2]*cutinv*cutinv; + } + } + coordination[i] += 1; // Increment contributing neighbor + + //Populate the upper triangle of the + for (a = 0; a < Mdim; a++) { + for (b = a; b < Mdim; b++) { + M[a*Mdim+b] += H[a]*H[b]*w*vj; + } + } + } + } + //Now populate the lower triangle from the symmetric entries of M: + for (a = 0; a < Mdim; a++) { + for (b = a; b < Mdim; b++) { + M[b*Mdim+a] = M[a*Mdim+b]; + } + } + + if (coordination[i] < N2min) continue; + + //Use gsl to get Minv + //Since the polynomials are independent, M is symmetrix & positive-definite + //So we will use a Cholesky decomposition + gsl_matrix_view gM = gsl_matrix_view_array(M,Mdim,Mdim); + int status; + status = 0; + //gsl_linalg_cholesky_decomp1 -> gsl_linalg_cholesky_decomp + //So I don't have to update my gsl (me being lazy, can revert) + status = gsl_linalg_cholesky_decomp(&gM.matrix); //M is now the cholesky decomposition of M + // check if erro in inversion + if (status) { + //Revert to uncorrected SPH for this particle + gsl_error_flag = 1; + gsl_error_tags.insert(tag[i]); + + //check if not positive-definite + if (status != GSL_EDOM) + fprintf(stderr, "failed, gsl_errno=%d.n", status); + + continue; + } else { + gsl_linalg_cholesky_invert(&gM.matrix); //M is now M^-1 + } + + // Correction coefficients are just the columns of M^-1 multiplied by an appropriate coefficient + //Solve the linear system several times to get coefficientns + // M: 1 x y (z) x^2 y^2 (z^2) xy (xz) (yz) + //---------------------------------------------------------- + // 0 1 2 3 4 5 || 2D indexing + // 0 1 2 3 4 5 6 7 8 9 || 3D indexing + // W 1 . . . . . . . . . + // dWx . -1 . . . . . . . . + // dWy . . -1 . . . . . . . + // dWz . . . (-1) . . . . . . + // d2Wx . . . . 2 . . . . . + // d2Wy . . . . . 2 . . . . + // d2Wz . . . . . . (2) . . . + + //0 1 2 3 4 + //0 1 2 3 4 5 6 + + // Use coefficents to compute smoothed density + //Pack coefficients into C + for (a = 0; a < Mdim; a++) { + //W + C[i][0][a] = M[a*Mdim + 0]; // all rows of column 0 + for (b = 0; b < dim; b++) { + //First derivatives + C[i][1+b][a] = -M[a*Mdim + b+1]/cut; // columns 1-2 (2D) or 1-3 (3D) + //Second derivatives + if (kernel_type == CRK2) + C[i][1+dim+b][a] = M[a*Mdim + b+1+dim]/cutsq; // columns 3-4 (2D) or 4-6 (3D) + } + } + } + + // communicate densities - maybe not needed for ghost atoms but just to be safe + // can remove in future once we determine they aren't necessary + comm->forward_comm_compute(this); + } +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOKernel::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,k,m,a,b; + coordination = atom->ivector[index_coord]; + m = 0; + if (correction_order > 0) { + for (i = 0; i < n; i++) { + j = list[i]; + for (a = 0; a < ncor; a++) { + for (b = 0; b < Mdim; b++) { + buf[m++] = C[j][a][b]; + } + } + buf[m++] = coordination[j]; + } + } else if (kernel_type == CRK0) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = C0[j]; + buf[m++] = coordination[j]; + } + } else { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = coordination[j]; + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last,a,b; + coordination = atom->ivector[index_coord]; + m = 0; + last = first + n; + if (correction_order > 0) { + for (i = first; i < last; i++) { + for (a = 0; a < ncor; a++) { + for (b = 0; b < Mdim; b++) { + C[i][a][b] = buf[m++]; + } + } + coordination[i] = buf[m++]; + } + } else if (kernel_type == CRK0) { + for (i = first; i < last; i++) { + C0[i] = buf[m++]; + coordination[i] = buf[m++]; + } + } else { + for (i = first; i < last; i++) { + coordination[i] = buf[m++]; + } + } +} diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h new file mode 100644 index 0000000000..114f39e85e --- /dev/null +++ b/src/RHEO/compute_rheo_kernel.h @@ -0,0 +1,71 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(rheo/kernel,ComputeRHEOKernel) +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_KERNEL_H +#define LMP_COMPUTE_RHEO_KERNEL_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEOKernel : public Compute { + public: + ComputeRHEOKernel(class LAMMPS *, int, char **); + ~ComputeRHEOKernel() override; + void init() override; + void init_list(int, class NeighList *) override; + void compute_peratom() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + double memory_usage() override; + double calc_w(int,int,double,double,double,double); + double calc_dw(int,int,double,double,double,double); + double calc_w_quintic(int,int,double,double,double,double); + double calc_dw_quintic(int,int,double,double,double,double,double *,double *); + + double dWij[3], dWji[3], Wij, Wji; + int correction_order; + + private: + int solid_flag; + int gsl_error_flag; + + int kernel_type, N2min, nmax, Mdim, ncor; + int nmax_old, index_coord; + double cut, cutsq, cutinv, h, ih, ihsq, pre_w, pre_wp; + double ***C; + double *C0; + + class NeighList *list; + class ComputeRHEOSolids *compute_solids; + class FixRHEO *fix_rheo; + + int check_corrections(int); + + double calc_w_crk0(int,int,double,double,double,double); + double calc_w_crk1(int,int,double,double,double,double); + double calc_w_crk2(int,int,double,double,double,double); + void calc_dw_crk1(int,int,double,double,double,double,double *); + void calc_dw_crk2(int,int,double,double,double,double,double *); +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index cccaa792ff..6d16bf2782 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -21,7 +21,6 @@ #include "compute_rheo_vshift.h" #include "domain.h" #include "error.h" -#include "fix_store_peratom.h" #include "force.h" #include "modify.h" #include "update.h" @@ -34,10 +33,7 @@ using namespace FixConst; FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), compute_grad(nullptr), compute_kernel(nullptr), - compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr), - fix_store_visc(nullptr), fix_store_pres(nullptr), fix_store_cond(nullptr), - fix_store_surf(nullptr), fix_store_fp(nullptr), surface(nullptr), conductivity(nullptr), - viscosity(nullptr), pressure(nullptr), f_pressure(nullptr) + compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr) { time_integrate = 1; @@ -112,12 +108,6 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : FixRHEO::~FixRHEO() { - if (fix_store_visc) modify->delete_fix("rheo_store_visc"); - if (fix_store_pres) modify->delete_fix("rheo_store_pres"); - if (fix_store_surf) modify->delete_fix("rheo_store_surf"); - if (fix_store_cond) modify->delete_fix("rheo_store_cond"); - if (fix_store_fp) modify->delete_fix("rheo_store_fp"); - if (compute_kernel) modify->delete_compute("rheo_kernel"); if (compute_grad) modify->delete_compute("rheo_grad"); if (compute_interface) modify->delete_compute("rheo_interface"); @@ -133,46 +123,26 @@ FixRHEO::~FixRHEO() void FixRHEO::post_constructor() { compute_kernel = dynamic_cast(modify->add_compute("rheo_kernel all rheo/kernel")); - - fix_store_visc = dynamic_cast(modify->add_fix("rheo_store_visc all STORE/PERATOM 0 1")) - fix_store_visc->disable = 1; - viscosity = fix_store_visc->vstore; - fix_store_pres = dynamic_cast(modify->add_fix("rheo_store_pres all STORE/PERATOM 0 1")) - pressure = fix_store_pres->vstore; - fix_store_pres->disable = 1; - + compute_kernel->fix_rheo = this; std::string cmd = "rheo_grad all rheo/grad velocity rho viscosity"; if (thermal_flag) cmd += "temperature"; compute_grad = dynamic_cast(modify->add_compute(cmd)); compute_grad->fix_rheo = this; - if (rhosum_flag) + if (rhosum_flag) { compute_rhosum = dynamic_cast(modify->add_compute("rheo_rhosum all rheo/rho/sum")); + compute_rhosum->fix_rheo = this; + } if (shift_flag) { compute_vshift = dynamic_cast(modify->add_compute("rheo_vshift all rheo/vshift")); compute_vshift->fix_rheo = this; } - if (surface_flag) { - fix_store_surf = dynamic_cast(modify->add_fix("rheo_store_surf all STORE/PERATOM 0 1")) - surface = fix_store_surf->vstore; - fix_store_surf->disable = 1; - } - - if (thermal_flag) { - fix_store_cond = dynamic_cast(modify->add_fix("rheo_store_cond all STORE/PERATOM 0 1")) - conductivity = fix_store_cond->vstore; - fix_store_cond->disable = 1; - } - if (interface_flag) { compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface"))); - - fix_store_fp = dynamic_cast(modify->add_fix("rheo_store_fp all STORE/PERATOM 0 3")) - f_pressure = fix_store_fp->astore; - fix_store_fp->disable = 1; + compute_interface->fix_rheo = this; } } diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 3487dd7273..0132f32bcc 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -44,11 +44,6 @@ class FixRHEO : public Fix { int kernel_style; enum {QUINTIC, CRK0, CRK1, CRK2}; - // Non-persistent per-atom arrays - int *surface; - double *conductivity, *viscosity, *pressure; - double **f_pressure; - // Status variables enum { // Phase status @@ -83,12 +78,6 @@ class FixRHEO : public Fix { int interface_fix_defined; int surface_fix_defined; - class FixStorePeratom *fix_store_visc; - class FixStorePeratom *fix_store_pres; - class FixStorePeratom *fix_store_cond; - class FixStorePeratom *fix_store_surf; - class FixStorePeratom *fix_store_fp; - class ComputeRHEOGrad *compute_grad; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 272daf9bd0..8b0c9e46de 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -32,8 +32,7 @@ enum {NONE, CONSTANT, TYPE}; /* ---------------------------------------------------------------------- */ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), - conductivity(nullptr) + Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); From 98050c96cc132ad8c5e6b6d96cad193eaad22437 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 26 Mar 2023 14:30:34 -0600 Subject: [PATCH 018/385] Cleaning up kernel compute --- src/RHEO/compute_rheo_kernel.cpp | 534 +++++++++++++------------------ src/RHEO/compute_rheo_kernel.h | 8 +- 2 files changed, 234 insertions(+), 308 deletions(-) diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 116ac08745..62a4283977 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -15,7 +15,7 @@ #include "atom.h" #include "comm.h" -#include "compute_rheo_solids.h" +#include "compute_rheo_interface.h" #include "domain.h" #include "error.h" #include "fix_rheo.h" @@ -31,26 +31,32 @@ #include "utils.h" #include -#include #include #include #include #include using namespace LAMMPS_NS; +using namespace MathExtra; + enum {QUINTIC, CRK0, CRK1, CRK2}; #define DELTA 2000 +Todo: convert delx dely delz to an array +Should vshift be using kernel quintic? +Move away from h notation, use cut? + /* ---------------------------------------------------------------------- */ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), - C(nullptr), C0(nullptr), compute_solids(nullptr); + C(nullptr), C0(nullptr), compute_interface(nullptr); { if (narg != 3) error->all(FLERR,"Illegal compute rheo/kernel command"); - comm_forward = 1; // For coordination + comm_forward = 1; // Always minimum for coordination solid_flag = 0; + dim = domain->dimension; } /* ---------------------------------------------------------------------- */ @@ -76,72 +82,67 @@ void ComputeRHEOKernel::init() if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use compute rheo/kernel"); fix_rheo = dynamic_cast(fixes[0]); - int icompute = modify->find_compute("rheo_solids"); + int icompute = modify->find_compute("rheo_interface"); if (icompute != -1) { - compute_solids = ((ComputeRHEOSolids *) modify->compute[icompute]); + compute_interface = ((ComputeRHEOInterface *) modify->compute[icompute]); solid_flag = 1; } + kernel_style = fix_rheo->kernel_style; + zmin = fix_rheo->zmin_kernel; + h = fix_rheo->h; + hsq = h * h; + hinv = 1.0 / h; + hsqinv = hinv * hinv; - N2min = utils::inumeric(FLERR,arg[4],false,lmp); - - cutsq = cut*cut; - cutinv = 1.0/cut; - h = cut/3.0; - ih = 1.0/h; - ihsq = ih*ih; - - kernel_type = QUINTIC; + if (kernel_style == FixRHEO::QUINTIC) { correction_order = -1; - } else if (strcmp(arg[3],"CRK0") == 0) { - kernel_type = CRK0; + } else if (kernel_style == FixRHEO::CRK0) { correction_order = 0; - } else if (strcmp(arg[3],"CRK1") == 0) { - kernel_type = CRK1; + } else if (kernel_style == FixRHEO::CRK1) { correction_order = 1; - } else if (strcmp(arg[3],"CRK2") == 0) { - kernel_type = CRK2; + } else if (kernel_style == FixRHEO::CRK2) { correction_order = 2; + } if (dim == 3) { - pre_w = 0.002652582384864922*ihsq*ih; - pre_wp = pre_w*ih; + pre_w = 0.002652582384864922 * 27.0 * ihsq * ih; + pre_wp = pre_w * 3.0 * ih; } else { - pre_w = 0.004661441847879780*ihsq; - pre_wp = pre_w*ih; + pre_w = 0.004661441847879780 * 9 * ihsq; + pre_wp = pre_w * 3.0 * ih; } - //Use property atom, can fix store save integers? - char **fixarg = new char*[4]; - fixarg[0] = (char *) "PROPERTY_ATOM_RHEO_KERNEL"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "property/atom"; - fixarg[3] = (char *) "i_coordination"; - modify->add_fix(4,fixarg,1); + // Create coordination array if it doesn't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded + int tmp1, tmp2; + int nmax = atom->nmax; + index_coord = atom->find_custom("rheo_coordination", tmp1, tmp2); + if (index_coord == -1) { + index_coord = atom->add_custom("rheo_coordination", 0, 0); + nmax_old = nmax; + } - nmax = atom->nmax; - + comm_forward = 1; + ncor = 0; + Mdim = 0; if (kernel_type == CRK0) { memory->create(C0, nmax, "rheo/kernel:C0"); - comm_forward = 1; - } - - if (kernel_type == CRK1) { + } else if (kernel_type == CRK1) { Mdim = 1 + dim; ncor = 1 + dim; memory->create(C, nmax, ncor, Mdim, "rheo/kernel:C"); - comm_forward = ncor*Mdim; - } - - if (kernel_type == CRK2) { + comm_forward = ncor * Mdim; + } else if (kernel_type == CRK2) { //Polynomial basis size (up to quadratic order) - Mdim = 1 + dim + dim*(dim+1)/2; + Mdim = 1 + dim + dim * (dim + 1) / 2; //Number of sets of correction coefficients (1 x y xx yy) + z zz (3D) - ncor = 1 + 2*dim; - //variables that require forwarding + ncor = 1 + 2 * dim; memory->create(C, nmax, ncor, Mdim, "rheo/kernel:C"); - comm_forward = ncor*Mdim; + comm_forward = ncor * Mdim; } } @@ -164,8 +165,8 @@ int ComputeRHEOKernel::check_corrections(int i) corrections = 0; } - coordination = atom->ivector[index_coord]; - if (coordination[i] < N2min) corrections = 0; + int *coordination = atom->ivector[index_coord]; + if (coordination[i] < zmin) corrections = 0; return corrections; } @@ -180,37 +181,10 @@ double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double int corrections_j = check_corrections(j); int corrections = corrections_i & corrections_j; - if (memory_flag) { - long long key; - int v_index; - tagint tag1 = atom->tag[i]; - tagint tag2 = atom->tag[j]; - - // Use Szudzik's pairing function to define unique index for two tags - // szudzik.com/elegantpairing.pdf - if (tag1 > tag2) key = (long long) tag1*tag1 + tag2; - else key = (long long) tag2*tag2 + tag1; - - if (locations_w.find(key) != locations_w.end()){ - v_index = locations_w[key]; - w = stored_w[v_index]; - } else { - if (kernel_type == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); - else if (kernel_type == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); - else if (kernel_type == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); - else if (kernel_type == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); - - locations_w[key] = nstored_w; - stored_w[nstored_w] = w; - nstored_w ++; - if (nstored_w >= max_nstored) grow_memory(); - } - } else { - if (kernel_type == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); - else if (kernel_type == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); - else if (kernel_type == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); - else if (kernel_type == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); - } + if (kernel_type == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); + else if (kernel_type == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); + else if (kernel_type == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); + else if (kernel_type == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); return w; } @@ -243,26 +217,26 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double double ComputeRHEOKernel::calc_w_quintic(int i, int j, double delx, double dely, double delz, double r) { double w, tmp1, tmp2, tmp3, tmp1sq, tmp2sq, tmp3sq, s; - s = r*ih; + s = r * 3.0 * ih; - if (s>3.0) { + if (s > 3.0) { w = 0.0; } if (s <= 3.0) { - tmp3 = 3 - s; - tmp3sq = tmp3*tmp3; - w = tmp3sq*tmp3sq*tmp3; + tmp3 = 3.0 - s; + tmp3sq = tmp3 * tmp3; + w = tmp3sq * tmp3sq * tmp3; } if (s <= 2.0) { - tmp2 = 2 - s; - tmp2sq = tmp2*tmp2; - w -= 6*tmp2sq*tmp2sq*tmp2; + tmp2 = 2.0 - s; + tmp2sq = tmp2 * tmp2; + w -= 6.0 * tmp2sq * tmp2sq * tmp2; } if (s <= 1.0) { - tmp1 = 1 - s; - tmp1sq = tmp1*tmp1; - w += 15*tmp1sq*tmp1sq*tmp1; + tmp1 = 1.0 - s; + tmp1sq = tmp1 * tmp1; + w += 15.0 * tmp1sq * tmp1sq * tmp1; } w *= pre_w; @@ -281,36 +255,36 @@ double ComputeRHEOKernel::calc_dw_quintic(int i, int j, double delx, double dely double *mass = atom->mass; int *type = atom->type; - s = r*ih; + s = r * 3.0 * ih; - if (s>3.0) { + if (s > 3.0) { wp = 0.0; } if (s <= 3.0) { - tmp3 = 3 - s; - tmp3sq = tmp3*tmp3; - wp = -5.0*tmp3sq*tmp3sq; + tmp3 = 3.0 - s; + tmp3sq = tmp3 * tmp3; + wp = -5.0 * tmp3sq * tmp3sq; } if (s <= 2.0) { - tmp2 = 2 - s; - tmp2sq = tmp2*tmp2; - wp += 30.0*tmp2sq*tmp2sq; + tmp2 = 2.0 - s; + tmp2sq = tmp2 * tmp2; + wp += 30.0 * tmp2sq * tmp2sq; } if (s <= 1.0) { - tmp1 = 1 - s; - tmp1sq = tmp1*tmp1; - wp -= 75.0*tmp1sq*tmp1sq; + tmp1 = 1.0 - s; + tmp1sq = tmp1 * tmp1; + wp -= 75.0 * tmp1sq * tmp1sq; } wp *= pre_wp; - wprinv = wp/r; - dW1[0] = delx*wprinv; - dW1[1] = dely*wprinv; - dW1[2] = delz*wprinv; + wprinv = wp / r; + dW1[0] = delx * wprinv; + dW1[1] = dely * wprinv; + dW1[2] = delz * wprinv; - dW2[0] = -delx*wprinv; - dW2[1] = -dely*wprinv; - dW2[2] = -delz*wprinv; + dW2[0] = -delx * wprinv; + dW2[1] = -dely * wprinv; + dW2[2] = -delz * wprinv; return wp; } @@ -324,8 +298,8 @@ double ComputeRHEOKernel::calc_w_crk0(int i, int j, double delx, double dely, do w = calc_w_quintic(i,j,delx,dely,delz,r); - Wij = C0[i]*w; - Wji = C0[j]*w; + Wij = C0[i] * w; + Wji = C0[j] * w; return w; } @@ -344,17 +318,17 @@ double ComputeRHEOKernel::calc_w_crk1(int i, int j, double delx, double dely, do if (dim == 2) { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; } else { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - H[3] = dx[2]*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + H[3] = dx[2] * hinv; } Wij = 0; for (b = 0; b < Mdim; b++) { - Wij += C[i][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + Wij += C[i][0][b] * H[b]; // C columns: 1 x y (z) xx yy (zz) } Wij *= w; @@ -365,7 +339,7 @@ double ComputeRHEOKernel::calc_w_crk1(int i, int j, double delx, double dely, do Wji = 0; for (b = 0; b < Mdim; b++) { - Wji += C[j][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + Wji += C[j][0][b] * H[b]; // C columns: 1 x y (z) xx yy (zz) } Wji *= w; @@ -383,29 +357,28 @@ double ComputeRHEOKernel::calc_w_crk2(int i, int j, double delx, double dely, do dx[2] = delz; w = calc_w_quintic(i,j,delx,dely,delz,r); - if (dim == 2) { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - H[3] = 0.5*dx[0]*dx[0]*cutinv*cutinv; - H[4] = 0.5*dx[1]*dx[1]*cutinv*cutinv; - H[5] = dx[0]*dx[1]*cutinv*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + H[3] = 0.5 * dx[0] * dx[0] * hsqinv; + H[4] = 0.5 * dx[1] * dx[1] * hsqinv; + H[5] = dx[0] * dx[1] * hsqinv; } else { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - H[3] = dx[2]*cutinv; - H[4] = 0.5*dx[0]*dx[0]*cutinv*cutinv; - H[5] = 0.5*dx[1]*dx[1]*cutinv*cutinv; - H[6] = 0.5*dx[2]*dx[2]*cutinv*cutinv; - H[7] = dx[0]*dx[1]*cutinv*cutinv; - H[8] = dx[0]*dx[2]*cutinv*cutinv; - H[9] = dx[1]*dx[2]*cutinv*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + H[3] = dx[2] * hinv; + H[4] = 0.5 * dx[0] * dx[0] * hsqinv; + H[5] = 0.5 * dx[1] * dx[1] * hsqinv; + H[6] = 0.5 * dx[2] * dx[2] * hsqinv; + H[7] = dx[0] * dx[1] * hsqinv; + H[8] = dx[0] * dx[2] * hsqinv; + H[9] = dx[1] * dx[2] * hsqinv; } Wij = 0; for (b = 0; b < Mdim; b++) { - Wij += C[i][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + Wij += C[i][0][b] * H[b]; // C columns: 1 x y (z) xx yy (zz) } Wij *= w; @@ -416,7 +389,7 @@ double ComputeRHEOKernel::calc_w_crk2(int i, int j, double delx, double dely, do Wji = 0; for (b = 0; b < Mdim; b++) { - Wji += C[j][0][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + Wji += C[j][0][b] * H[b]; // C columns: 1 x y (z) xx yy (zz) } Wji *= w; @@ -434,24 +407,26 @@ void ComputeRHEOKernel::calc_dw_crk1(int i, int j, double delx, double dely, dou dx[2] = delz; w = calc_w_quintic(i,j,delx,dely,delz,r); + //Populate correction basis if (dim == 2) { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; } else { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - H[3] = dx[2]*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + H[3] = dx[2] * hinv; } + // dWij[] = dWx dWy (dWz) //compute derivative operators for (a = 0; a < dim; a++) { dW[a] = 0.0; for (b = 0; b < Mdim; b++) { //First derivative kernels - dW[a] += C[i][1+a][b]*H[b]; // C columns: 1 x y (z) + dW[a] += C[i][1 + a][b] * H[b]; // C columns: 1 x y (z) } dW[a] *= w; } @@ -473,22 +448,22 @@ void ComputeRHEOKernel::calc_dw_crk2(int i, int j, double delx, double dely, dou //Populate correction basis if (dim == 2) { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - H[3] = 0.5*dx[0]*dx[0]*cutinv*cutinv; - H[4] = 0.5*dx[1]*dx[1]*cutinv*cutinv; - H[5] = dx[0]*dx[1]*cutinv*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + H[3] = 0.5 * dx[0] * dx[0] * hsqinv; + H[4] = 0.5 * dx[1] * dx[1] * hsqinv; + H[5] = dx[0] * dx[1] * hsqinv; } else { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - H[3] = dx[2]*cutinv; - H[4] = 0.5*dx[0]*dx[0]*cutinv*cutinv; - H[5] = 0.5*dx[1]*dx[1]*cutinv*cutinv; - H[6] = 0.5*dx[2]*dx[2]*cutinv*cutinv; - H[7] = dx[0]*dx[1]*cutinv*cutinv; - H[8] = dx[0]*dx[2]*cutinv*cutinv; - H[9] = dx[1]*dx[2]*cutinv*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + H[3] = dx[2] * hinv; + H[4] = 0.5 * dx[0] * dx[0] * hsqinv; + H[5] = 0.5 * dx[1] * dx[1] * hsqinv; + H[6] = 0.5 * dx[2] * dx[2] * hsqinv; + H[7] = dx[0] * dx[1] * hsqinv; + H[8] = dx[0] * dx[2] * hsqinv; + H[9] = dx[1] * dx[2] * hsqinv; } // dWij[] = dWx dWy (dWz) @@ -497,7 +472,7 @@ void ComputeRHEOKernel::calc_dw_crk2(int i, int j, double delx, double dely, dou dW[a] = 0.0; for (b = 0; b < Mdim; b++) { //First derivative kernels - dW[a] += C[i][1+a][b]*H[b]; // C columns: 1 x y (z) xx yy (zz) + dW[a] += C[i][1 + a][b] * H[b]; // C columns: 1 x y (z) xx yy (zz) } dW[a] *= w; } @@ -510,21 +485,21 @@ void ComputeRHEOKernel::compute_peratom() gsl_error_flag = 0; gsl_error_tags.clear(); - int i, j, ii, jj, jnum, itype, jtype; - double xtmp, ytmp, ztmp, delx, dely, delz; - double r, rinv, rsq, imass, jmass; + int i, j, ii, jj, jnum, g, a, b, gsl_error; + double xtmp, ytmp, ztmp, r, rsq, w, vj; double dx[3]; - double w, wp, s, vi, vj, M, vjw; - double vjdw[3] = {0}; - bool sflag; + gsl_matrix_view gM; + + // Turn off GSL error handler, revert RK to Quintic when insufficient neighbors + gsl_set_error_handler_off(); double **x = atom->x; int *type = atom->type; double *mass = atom->mass; double *rho = atom->rho; - int *phase = atom->phase; + int *status = atom->status; + int *coordination = atom->ivector[index_coord]; tagint *tag = atom->tag; - coordination = atom->ivector[index_coord]; int inum, *ilist, *jlist, *numneigh, **firstneigh; inum = list->inum; @@ -532,17 +507,29 @@ void ComputeRHEOKernel::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - if (kernel_type == QUINTIC) { + // Grow arrays if necessary + int nmax = atom->nmax; + if (nmax_old < nmax) + memory->grow(coordination, nmax, "atom:rheo_coordination"); + if (kernel_type == FixRHEO::CRK0) { + memory->grow(C0, nmax, "rheo/kernel:C0"); + } else if (correction_order > 0) { + memory->grow(C, nmax, ncor, Mdim, "rheo/kernel:C"); + } + + nmax_old = atom->nmax; + } + + if (kernel_type == FixRHEO::QUINTIC) { for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; - ztmp = x[i][2]; // Will be ignored in 2D + ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; - itype = type[i]; coordination[i] = 0; for (jj = 0; jj < jnum; jj++) { @@ -552,42 +539,28 @@ void ComputeRHEOKernel::compute_peratom() dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; + rsq = lensq(dx); - rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; - r = sqrt(rsq); - rinv = 1/r; - - if (rsq < cutsq) { + if (rsq < hsq) { coordination[i] += 1; } } } + } else if (kernel_type == FixRHEO::CRK0) { - comm->forward_comm_compute(this); + double M; - } else if (kernel_type == CRK0) { - if (atom->nmax > nmax){ - nmax = atom->nmax; - memory->destroy(C0); - memory->create(C0, nmax, "rheo/kernel:C"); - } - - //The moment Matrix array has to be 1D to be compatible with gsl - // Solve linear system for each atom for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; - ztmp = x[i][2]; // Will be ignored in 2D + ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; - itype = type[i]; - //Initialize M and H to zero: + //Initialize M to zero: M = 0; - - //variable for insufficient neighbors coordination[i] = 0; for (jj = 0; jj < jnum; jj++) { @@ -597,85 +570,45 @@ void ComputeRHEOKernel::compute_peratom() dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; + rsq = lensq(dx); - rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; - r = sqrt(rsq); - rinv = 1/r; - - if (rsq < cutsq) { - //Compute Wij + if (rsq < hsq) { + r = sqrt(rsq); w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); - if (phase[j] > FixRHEO::FLUID_MAX && solid_flag) - vj = mass[type[j]]/compute_solids->correct_rho(j,i); - else vj = mass[type[j]]/rho[j]; - coordination[i] += 1; // Increment contributing neighbor + if (!(status[j] & FixRHEO::STATUS_FLUID) && solid_flag) { + vj = mass[type[j]] / compute_interface->correct_rho(j,i); + } else vj = mass[type[j]] / rho[j]; - M += w*vj; + coordination[i] += 1; + M += w * vj; } } - if (coordination[i] < N2min) continue; - //Get inverse of 1x1 matrix - M = 1.0/M; - C0[i] = M; + // Inverse of 1x1 matrix + if (coordination[i] >= zmin) C0[i] = 1.0 / M; } - - // communicate densities - maybe not needed for ghost atoms but just to be safe - // can remove in future once we determine they aren't necessary - comm->forward_comm_compute(this); - } else if (correction_order > 0) { - int i, j, ii, jj, jnum, itype, jtype; - int g, a, b, c, d, ib, ic, id, nperm; - double xtmp, ytmp, ztmp, delx, dely, delz; - double dx[3] = {0}; + // Moment matrix M and polynomial basis vector H (1d for gsl compatibility) + double H[Mdim], M[Mdim * Mdim]; - //Turn off GSL error handler so we can check and revert RK to Quintic - //when inssuficient neighbors - gsl_set_error_handler_off(); - - // Create Moment matrix M and polynomial basis vector H - //The moment Matrix array has to be 1D to be compatible with gsl - double H[Mdim], M[Mdim*Mdim]; - - if (atom->nmax > nmax){ - nmax = atom->nmax; - memory->destroy(C); - memory->create(C, nmax,ncor,Mdim, "rheo/kernel:C"); - } - - // Solve linear system for each atom for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; - ztmp = x[i][2]; // Will be ignored in 2D + ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; itype = type[i]; - //Initialize M and H to zero: + // Zero upper-triangle M and H (will be symmetric): for (a = 0; a < Mdim; a++) { for (b = a; b < Mdim; b++) { - //Just zero upper-triangle of M since it will be symmetric - M[a*Mdim+b] = 0; + M[a * Mdim + b] = 0; } } - //Zero moment - //variables for switching off RK caclulation if insufficient neighbors - sflag = 0; coordination[i] = 0; - // Loop over neighbors to populate elements of L - //m0[i] = 0.0; - - //Self contribution - //w = calc_w_quintic(i,i,0.,0.,0.,0.); - //m0[i] += w; - //vi = 1/vw[i]; - - vi = mass[type[i]]/rho[i]; // Overwritten if i is solid for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -685,94 +618,85 @@ void ComputeRHEOKernel::compute_peratom() dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]; - r = sqrt(rsq); - rinv = 1/r; + rsq = lensq(dx); if (rsq < cutsq) { - //Compute Wij + r = sqrt(rsq); w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); - //vj = 1/vw[j]; // - if (phase[i] > FixRHEO::FLUID_MAX && solid_flag) - vi = mass[type[i]]/compute_solids->correct_rho(i,j); - - if (phase[j] > FixRHEO::FLUID_MAX && solid_flag) - vj = mass[type[j]]/compute_solids->correct_rho(j,i); + if (status[j] > FixRHEO::FLUID_MAX && solid_flag) + vj = mass[type[j]]/compute_interface->correct_rho(j,i); else vj = mass[type[j]]/rho[j]; - //m0[i] += w; //Populate the H-vector of polynomials (2D) if (dim == 2) { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - if (kernel_type == CRK2) { - H[3] = 0.5*dx[0]*dx[0]*cutinv*cutinv; - H[4] = 0.5*dx[1]*dx[1]*cutinv*cutinv; - H[5] = dx[0]*dx[1]*cutinv*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + if (kernel_type == FixRHEO::CRK2) { + H[3] = 0.5 * dx[0] * dx[0] * hsqinv; + H[4] = 0.5 * dx[1] * dx[1] * hsqinv; + H[5] = dx[0] * dx[1] * hsqinv; } } else { H[0] = 1.0; - H[1] = dx[0]*cutinv; - H[2] = dx[1]*cutinv; - H[3] = dx[2]*cutinv; - if (kernel_type == CRK2) { - H[4] = 0.5*dx[0]*dx[0]*cutinv*cutinv; - H[5] = 0.5*dx[1]*dx[1]*cutinv*cutinv; - H[6] = 0.5*dx[2]*dx[2]*cutinv*cutinv; - H[7] = dx[0]*dx[1]*cutinv*cutinv; - H[8] = dx[0]*dx[2]*cutinv*cutinv; - H[9] = dx[1]*dx[2]*cutinv*cutinv; + H[1] = dx[0] * hinv; + H[2] = dx[1] * hinv; + H[3] = dx[2] * hinv; + if (kernel_type == FixRHEO::CRK2) { + H[4] = 0.5 * dx[0] * dx[0] * hsqinv; + H[5] = 0.5 * dx[1] * dx[1] * hsqinv; + H[6] = 0.5 * dx[2] * dx[2] * hsqinv; + H[7] = dx[0] * dx[1] * hsqinv; + H[8] = dx[0] * dx[2] * hsqinv; + H[9] = dx[1] * dx[2] * hsqinv; } } - coordination[i] += 1; // Increment contributing neighbor - //Populate the upper triangle of the + coordination[i] += 1; + + // Populate the upper triangle for (a = 0; a < Mdim; a++) { for (b = a; b < Mdim; b++) { - M[a*Mdim+b] += H[a]*H[b]*w*vj; + M[a * Mdim + b] += H[a] * H[b] * w * vj; } } } } - //Now populate the lower triangle from the symmetric entries of M: + + // Populate the lower triangle from the symmetric entries of M: for (a = 0; a < Mdim; a++) { for (b = a; b < Mdim; b++) { - M[b*Mdim+a] = M[a*Mdim+b]; + M[b * Mdim + a] = M[a * Mdim + b]; } } - if (coordination[i] < N2min) continue; + // Skip if undercoordinated + if (coordination[i] < zmin) continue - //Use gsl to get Minv - //Since the polynomials are independent, M is symmetrix & positive-definite - //So we will use a Cholesky decomposition - gsl_matrix_view gM = gsl_matrix_view_array(M,Mdim,Mdim); - int status; - status = 0; - //gsl_linalg_cholesky_decomp1 -> gsl_linalg_cholesky_decomp - //So I don't have to update my gsl (me being lazy, can revert) - status = gsl_linalg_cholesky_decomp(&gM.matrix); //M is now the cholesky decomposition of M - // check if erro in inversion - if (status) { + // Use gsl to get Minv, use Cholesky decomposition since the + // polynomials are independent, M is symmetrix & positive-definite + gM = gsl_matrix_view_array(M,Mdim,Mdim); + gsl_error = gsl_linalg_cholesky_decomp(&gM.matrix); + + if (gsl_error) { //Revert to uncorrected SPH for this particle gsl_error_flag = 1; gsl_error_tags.insert(tag[i]); //check if not positive-definite - if (status != GSL_EDOM) - fprintf(stderr, "failed, gsl_errno=%d.n", status); + if (gsl_error != GSL_EDOM) + error->warn(FLERR, "Failed decomposition in rheo/kernel, gsl_error = {}", gsl_error); continue; - } else { - gsl_linalg_cholesky_invert(&gM.matrix); //M is now M^-1 } - // Correction coefficients are just the columns of M^-1 multiplied by an appropriate coefficient - //Solve the linear system several times to get coefficientns + gsl_linalg_cholesky_invert(&gM.matrix); //M is now M^-1 + + // Correction coefficients are columns of M^-1 multiplied by an appropriate coefficient + // Solve the linear system several times to get coefficientns // M: 1 x y (z) x^2 y^2 (z^2) xy (xz) (yz) - //---------------------------------------------------------- + // ---------------------------------------------------------- // 0 1 2 3 4 5 || 2D indexing // 0 1 2 3 4 5 6 7 8 9 || 3D indexing // W 1 . . . . . . . . . @@ -786,25 +710,25 @@ void ComputeRHEOKernel::compute_peratom() //0 1 2 3 4 //0 1 2 3 4 5 6 - // Use coefficents to compute smoothed density - //Pack coefficients into C + // Pack coefficients into C for (a = 0; a < Mdim; a++) { - //W - C[i][0][a] = M[a*Mdim + 0]; // all rows of column 0 + C[i][0][a] = M[a * Mdim + 0]; // all rows of column 0 for (b = 0; b < dim; b++) { //First derivatives - C[i][1+b][a] = -M[a*Mdim + b+1]/cut; // columns 1-2 (2D) or 1-3 (3D) + C[i][1 + b][a] = -M[a * Mdim + b + 1] * hinv; + // columns 1-2 (2D) or 1-3 (3D) + //Second derivatives - if (kernel_type == CRK2) - C[i][1+dim+b][a] = M[a*Mdim + b+1+dim]/cutsq; // columns 3-4 (2D) or 4-6 (3D) + if (kernel_type == FixRHEO::CRK2) + C[i][1 + dim + b][a] = M[a * Mdim + b + 1 + dim] * hsqinv; + // columns 3-4 (2D) or 4-6 (3D) } } } - - // communicate densities - maybe not needed for ghost atoms but just to be safe - // can remove in future once we determine they aren't necessary - comm->forward_comm_compute(this); } + + // communicate calculated quantities + comm->forward_comm_compute(this); } /* ---------------------------------------------------------------------- */ @@ -825,7 +749,7 @@ int ComputeRHEOKernel::pack_forward_comm(int n, int *list, double *buf, } buf[m++] = coordination[j]; } - } else if (kernel_type == CRK0) { + } else if (kernel_type == FixRHEO::CRK0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = C0[j]; @@ -857,7 +781,7 @@ void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) } coordination[i] = buf[m++]; } - } else if (kernel_type == CRK0) { + } else if (kernel_type == FixRHEO::CRK0) { for (i = first; i < last; i++) { C0[i] = buf[m++]; coordination[i] = buf[m++]; diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 114f39e85e..346df5a20c 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -21,6 +21,7 @@ ComputeStyle(rheo/kernel,ComputeRHEOKernel) #define LMP_COMPUTE_RHEO_KERNEL_H #include "compute.h" +#include namespace LAMMPS_NS { @@ -45,15 +46,16 @@ class ComputeRHEOKernel : public Compute { private: int solid_flag; int gsl_error_flag; + std::unordered_set gsl_error_tags; - int kernel_type, N2min, nmax, Mdim, ncor; + int kernel_style, zmin, dim, Mdim, ncor; int nmax_old, index_coord; - double cut, cutsq, cutinv, h, ih, ihsq, pre_w, pre_wp; + double h, hsq, hinv, hsqinv, pre_w, pre_wp; double ***C; double *C0; class NeighList *list; - class ComputeRHEOSolids *compute_solids; + class ComputeRHEOInterface *compute_interface; class FixRHEO *fix_rheo; int check_corrections(int); From bfb3457b9e1dfab7fedd6e4c328318914f38302b Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 26 Mar 2023 14:44:01 -0600 Subject: [PATCH 019/385] Adding memory usage --- src/RHEO/compute_rheo_kernel.cpp | 15 +++++++++++++++ src/RHEO/fix_rheo_pressure.cpp | 11 ++++++++++- src/RHEO/fix_rheo_pressure.h | 1 + src/RHEO/fix_rheo_thermal.cpp | 9 +++++++++ src/RHEO/fix_rheo_thermal.h | 1 + src/RHEO/fix_rheo_viscosity.cpp | 9 +++++++++ src/RHEO/fix_rheo_viscosity.h | 1 + 7 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 62a4283977..a3f7ed3da5 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -792,3 +792,18 @@ void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) } } } + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::memory_usage() +{ + double bytes = 0.0; + bytes = (size_t) atom->nmax * sizeof(int); + + if (kernel_type == FixRHEO::CRK0) { + bytes += (size_t) atom->nmax * sizeof(double); + } else if (correction_order > 0) { + bytes += (size_t) atom->nmax * ncor * Mdim * sizeof(double); + } + return bytes; +} diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index e4c1c44163..0a92e10767 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -203,4 +203,13 @@ double FixRHEOPressure::calculate_p(double rho) p = csq * rho0 * inv7 * (rr3 * rr3 * rho_ratio - 1.0); } return rho; -} \ No newline at end of file +} + +/* ---------------------------------------------------------------------- */ + +double FixRHEOPressure::memory_usage() +{ + double bytes = 0.0; + bytes += (size_t) atom->nmax * sizeof(double); + return bytes; +} diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index 6c7ee73370..8272cc38f5 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -34,6 +34,7 @@ class FixRHEOPressure : public Fix { void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; + double memory_usage() override; double calculate_p(double); private: double c_cubic, csq, rho0, rho0inv; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 8b0c9e46de..c8171f9beb 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -432,3 +432,12 @@ void FixRHEOThermal::unpack_reverse_comm(int n, int *list, double *buf) for (int i = 0; i < n; i++) heatflow[list[i]] += buf[m++]; } + +/* ---------------------------------------------------------------------- */ + +double FixRHEOThermal::memory_usage() +{ + double bytes = 0.0; + bytes += (size_t) atom->nmax * sizeof(double); + return bytes; +} diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index d9a17ebd60..3b62e86fa8 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -41,6 +41,7 @@ class FixRHEOThermal : public Fix { void unpack_forward_comm(int, int, double *) override; int pack_reverse_comm(int, int, double *) override; void unpack_reverse_comm(int, int *, double *) override; + double memory_usage() override; private: double *cv_type, cv; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 2b63c7633b..d81a1e9b4f 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -250,3 +250,12 @@ void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) viscosity[i] = buf[m++]; } } + +/* ---------------------------------------------------------------------- */ + +double FixRHEOViscosity::memory_usage() +{ + double bytes = 0.0; + bytes += (size_t) atom->nmax * sizeof(double); + return bytes; +} diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index d531507a72..407170f668 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -35,6 +35,7 @@ class FixRHEOViscosity : public Fix { void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; + double memory_usage() override; private: double *eta_type, eta; From 79ddd1445f051fdc7c78bb03123855a94bef2ad9 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 26 Mar 2023 17:04:56 -0600 Subject: [PATCH 020/385] Misc clean ups, initial draft of interface --- src/RHEO/atom_vec_rheo.cpp | 5 + src/RHEO/compute_rheo_grad.cpp | 27 +- src/RHEO/compute_rheo_grad.h | 1 + src/RHEO/compute_rheo_interface.cpp | 432 ++++++++++++++++++++++++++++ src/RHEO/compute_rheo_interface.h | 61 ++++ src/RHEO/compute_rheo_kernel.cpp | 29 +- src/RHEO/compute_rheo_vshift.cpp | 95 +++--- src/RHEO/compute_rheo_vshift.h | 7 +- src/RHEO/fix_rheo.cpp | 9 +- src/RHEO/fix_rheo_pressure.cpp | 11 +- src/RHEO/fix_rheo_thermal.cpp | 11 +- src/RHEO/fix_rheo_viscosity.cpp | 11 +- src/RHEO/pair_rheo.cpp | 5 + 13 files changed, 634 insertions(+), 70 deletions(-) create mode 100644 src/RHEO/compute_rheo_interface.cpp create mode 100644 src/RHEO/compute_rheo_interface.h diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp index 9effad685c..a8496a18e9 100644 --- a/src/RHEO/atom_vec_rheo.cpp +++ b/src/RHEO/atom_vec_rheo.cpp @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + #include "atom_vec_rheo.h" #include "atom.h" diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index ce351048be..03e76b194a 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + #include "compute_rheo_grad.h" #include "atom.h" @@ -457,4 +462,24 @@ void ComputeRHEOGrad::grow_arrays(int nmax) if (eta_flag) memory->grow(gradn, nmax, dim, "atom:rheo_grad_eta"); nmax_old = nmax; -} \ No newline at end of file +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::memory_usage() +{ + double bytes = 0.0; + if (velocity_flag) + bytes = (size_t) nmax_old * dim * dim * sizeof(double); + + if (rho_flag) + bytes = (size_t) nmax_old * dim * sizeof(double); + + if (temperature_flag) + bytes = (size_t) nmax_old * dim * sizeof(double); + + if (eta_flag) + bytes = (size_t) nmax_old * dim * sizeof(double); + + return bytes; +} diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 220b5813e3..d86efe47ee 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -35,6 +35,7 @@ class ComputeRHEOGrad : public Compute { void unpack_forward_comm(int, int, double *) override; int pack_reverse_comm(int, int, double *) override; void unpack_reverse_comm(int, int *, double *) override; + double memory_usage() override; void forward_gradients(); void forward_fields(); double **gradv; diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp new file mode 100644 index 0000000000..e76e46d422 --- /dev/null +++ b/src/RHEO/compute_rheo_interface.cpp @@ -0,0 +1,432 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + +#include "compute_rheo_interface.h" + +#include "fix_rheo.h" +#include "compute_rheo_kernel.h" +#include "fix_store.h" +#include "fix.h" +#include +#include +#include "atom.h" +#include "update.h" +#include "modify.h" +#include "domain.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "force.h" +#include "pair.h" +#include "comm.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +#define EPSILON 1e-1 + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOInterface::ComputeRHEOInterface(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), + id_fix_chi(nullptr) +{ + if (narg != 4) error->all(FLERR,"Illegal compute RHEO/chi command"); + + cut = utils::numeric(FLERR,arg[3],false,lmp); + cutsq = cut*cut; + + wall_max = sqrt(3)/12.0*cut; + + nmax = 0; + + comm_forward = 3; + comm_reverse = 4; + + fix_chi = nullptr; + norm = nullptr; + normwf = nullptr; + + // new id = fix-ID + FIX_STORE_ATTRIBUTE + // new fix group = group for this fix + + id_fix_chi = nullptr; + std::string fixcmd = id + std::string("_chi"); + id_fix_chi = new char[fixcmd.size()+1]; + strcpy(id_fix_chi,fixcmd.c_str()); + fixcmd += fmt::format(" all STORE peratom 0 {}", 1); + modify->add_fix(fixcmd); + fix_chi = (FixStore *) modify->fix[modify->nfix-1]; + chi = fix_chi->vstore; +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOInterface::~ComputeRHEOInterface() +{ + if (id_fix_chi && modify->nfix) modify->delete_fix(id_fix_chi); + if (modify->nfix) modify->delete_fix("PROPERTY_ATOM_COMP_RHEO_SOLIDS"); + + memory->destroy(norm); + memory->destroy(normwf); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOInterface::init() +{ + // need an occasional full neighbor list + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->pair = 0; + neighbor->requests[irequest]->compute = 1; + neighbor->requests[irequest]->half = 1; + neighbor->requests[irequest]->full = 0; + //neighbor->requests[irequest]->occasional = 1; //Anticipate needing regulalry + + int icompute = modify->find_compute("rheo_kernel"); + if (icompute == -1) error->all(FLERR, "Using compute/RHEO/chi without compute/RHEO/kernel"); + + compute_kernel = ((ComputeRHEOKernel *) modify->compute[icompute]); + + //Store persistent per atom quantities - need to be exchanged + char **fixarg = new char*[8]; + fixarg[0] = (char *) "PROPERTY_ATOM_COMP_RHEO_SOLIDS"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "property/atom"; + fixarg[3] = (char *) "d_fx"; + fixarg[4] = (char *) "d_fy"; + fixarg[5] = (char *) "d_fz"; + fixarg[6] = (char *) "ghost"; + fixarg[7] = (char *) "yes"; + modify->add_fix(8,fixarg,1); + delete [] fixarg; + + int temp_flag; + index_fx = atom->find_custom("fx", temp_flag); + if ((index_fx < 0) || (temp_flag != 1)) + error->all(FLERR, "Compute rheo/solids can't find fix property/atom fx"); + index_fy = atom->find_custom("fy", temp_flag); + if ((index_fy < 0) || (temp_flag != 1)) + error->all(FLERR, "Compute rheo/solids can't find fix property/atom fy"); + index_fz = atom->find_custom("fz", temp_flag); + if ((index_fz < 0) || (temp_flag != 1)) + error->all(FLERR, "Compute rheo/solids can't find fix property/atom fz"); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOInterface::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOInterface::compute_peratom() +{ + int i, j, ii, jj, jnum, itype, jtype, phase_match; + double xtmp, ytmp, ztmp, delx, dely, delz, rsq; + int *jlist; + double w; + + // neighbor list ariables + int inum, *ilist, *numneigh, **firstneigh; + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + double **x = atom->x; + int *type = atom->type; + int newton = force->newton; + int *phase = atom->phase; + double *rho = atom->rho; + double *fx = atom->dvector[index_fx]; + double *fy = atom->dvector[index_fy]; + double *fz = atom->dvector[index_fz]; + double mi, mj; + + //Declare mass pointer to calculate acceleration from force + double *mass = atom->mass; + + cs2 = 1.0; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + if (atom->nmax > nmax) { + nmax = atom->nmax; + fix_chi->grow_arrays(nmax); + chi = fix_chi->vstore; + memory->destroy(norm); + memory->destroy(normwf); + memory->create(norm, nmax, "RHEO/chi:norm"); + memory->create(normwf, nmax, "RHEO/chi:normwf"); + } + + for (i = 0; i < nall; i++) { + if (phase[i] > FixRHEO::FLUID_MAX) rho[i] = 0.0; + normwf[i] = 0.0; + norm[i] = 0.0; + chi[i] = 0.0; + } + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + mi = mass[type[i]]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + + if (rsq < cutsq) { + jtype = type[j]; + mj = mass[type[j]]; + w = compute_kernel->calc_w_quintic(i, j, delx, dely, delz, sqrt(rsq)); + + phase_match = 0; + norm[i] += w; + if ((phase[i] <= FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) + || (phase[i] > FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX)) { + phase_match = 1; + } + + if (phase_match) { + chi[i] += w; + } else { + if (phase[i] > FixRHEO::FLUID_MAX) { + //speed of sound and rho0 assumed to = 1 (units in density not pressure) + //In general, rho is calculated using the force vector on the wall particle + //fx stores f-fp + rho[i] += w*(cs2*(rho[j] - 1.0) - rho[j]*((-fx[j]/mj+fx[i]/mi)*delx + (-fy[j]/mj+fy[i]/mi)*dely + (-fz[j]/mj+fz[i]/mi)*delz)); + //For the specific taste case whre force on wall particles = 0 + //rho[i] += w*(1.0*(rho[j] - 1.0) + rho[j]*(1e-3*delx)); + normwf[i] += w; + } + } + + if (newton || j < nlocal) { + norm[j] += w; + if (phase_match) { + chi[j] += w; + } else { + if (phase[j] > FixRHEO::FLUID_MAX) { + rho[j] += w*(cs2*(rho[i] - 1.0) + rho[i]*((-fx[i]/mi+fx[j]/mj)*delx + (-fy[i]/mi+fy[j]/mj)*dely + (-fz[i]/mi+fz[j]/mj)*delz)); + normwf[j] += w; + } + } + } + } + } + } + + if (newton) comm->reverse_comm_compute(this); + + for (i = 0; i < nlocal; i++) { + if (norm[i] != 0.0) chi[i] /= norm[i]; + if (normwf[i] != 0.0) { // Only if it's a wall particle + rho[i] = 1.0 + (rho[i] / normwf[i])/cs2; // Stores rho for solid particles 1+Pw in Adami Adams 2012 + if (rho[i] < EPSILON) rho[i] = EPSILON; + } + + if (normwf[i] == 0.0 && phase[i] > FixRHEO::FLUID_MAX) rho[i] = 1.0; + } + + comm_stage = 1; + comm_forward = 2; + comm->forward_comm_compute(this); +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOInterface::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,k,m; + m = 0; + double *rho = atom->rho; + double *fx = atom->dvector[index_fx]; + double *fy = atom->dvector[index_fy]; + double *fz = atom->dvector[index_fz]; + + for (i = 0; i < n; i++) { + j = list[i]; + if (comm_stage == 0) { + buf[m++] = fx[j]; + buf[m++] = fy[j]; + buf[m++] = fz[j]; + } else { + buf[m++] = chi[j]; + buf[m++] = rho[j]; + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOInterface::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double *rho = atom->rho; + double *fx = atom->dvector[index_fx]; + double *fy = atom->dvector[index_fy]; + double *fz = atom->dvector[index_fz]; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (comm_stage == 0) { + fx[i] = buf[m++]; + fy[i] = buf[m++]; + fz[i] = buf[m++]; + } else { + chi[i] = buf[m++]; + rho[i] = buf[m++]; // Won't do anything for fluids + } + } +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOInterface::pack_reverse_comm(int n, int first, double *buf) +{ + int i,k,m,last; + double *rho = atom->rho; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = norm[i]; + buf[m++] = chi[i]; + buf[m++] = normwf[i]; + buf[m++] = rho[i]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i,k,j,m; + double *rho = atom->rho; + int *phase = atom->phase; + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + norm[j] += buf[m++]; + chi[j] += buf[m++]; + if (phase[j] > FixRHEO::FLUID_MAX){ + normwf[j] += buf[m++]; + rho[j] += buf[m++]; + } else { + m++; + m++; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOInterface::correct_v(double *vi, double *vj, double *vi_out, int i, int j) +{ + double wall_prefactor, wall_denom, wall_numer; + + wall_numer = 2.0*cut*(chi[i]-0.5); + if (wall_numer < 0) wall_numer = 0; + wall_denom = 2.0*cut*(chi[j]-0.5); + if (wall_denom < wall_max) wall_denom = wall_max; + + wall_prefactor = wall_numer / wall_denom; + + vi_out[0] = (vi[0]-vj[0])*wall_prefactor + vi[0]; + vi_out[1] = (vi[1]-vj[1])*wall_prefactor + vi[1]; + vi_out[2] = (vi[2]-vj[2])*wall_prefactor + vi[2]; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOInterface::correct_rho(int i, int j) // i is wall, j is fluid +{ + //In future may depend on atom type j's pressure equation + return atom->rho[i]; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOInterface::store_forces() +{ + double *fx = atom->dvector[index_fx]; + double *fy = atom->dvector[index_fy]; + double *fz = atom->dvector[index_fz]; + double **f = atom->f; + double **fp = atom->fp; + int *mask = atom->mask; + + int flag; + int ifix = modify->find_fix_by_style("setforce"); + if (ifix != -1) { + for (int i = 0; i < atom->nlocal; i++) { + if (mask[i] & modify->fix[ifix]->groupbit) { + fx[i] = f[i][0]; + fy[i] = f[i][1]; + fz[i] = f[i][2]; + } else { + fx[i] = f[i][0] - fp[i][0]; + fy[i] = f[i][1] - fp[i][1]; + fz[i] = f[i][2] - fp[i][2]; + } + } + } else { + for (int i = 0; i < atom->nlocal; i++) { + fx[i] = f[i][0] - fp[i][0]; + fy[i] = f[i][1] - fp[i][1]; + fz[i] = f[i][2] - fp[i][2]; + } + } + + //Forward comm forces -note only needed here b/c property atom will forward otherwise + comm_forward = 3; + comm_stage = 0; + comm->forward_comm_compute(this); +} + + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeRHEOInterface::memory_usage() +{ + double bytes = nmax * sizeof(double); + return bytes; +} + diff --git a/src/RHEO/compute_rheo_interface.h b/src/RHEO/compute_rheo_interface.h new file mode 100644 index 0000000000..635f190aed --- /dev/null +++ b/src/RHEO/compute_rheo_interface.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(rheo/interface,ComputeRHEOInterface) +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_INTERFACE_H +#define LMP_COMPUTE_RHEO_INTERFACE_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEOInterface : public Compute { + public: + ComputeRHEOInterface(class LAMMPS *, int, char **); + ~ComputeRHEOInterface(); + void init(); + void init_list(int, class NeighList *); + void compute_peratom(); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + int pack_reverse_comm(int, int, double *); + void unpack_reverse_comm(int, int *, double *); + void correct_v(double *, double *, double *, int, int); + double correct_rho(int, int); + double memory_usage(); + void store_forces(); + double *chi; + + private: + int nmax; + double cut, cutsq, cs2; + class NeighList *list; + double *norm, *normwf, wall_max; + + class ComputeRHEOKernel *compute_kernel; + char *id_fix_chi; + class FixStore *fix_chi; + + int index_fx, index_fy, index_fz; + int comm_stage; +}; + +} + +#endif +#endif diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index a3f7ed3da5..15b5f9568b 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -1,15 +1,20 @@ /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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. + 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. -------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ #include "compute_rheo_kernel.h" @@ -798,12 +803,12 @@ void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) double ComputeRHEOKernel::memory_usage() { double bytes = 0.0; - bytes = (size_t) atom->nmax * sizeof(int); + bytes = (size_t) nmax_old * sizeof(int); if (kernel_type == FixRHEO::CRK0) { - bytes += (size_t) atom->nmax * sizeof(double); + bytes += (size_t) nmax_old * sizeof(double); } else if (correction_order > 0) { - bytes += (size_t) atom->nmax * ncor * Mdim * sizeof(double); + bytes += (size_t) nmax_old * ncor * Mdim * sizeof(double); } return bytes; } diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 42fa1e8c82..2b7c9394d3 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -1,35 +1,36 @@ /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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. + 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. -------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ #include "compute_rheo_vshift.h" -#include "fix_rheo.h" -#include "compute_rheo_solids.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_interface.h" #include "compute_rheo_grad.h" #include "compute_rheo_kernel.h" -#include "fix_rheo_surface.h" -#include -#include -#include "atom.h" -#include "modify.h" #include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "memory.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" -#include "force.h" -#include "pair.h" -#include "comm.h" -#include "memory.h" -#include "error.h" using namespace LAMMPS_NS; @@ -44,18 +45,28 @@ ComputeRHEOVShift::ComputeRHEOVShift(LAMMPS *lmp, int narg, char **arg) : comm_reverse = 3; surface_flag = 0; - nmax = atom->nmax; - memory->create(vshift, nmax, 3, "rheo/vshift:vshift"); - array_atom = vshift; - peratom_flag = 1; - size_peratom_cols = 3; + // Create vshift array if it doesn't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded + + int tmp1, tmp2; + index_vshift = atom->find_custom("rheo_vshift", tmp1, tmp2); + if (index_vshift == -1) { + index_vshift = atom->add_custom("rheo_vshift", 1, 3); + nmax_old = atom->nmax; + } } /* ---------------------------------------------------------------------- */ ComputeRHEOVShift::~ComputeRHEOVShift() { - memory->destroy(vshift); + // Remove custom property if it exists + int tmp1, tmp2, index; + index = atom->find_custom("rheo_vshift", tmp1, tmp2); + if (index != -1) atom->remove_custom(index_vshift, 1, 3); + } /* ---------------------------------------------------------------------- */ @@ -65,10 +76,8 @@ void ComputeRHEOVShift::init() neighbor->add_request(this, NeighConst::REQ_DEFAULT); surface_flag = 0; - if (fix_rheo->surface_flag) { + if (fix_rheo->surface_flag) surface_flag = 1; - fix_rheo_surface = fix_rheo->fix_rheo_surface; - } compute_kernel = fix_rheo->compute_kernel; compute_grad = fix_rheo->compute_grad; @@ -110,6 +119,7 @@ void ComputeRHEOVShift::compute_peratom() int *surface = atom->surface; double *rho = atom->rho; double *mass = atom->mass; + double **vshift = atom->darray[index_vshift]; int newton_pair = force->newton_pair; inum = list->inum; @@ -117,12 +127,10 @@ void ComputeRHEOVShift::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - if (nall > nmax) { - nmax = nall; - memory->destroy(vshift); - memory->create(vshift, nmax, 3, "rheo/vshift:vshift"); - array_atom = vshift; - } + + if (nmax_old < atom->nmax) + memory->grow(vshift, atom->nmax, 3, "atom:rheo_vshift"); + nmax_old = atom->nmax; for (i = 0; i < nall; i++) for (a = 0; a < dim; a++) @@ -224,14 +232,17 @@ void ComputeRHEOVShift::correct_surfaces() int nlocal = atom->nlocal; int i, a, b; int dim = domain->dimension; - int *surface = atom->surface; + double **vshift = atom->darray[index_vshift]; + + int tmp1, tmp2; + int index_nsurf = atom->find_custom("rheo_nsurf", tmp1, tmp2); + if (index_nsurf == -1) error->all(FLERR, "Cannot find rheo nsurf"); + double **nsurf = atom->darray[index_nsurf]; - double **nsurf; - nsurf = fix_rheo_surface->n_surface; double nx,ny,nz,vx,vy,vz; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { - if (surface[i] == 1 || surface[i] == 2) { + if ((surface[i] & FixRHEO::STATUS_SURFACE) || (surface[i] & FixRHEO::STATUS_LAYER)) { nx = nsurf[i][0]; ny = nsurf[i][1]; vx = vshift[i][0]; @@ -257,6 +268,7 @@ void ComputeRHEOVShift::correct_surfaces() int ComputeRHEOVShift::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; + double **vshift = atom->darray[index_vshift]; m = 0; last = first + n; @@ -273,6 +285,7 @@ int ComputeRHEOVShift::pack_reverse_comm(int n, int first, double *buf) void ComputeRHEOVShift::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; + double **vshift = atom->darray[index_vshift]; m = 0; for (i = 0; i < n; i++) { @@ -289,6 +302,6 @@ void ComputeRHEOVShift::unpack_reverse_comm(int n, int *list, double *buf) double ComputeRHEOVShift::memory_usage() { - double bytes = 3 * nmax * sizeof(double); + double bytes = 3 * nmax_old * sizeof(double); return bytes; } diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h index fceb287510..f93cced31c 100644 --- a/src/RHEO/compute_rheo_vshift.h +++ b/src/RHEO/compute_rheo_vshift.h @@ -37,15 +37,12 @@ class ComputeRHEOVShift : public Compute { void correct_surfaces(); private: - int nmax; + int nmax_old; double dtv, cut, cutsq, cutthird; - int surface_flag; - - double **vshift; + int surface_flag, index_vshift; class NeighList *list; class FixRHEO *fix_rheo; - class FixRHEOSurface *fix_rheo_surface; class ComputeRHEOInterface *compute_interface ; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOGrad *compute_grad; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 6d16bf2782..25a97bd52a 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -1,7 +1,7 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + #include "fix_rheo.h" #include "atom.h" diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 0a92e10767..4fa4ece0f9 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -1,7 +1,7 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + #include "fix_rheo_pressure.h" #include "atom.h" @@ -210,6 +215,6 @@ double FixRHEOPressure::calculate_p(double rho) double FixRHEOPressure::memory_usage() { double bytes = 0.0; - bytes += (size_t) atom->nmax * sizeof(double); + bytes += (size_t) nmax_old * sizeof(double); return bytes; } diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index c8171f9beb..3ef9fab853 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -1,7 +1,7 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + #include "fix_rheo_thermal.h" #include "atom.h" @@ -438,6 +443,6 @@ void FixRHEOThermal::unpack_reverse_comm(int n, int *list, double *buf) double FixRHEOThermal::memory_usage() { double bytes = 0.0; - bytes += (size_t) atom->nmax * sizeof(double); + bytes += (size_t) nmax_old * sizeof(double); return bytes; } diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index d81a1e9b4f..3f779aa3c6 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -1,7 +1,7 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + #include "fix_rheo_viscosity.h" #include "atom.h" @@ -256,6 +261,6 @@ void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) double FixRHEOViscosity::memory_usage() { double bytes = 0.0; - bytes += (size_t) atom->nmax * sizeof(double); + bytes += (size_t) nmax_old * sizeof(double); return bytes; } diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 0fed0297b4..7d5d0f425f 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + #include "pair_rheo.h" #include "atom.h" From 986cfd66414da8a9cf7cc4a09a19cf1f44a94dae Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 12 Apr 2023 17:05:05 -0600 Subject: [PATCH 021/385] Cleaning up peratom variables, adding peratom variables to fix rheo/interface --- src/RHEO/compute_rheo_grad.cpp | 72 +++++++++++------ src/RHEO/compute_rheo_grad.h | 2 - src/RHEO/compute_rheo_interface.cpp | 121 ++++++++++++---------------- src/RHEO/compute_rheo_interface.h | 39 +++++---- src/RHEO/compute_rheo_kernel.cpp | 16 ++-- src/RHEO/compute_rheo_kernel.h | 3 +- src/RHEO/compute_rheo_vshift.cpp | 21 ++--- src/RHEO/compute_rheo_vshift.h | 4 +- src/RHEO/fix_rheo.cpp | 5 +- src/RHEO/fix_rheo.h | 1 + src/RHEO/fix_rheo_pressure.cpp | 16 ++-- src/RHEO/fix_rheo_pressure.h | 3 +- src/RHEO/fix_rheo_thermal.cpp | 12 +-- src/RHEO/fix_rheo_thermal.h | 3 +- src/RHEO/fix_rheo_viscosity.cpp | 11 +-- src/RHEO/fix_rheo_viscosity.h | 3 +- src/RHEO/pair_rheo.cpp | 30 ++++--- src/RHEO/pair_rheo.h | 2 +- 18 files changed, 184 insertions(+), 180 deletions(-) diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 03e76b194a..31f60550c1 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -38,7 +38,7 @@ enum{COMMGRAD, COMMFIELD}; /* ---------------------------------------------------------------------- */ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), compute_interface(nullptr), compute_kernel(nullptr), + Compute(lmp, narg, arg), fix_rheo(nullptr), compute_interface(nullptr), compute_kernel(nullptr), gradv(nullptr), gradr(nullptr), gradt(nullptr), gradn(nullptr) { if (narg < 4) error->all(FLERR,"Illegal compute rheo/grad command"); @@ -61,40 +61,26 @@ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : ncomm_grad += dim * dim; ncomm_field += dim; comm_reverse += dim * dim; - indexv = atom->add_custom("rheo_grad_v", 1, dim * dim); - gradv = atom->darray[indexv]; } if (rho_flag) { ncomm_grad += dim; ncomm_field += 1; comm_reverse += dim; - indexr = atom->add_custom("rheo_grad_rho", 1, dim); - gradr = atom->darray[indexr]; } if (temperature_flag) { ncomm_grad += dim; ncomm_field += 1; comm_reverse += dim; - indext= atom->add_custom("rheo_grad_temp", 1, dim); - gradt = atom->darray[indext]; } if (eta_flag) { ncomm_grad += dim; comm_reverse += dim; - indexn = atom->add_custom("rheo_grad_eta", 1, dim); - gradn = atom->darray[indexn]; } - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded - comm_forward = ncomm_grad; - nmax_old = 0; - grow_arrays(atom->nmax); } /* ---------------------------------------------------------------------- */ @@ -102,14 +88,16 @@ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : ComputeRHEOGrad::~ComputeRHEOGrad() { int dim = domain->dimension; - if (velocity_flag) - atom->remove_custom(indexv, 1, dim * dim); - if (rho_flag) - atom->remove_custom(indexr, 1, dim); - if (temperature_flag) - atom->remove_custom(indext, 1, dim); - if (eta_flag) - atom->remove_custom(indexn, 1, dim); + int tmp1, tmp2, index; + + index = atom->find_custom("rheo_grad_v", tmp1, tmp2); + if (index != 1) atom->remove_custom(index, 1, dim * dim); + index = atom->find_custom("rheo_grad_rho", tmp1, tmp2); + if (index != 1) atom->remove_custom(index, 1, dim); + index = atom->find_custom("rheo_grad_t", tmp1, tmp2); + if (index != 1) atom->remove_custom(index, 1, dim); + index = atom->find_custom("rheo_grad_eta", tmp1, tmp2); + if (index != 1) atom->remove_custom(index, 1, dim); } /* ---------------------------------------------------------------------- */ @@ -123,6 +111,36 @@ void ComputeRHEOGrad::init() rho0 = fix_rheo->rho0; compute_kernel = fix_rheo->compute_kernel; compute_interface = fix_rheo->compute_interface; + + // Create coordination array if it doesn't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded + + int index; + int dim = domain->dimension; + if (velocity_flag) { + index = atom->add_custom("rheo_grad_v", 1, dim * dim); + gradv = atom->darray[index]; + } + + if (rho_flag) { + index = atom->add_custom("rheo_grad_rho", 1, dim); + gradr = atom->darray[index]; + } + + if (temperature_flag) { + index= atom->add_custom("rheo_grad_temp", 1, dim); + gradt = atom->darray[index]; + } + + if (eta_flag) { + index = atom->add_custom("rheo_grad_eta", 1, dim); + gradn = atom->darray[index]; + } + + nmax_old = 0; + grow_arrays(atom->nmax); } /* ---------------------------------------------------------------------- */ @@ -151,13 +169,17 @@ void ComputeRHEOGrad::compute_peratom() double **v = atom->v; double *rho = atom->rho; double *temperature = atom->temperature; - double *eta = atom->viscosity; int *status = atom->status; int *type = atom->type; double *mass = atom->mass; int newton = force->newton; int dim = domain->dimension; + int tmp1, tmp2; + int index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); + if (index_visc == -1) error->all(FLERR, "Cannot find rheo viscosity"); + double *viscosity = atom->dvector[index_visc]; + inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; @@ -229,7 +251,7 @@ void ComputeRHEOGrad::compute_peratom() if (rho_flag) drho = rhoi - rhoj; if (temperature_flag) dT = temperature[i] - temperature[j]; - if (eta_flag) deta = eta[i] - eta[j]; + if (eta_flag) deta = viscosity[i] - viscosity[j]; wp = compute_kernel->calc_dw(i, j, delx, dely, delz, sqrt(rsq)); dWij = compute_kernel->dWij; diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index d86efe47ee..7804ee72dd 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -42,11 +42,9 @@ class ComputeRHEOGrad : public Compute { double **gradr; double **gradt; double **gradn; - int stage; private: int comm_stage, ncomm_grad, ncomm_field, nmax_old; - int indexv, indexr, indext, indexn; double cut, cutsq, rho0; class NeighList *list; diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index e76e46d422..ae1bc13831 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -18,24 +18,20 @@ #include "compute_rheo_interface.h" -#include "fix_rheo.h" -#include "compute_rheo_kernel.h" -#include "fix_store.h" -#include "fix.h" -#include -#include #include "atom.h" -#include "update.h" -#include "modify.h" +#include "comm.h" #include "domain.h" +#include "compute_rheo_kernel.h" +#include "error.h" +#include "force.h" +#include "fix_rheo.h" +#include "memory.h" +#include "modify.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" -#include "force.h" -#include "pair.h" -#include "comm.h" -#include "memory.h" -#include "error.h" + +#include using namespace LAMMPS_NS; @@ -44,45 +40,29 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ComputeRHEOInterface::ComputeRHEOInterface(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), - id_fix_chi(nullptr) + Compute(lmp, narg, arg), fix_rheo(nullptr), compute_kernel(nullptr), fx_m_norm(nullptr), + norm(nullptr), normwf(nullptr), chi(nullptr), f_pressure(nullptr), id_fix_pa(nullptr) { - if (narg != 4) error->all(FLERR,"Illegal compute RHEO/chi command"); - - cut = utils::numeric(FLERR,arg[3],false,lmp); - cutsq = cut*cut; - - wall_max = sqrt(3)/12.0*cut; + if (narg != 3) error->all(FLERR,"Illegal compute rheo/interface command"); nmax = 0; comm_forward = 3; comm_reverse = 4; - - fix_chi = nullptr; - norm = nullptr; - normwf = nullptr; - - // new id = fix-ID + FIX_STORE_ATTRIBUTE - // new fix group = group for this fix - - id_fix_chi = nullptr; - std::string fixcmd = id + std::string("_chi"); - id_fix_chi = new char[fixcmd.size()+1]; - strcpy(id_fix_chi,fixcmd.c_str()); - fixcmd += fmt::format(" all STORE peratom 0 {}", 1); - modify->add_fix(fixcmd); - fix_chi = (FixStore *) modify->fix[modify->nfix-1]; - chi = fix_chi->vstore; } /* ---------------------------------------------------------------------- */ ComputeRHEOInterface::~ComputeRHEOInterface() { - if (id_fix_chi && modify->nfix) modify->delete_fix(id_fix_chi); - if (modify->nfix) modify->delete_fix("PROPERTY_ATOM_COMP_RHEO_SOLIDS"); + // Remove custom property if it exists + int tmp1, tmp2, index; + index = atom->find_custom("rheo_chi", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 0); + if (id_fix_pa && modify->nfix) modify->delete_fix(id_fix_pa); + + memory->destroy(fx_m_norm); memory->destroy(norm); memory->destroy(normwf); } @@ -91,42 +71,40 @@ ComputeRHEOInterface::~ComputeRHEOInterface() void ComputeRHEOInterface::init() { - // need an occasional full neighbor list - int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->pair = 0; - neighbor->requests[irequest]->compute = 1; - neighbor->requests[irequest]->half = 1; - neighbor->requests[irequest]->full = 0; - //neighbor->requests[irequest]->occasional = 1; //Anticipate needing regulalry + compute_kernel = fix_rheo->compute_kernel; + cut = fix_rheo->cut; + cutsq = cut * cut; + wall_max = sqrt(3.0) / 12.0 * cut; - int icompute = modify->find_compute("rheo_kernel"); - if (icompute == -1) error->all(FLERR, "Using compute/RHEO/chi without compute/RHEO/kernel"); + // Create chi array if it doesn't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded - compute_kernel = ((ComputeRHEOKernel *) modify->compute[icompute]); + int create_flag = 0; + int tmp1, tmp2; + int nmax = atom->nmax; + int index = atom->find_custom("rheo_chi", tmp1, tmp2); + if (index == -1) { + index = atom->add_custom("rheo_chi", 1, 0); + nmax_old = nmax; + } + chi = atom->dvector[index]; - //Store persistent per atom quantities - need to be exchanged - char **fixarg = new char*[8]; - fixarg[0] = (char *) "PROPERTY_ATOM_COMP_RHEO_SOLIDS"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "property/atom"; - fixarg[3] = (char *) "d_fx"; - fixarg[4] = (char *) "d_fy"; - fixarg[5] = (char *) "d_fz"; - fixarg[6] = (char *) "ghost"; - fixarg[7] = (char *) "yes"; - modify->add_fix(8,fixarg,1); - delete [] fixarg; + // For fpressure, go ahead and create an instance of fix property atom + // Need restarts + exchanging with neighbors since it needs to persist + // between timesteps (fix property atom will handle callbacks) - int temp_flag; - index_fx = atom->find_custom("fx", temp_flag); - if ((index_fx < 0) || (temp_flag != 1)) - error->all(FLERR, "Compute rheo/solids can't find fix property/atom fx"); - index_fy = atom->find_custom("fy", temp_flag); - if ((index_fy < 0) || (temp_flag != 1)) - error->all(FLERR, "Compute rheo/solids can't find fix property/atom fy"); - index_fz = atom->find_custom("fz", temp_flag); - if ((index_fz < 0) || (temp_flag != 1)) - error->all(FLERR, "Compute rheo/solids can't find fix property/atom fz"); + index = atom->find_custom("rheo_pressure", tmp1, tmp2); + if (index == -1) { + id_fix_pa = utils::strdup(id + std::string("_fix_property_atom")); + modify->add_fix(fmt::format("{} all property/atom d2_f_pressure 3", id_fix_pa))); + index = atom->find_custom("rheo_pressure", tmp1, tmp2); + } + f_pressure = atom->darray[index]; + + // need an occasional half neighbor list + neighbor->add_request(this, NeighConst::REQ_HALF); } /* ---------------------------------------------------------------------- */ @@ -138,6 +116,7 @@ void ComputeRHEOInterface::init_list(int /*id*/, NeighList *ptr) /* ---------------------------------------------------------------------- */ +// Left off here void ComputeRHEOInterface::compute_peratom() { int i, j, ii, jj, jnum, itype, jtype, phase_match; diff --git a/src/RHEO/compute_rheo_interface.h b/src/RHEO/compute_rheo_interface.h index 635f190aed..f314c16aa9 100644 --- a/src/RHEO/compute_rheo_interface.h +++ b/src/RHEO/compute_rheo_interface.h @@ -27,35 +27,34 @@ namespace LAMMPS_NS { class ComputeRHEOInterface : public Compute { public: ComputeRHEOInterface(class LAMMPS *, int, char **); - ~ComputeRHEOInterface(); - void init(); - void init_list(int, class NeighList *); - void compute_peratom(); - int pack_forward_comm(int, int *, double *, int, int *); - void unpack_forward_comm(int, int, double *); - int pack_reverse_comm(int, int, double *); - void unpack_reverse_comm(int, int *, double *); + ~ComputeRHEOInterface() override; + void init() override; + void init_list(int, class NeighList *) override; + void compute_peratom() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; + double memory_usage() override; void correct_v(double *, double *, double *, int, int); double correct_rho(int, int); - double memory_usage(); void store_forces(); - double *chi; + + double *chi, **f_pressure; private: - int nmax; - double cut, cutsq, cs2; + int nmax_old, comm_stage; + double cut, cutsq, cs, wall_max; + double **fx_m_norm, *norm, *normwf; + + char *id_fix_pa; + class NeighList *list; - double *norm, *normwf, wall_max; - + class FixRHEO *fix_rheo; class ComputeRHEOKernel *compute_kernel; - char *id_fix_chi; - class FixStore *fix_chi; - - int index_fx, index_fy, index_fz; - int comm_stage; }; -} +} // namespace LAMMPS_NS #endif #endif diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 15b5f9568b..ac9ea75fc4 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -55,7 +55,7 @@ Move away from h notation, use cut? ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), - C(nullptr), C0(nullptr), compute_interface(nullptr); + C(nullptr), C0(nullptr), coordination(nullptr), compute_interface(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute rheo/kernel command"); @@ -71,7 +71,7 @@ ComputeRHEOKernel::~ComputeRHEOKernel() // Remove custom property if it exists int tmp1, tmp2, index; index = atom->find_custom("rheo_coordination", tmp1, tmp2); - if (index != -1) atom->remove_custom(index_coord, 1, 0); + if (index != -1) atom->remove_custom(index, 0, 0); memory->destroy(C); memory->destroy(C0); @@ -125,12 +125,14 @@ void ComputeRHEOKernel::init() int tmp1, tmp2; int nmax = atom->nmax; - index_coord = atom->find_custom("rheo_coordination", tmp1, tmp2); - if (index_coord == -1) { - index_coord = atom->add_custom("rheo_coordination", 0, 0); + int index = atom->find_custom("rheo_coordination", tmp1, tmp2); + if (index == -1) { + index = atom->add_custom("rheo_coordination", 0, 0); nmax_old = nmax; } + coordination = atom->ivector[index]; + // Create local arrays for kernel arrays, I can't foresee a reason to print comm_forward = 1; ncor = 0; Mdim = 0; @@ -170,7 +172,6 @@ int ComputeRHEOKernel::check_corrections(int i) corrections = 0; } - int *coordination = atom->ivector[index_coord]; if (coordination[i] < zmin) corrections = 0; return corrections; @@ -503,7 +504,6 @@ void ComputeRHEOKernel::compute_peratom() double *mass = atom->mass; double *rho = atom->rho; int *status = atom->status; - int *coordination = atom->ivector[index_coord]; tagint *tag = atom->tag; int inum, *ilist, *jlist, *numneigh, **firstneigh; @@ -742,7 +742,6 @@ int ComputeRHEOKernel::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,k,m,a,b; - coordination = atom->ivector[index_coord]; m = 0; if (correction_order > 0) { for (i = 0; i < n; i++) { @@ -774,7 +773,6 @@ int ComputeRHEOKernel::pack_forward_comm(int n, int *list, double *buf, void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last,a,b; - coordination = atom->ivector[index_coord]; m = 0; last = first + n; if (correction_order > 0) { diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 346df5a20c..df659c47de 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -42,6 +42,7 @@ class ComputeRHEOKernel : public Compute { double dWij[3], dWji[3], Wij, Wji; int correction_order; + int *coordination; private: int solid_flag; @@ -49,7 +50,7 @@ class ComputeRHEOKernel : public Compute { std::unordered_set gsl_error_tags; int kernel_style, zmin, dim, Mdim, ncor; - int nmax_old, index_coord; + int nmax_old; double h, hsq, hinv, hsqinv, pre_w, pre_wp; double ***C; double *C0; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 2b7c9394d3..dccd3867cd 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -21,7 +21,6 @@ #include "atom.h" #include "comm.h" #include "compute_rheo_interface.h" -#include "compute_rheo_grad.h" #include "compute_rheo_kernel.h" #include "domain.h" #include "error.h" @@ -37,8 +36,8 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ComputeRHEOVShift::ComputeRHEOVShift(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), vshift(nullptr), fix_rheo(nullptr), compute_kernel(nullptr), - compute_grad(nullptr), compute_surface(nullptr), compute_interface(nullptr) + Compute(lmp, narg, arg), vshift(nullptr), fix_rheo(nullptr), fix_rheo(nullptr), + compute_kernel(nullptr), compute_interface(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute RHEO/VShift command"); @@ -51,11 +50,12 @@ ComputeRHEOVShift::ComputeRHEOVShift(LAMMPS *lmp, int narg, char **arg) : // Manually grow if nmax_old exceeded int tmp1, tmp2; - index_vshift = atom->find_custom("rheo_vshift", tmp1, tmp2); - if (index_vshift == -1) { - index_vshift = atom->add_custom("rheo_vshift", 1, 3); + int index = atom->find_custom("rheo_vshift", tmp1, tmp2); + if (index == -1) { + index = atom->add_custom("rheo_vshift", 1, 3); nmax_old = atom->nmax; } + vshift = atom->dvector[index]; } /* ---------------------------------------------------------------------- */ @@ -65,7 +65,7 @@ ComputeRHEOVShift::~ComputeRHEOVShift() // Remove custom property if it exists int tmp1, tmp2, index; index = atom->find_custom("rheo_vshift", tmp1, tmp2); - if (index != -1) atom->remove_custom(index_vshift, 1, 3); + if (index != -1) atom->remove_custom(index, 1, 3); } @@ -80,7 +80,6 @@ void ComputeRHEOVShift::init() surface_flag = 1; compute_kernel = fix_rheo->compute_kernel; - compute_grad = fix_rheo->compute_grad; compute_interface = fix_rheo->compute_interface; cut = fix_rheo->cut; @@ -119,7 +118,6 @@ void ComputeRHEOVShift::compute_peratom() int *surface = atom->surface; double *rho = atom->rho; double *mass = atom->mass; - double **vshift = atom->darray[index_vshift]; int newton_pair = force->newton_pair; inum = list->inum; @@ -127,7 +125,6 @@ void ComputeRHEOVShift::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - if (nmax_old < atom->nmax) memory->grow(vshift, atom->nmax, 3, "atom:rheo_vshift"); nmax_old = atom->nmax; @@ -232,9 +229,9 @@ void ComputeRHEOVShift::correct_surfaces() int nlocal = atom->nlocal; int i, a, b; int dim = domain->dimension; - double **vshift = atom->darray[index_vshift]; int tmp1, tmp2; + define after surf int index_nsurf = atom->find_custom("rheo_nsurf", tmp1, tmp2); if (index_nsurf == -1) error->all(FLERR, "Cannot find rheo nsurf"); double **nsurf = atom->darray[index_nsurf]; @@ -268,7 +265,6 @@ void ComputeRHEOVShift::correct_surfaces() int ComputeRHEOVShift::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; - double **vshift = atom->darray[index_vshift]; m = 0; last = first + n; @@ -285,7 +281,6 @@ int ComputeRHEOVShift::pack_reverse_comm(int n, int first, double *buf) void ComputeRHEOVShift::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; - double **vshift = atom->darray[index_vshift]; m = 0; for (i = 0; i < n; i++) { diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h index f93cced31c..af5675fd8d 100644 --- a/src/RHEO/compute_rheo_vshift.h +++ b/src/RHEO/compute_rheo_vshift.h @@ -35,17 +35,17 @@ class ComputeRHEOVShift : public Compute { void unpack_reverse_comm(int, int *, double *) override; double memory_usage() override; void correct_surfaces(); + double **vshift; private: int nmax_old; double dtv, cut, cutsq, cutthird; - int surface_flag, index_vshift; + int surface_flag; class NeighList *list; class FixRHEO *fix_rheo; class ComputeRHEOInterface *compute_interface ; class ComputeRHEOKernel *compute_kernel; - class ComputeRHEOGrad *compute_grad; }; } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 25a97bd52a..e83a95751a 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -21,6 +21,7 @@ #include "atom.h" #include "compute_rheo_grad.h" #include "compute_rheo_interface.h" +#include "compute_rheo_surface.h" #include "compute_rheo_kernel.h" #include "compute_rheo_rhosum.h" #include "compute_rheo_vshift.h" @@ -37,7 +38,7 @@ using namespace FixConst; /* ---------------------------------------------------------------------- */ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), compute_grad(nullptr), compute_kernel(nullptr), + Fix(lmp, narg, arg), compute_grad(nullptr), compute_kernel(nullptr), compute_surface(nullptr), compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr) { time_integrate = 1; @@ -258,7 +259,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) double **gradr = compute_grad->gradr; double **gradv = compute_grad->gradv; - double **vshift = compute_vshift->array_atom; + double **vshift = compute_vshift->vshift; int *type = atom->type; int *mask = atom->mask; diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 0132f32bcc..89304fe22f 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -81,6 +81,7 @@ class FixRHEO : public Fix { class ComputeRHEOGrad *compute_grad; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; + class ComputeRHEOSurface *compute_surface; class ComputeRHEORhoSum *compute_rhosum; class ComputeRHEOVShift *compute_vshift; diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 4fa4ece0f9..726c44c32b 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -36,7 +36,7 @@ enum {NONE, LINEAR, CUBIC, TAITWATER}; /* ---------------------------------------------------------------------- */ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg) + Fix(lmp, narg, arg), fix_rheo(nullptr), pressure(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -74,7 +74,7 @@ FixRHEOPressure::~FixRHEOPressure() // Remove custom property if it exists int tmp1, tmp2, index; index = atom->find_custom("rheo_pressure", tmp1, tmp2); - if (index != -1) atom->remove_custom(index_pres, 1, 0); + if (index != -1) atom->remove_custom(index, 1, 0); } /* ---------------------------------------------------------------------- */ @@ -115,11 +115,12 @@ void FixRHEOPressure::setup_pre_force(int /*vflag*/) // Manually grow if nmax_old exceeded int tmp1, tmp2; - index_pres = atom->find_custom("rheo_pressure", tmp1, tmp2); - if (index_pres == -1) { - index_pres = atom->add_custom("rheo_pressure", 1, 0); + int index = atom->find_custom("rheo_pressure", tmp1, tmp2); + if (index == -1) { + index = atom->add_custom("rheo_pressure", 1, 0); nmax_old = atom->nmax; } + pressure = atom->dvector[index]; pre_force(0); } @@ -133,7 +134,6 @@ void FixRHEOPressure::pre_force(int /*vflag*/) int i; double dr, rr3, rho_ratio; - double *pressure = atom->dvector[index_pres]; int *mask = atom->mask; double *rho = atom->rho; @@ -170,7 +170,6 @@ int FixRHEOPressure::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,k,m; - double *pressure = atom->dvector[index_pres]; m = 0; for (i = 0; i < n; i++) { @@ -185,7 +184,6 @@ int FixRHEOPressure::pack_forward_comm(int n, int *list, double *buf, void FixRHEOPressure::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; - double *pressure = atom->dvector[index_pres]; m = 0; last = first + n; @@ -194,6 +192,8 @@ void FixRHEOPressure::unpack_forward_comm(int n, int first, double *buf) } } +/* ---------------------------------------------------------------------- */ + double FixRHEOPressure::calculate_p(double rho) { double rho; diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index 8272cc38f5..197cab6e5c 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -38,9 +38,10 @@ class FixRHEOPressure : public Fix { double calculate_p(double); private: double c_cubic, csq, rho0, rho0inv; + double *pressure; int pressure_style; int first_flag, last_flag; - int nmax_old, index_pressure; + int nmax_old; class FixRHEO *fix_rheo; }; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 3ef9fab853..1a5d894ced 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -37,7 +37,8 @@ enum {NONE, CONSTANT, TYPE}; /* ---------------------------------------------------------------------- */ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr) + Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), + conductivity(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -131,7 +132,7 @@ FixRHEOThermal::~FixRHEOThermal() // Remove custom property if it exists int tmp1, tmp2, index; index = atom->find_custom("rheo_conductivity", tmp1, tmp2); - if (index != -1) atom->remove_custom(index_cond, 1, 0); + if (index != -1) atom->remove_custom(index, 1, 0); memory->destroy(cv_type); memory->destroy(Tc_type); @@ -199,11 +200,12 @@ void FixRHEOThermal::setup_pre_force(int /*vflag*/) // Manually grow if nmax_old exceeded int tmp1, tmp2; - index_cond = atom->find_custom("rheo_conductivity", tmp1, tmp2); - if (index_cond == -1) { - index_cond = atom->add_custom("rheo_conductivity", 1, 0); + index = atom->find_custom("rheo_conductivity", tmp1, tmp2); + if (index== -1) { + index = atom->add_custom("rheo_conductivity", 1, 0); nmax_old = atom->nmax; } + conductivity = atom->dvector[index]; post_neighbor(); pre_force(0); diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index 3b62e86fa8..4f0e89f17c 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -48,11 +48,12 @@ class FixRHEOThermal : public Fix { double *Tc_type, Tc; double *kappa_type, kappa; double dtf, dtv; + double *conductivity; int Tc_style; int cv_style; int conductivity_style; int first_flag, last_flag; - int nmax_old, index_cond; + int nmax_old; class FixRHEO *fix_rheo; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 3f779aa3c6..bb7094c43e 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -37,7 +37,7 @@ enum {NONE, CONSTANT, TYPE, POWER}; /* ---------------------------------------------------------------------- */ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), eta_type(nullptr) + Fix(lmp, narg, arg), fix_rheo(nullptr), eta_type(nullptr), viscosity(nullptr), compute_grad(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -142,11 +142,12 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) // Manually grow if nmax_old exceeded int tmp1, tmp2; - index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); + int index = atom->find_custom("rheo_viscosity", tmp1, tmp2); if (index_visc == -1) { - index_visc = atom->add_custom("rheo_viscosity", 1, 0); + index = atom->add_custom("rheo_viscosity", 1, 0); nmax_old = atom->nmax; } + viscosity = atom->dvector[index]; post_neighbor(); pre_force(0); @@ -161,7 +162,6 @@ void FixRHEOViscosity::post_neighbor() int i; int *type = atom->type; - double *viscosity = atom->dvector[index_visc]; int *mask = atom->mask; int nlocal = atom->nlocal; @@ -190,7 +190,6 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) int i, a, b; double tmp, gdot; - double *viscosity = atom->dvector[index_visc]; int *mask = atom->mask; double **gradv = compute_grad->gradv; @@ -232,7 +231,6 @@ int FixRHEOViscosity::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,k,m; - double *viscosity = atom->dvector[index_visc]; m = 0; for (i = 0; i < n; i++) { @@ -247,7 +245,6 @@ int FixRHEOViscosity::pack_forward_comm(int n, int *list, double *buf, void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; - double *viscosity = atom->dvector[index_visc]; m = 0; last = first + n; diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index 407170f668..14f8b70de9 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -40,9 +40,10 @@ class FixRHEOViscosity : public Fix { private: double *eta_type, eta; double npow, K, gd0, tau0; + double *viscosity; int viscosity_style; int first_flag, last_flag; - int nmax_old, index_visc; + int nmax_old; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 7d5d0f425f..7b9425cf20 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -47,7 +47,7 @@ using namespace MathExtra; PairRHEO::PairRHEO(LAMMPS *lmp) : Pair(lmp), compute_kernel(nullptr), compute_grad(nullptr), - compute_interface(nullptr), fix_rheo(nullptr), fix_rheo_pressure(nullptr) + compute_interface(nullptr), fix_rheo(nullptr), fix_pressure(nullptr) { restartinfo = 0; single_enable = 0; @@ -91,8 +91,7 @@ void PairRHEO::compute(int eflag, int vflag) double **v = atom->v; double **x = atom->x; double **f = atom->f; - double **f_pressure = fix_rheo->f_pressure; // rewrite later - double *pressure = atom->pressure; // rewrite later + double **f_pressure = compute_interface->f_pressure; double *rho = atom->rho; double *mass = atom->mass; double *drho = atom->drho; @@ -105,15 +104,19 @@ void PairRHEO::compute(int eflag, int vflag) int *status = atom->status; int tmp1, tmp2; - int index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index_visc == -1) error->all(FLERR, "Cannot find rheo viscosity"); - double *viscosity = atom->dvector[index_visc]; + int index = atom->find_custom("rheo_viscosity", tmp1, tmp2); + if (index == -1) error->all(FLERR, "Cannot find rheo viscosity"); + double *viscosity = atom->dvector[index]; + + index = atom->find_custom("rheo_pressure", tmp1, tmp2); + if (index == -1) error->all(FLERR, "Cannot find rheo pressure"); + double *pressure = atom->dvector[index]; double *conductivity; if (thermal_flag) { - int index_cond = atom->find_custom("rheo_conductivity", tmp1, tmp2); - if (index_cond == -1) error->all(FLERR, "Cannot find rheo conductivity"); - conductivity = atom->dvector[index_cond]; + index = atom->find_custom("rheo_conductivity", tmp1, tmp2); + if (index == -1) error->all(FLERR, "Cannot find rheo conductivity"); + conductivity = atom->dvector[index]; } int *ilist, *jlist, *numneigh, **firstneigh; @@ -195,7 +198,7 @@ void PairRHEO::compute(int eflag, int vflag) if (fluidi && (!fluidj)) { compute_interface->correct_v(vi, vj, i, j); rhoj = compute_interface->correct_rho(j, i); - Pj = fix_rheo_pressure->calculate_p(rhoj); + Pj = fix_pressure->calculate_p(rhoj); if ((chi[j] > 0.9) && (r < (h * 0.5))) fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; @@ -413,7 +416,12 @@ void PairRHEO::setup() fixes = modify->get_fix_by_style("rheo/pressure"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo/pressure to use pair rheo"); - fix_rheo_pressure = dynamic_cast(fixes[0]); + fix_pressure = dynamic_cast(fixes[0]); + + int tmp1, tmp2; + index_pressure = atom->find_custom("rheo_pressure", tmp1, tmp2); + if (index_pressure == -1) index_pressure = atom->add_custom("rheo_pressure", 1, 0); + else error->all(FLERR, "Cannot find pressure value in pair rheo"); compute_kernel = fix_rheo->compute_kernel; compute_grad = fix_rheo->compute_grad; diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index aa98e63ddc..49aa1ad025 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -49,7 +49,7 @@ class PairRHEO : public Pair { class ComputeRHEOGrad *compute_grad; class ComputeRHEOInterface *compute_interface; class FixRHEO *fix_rheo; - class FixRHEOPressure *fix_rheo_pressure; + class FixRHEOPressure *fix_pressure; }; } // namespace LAMMPS_NS From 5980fdf9fdad22d75a395078a61319f3e453c71e Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sat, 15 Apr 2023 21:15:37 -0600 Subject: [PATCH 022/385] Revising interface compute --- src/RHEO/compute_rheo_interface.cpp | 185 +++++++++++++--------------- src/RHEO/compute_rheo_interface.h | 4 +- src/RHEO/compute_rheo_vshift.cpp | 8 +- src/RHEO/fix_rheo_thermal.cpp | 10 +- src/RHEO/fix_rheo_viscosity.cpp | 10 +- src/RHEO/pair_rheo.cpp | 29 +++-- 6 files changed, 126 insertions(+), 120 deletions(-) diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index ae1bc13831..ff76b75f77 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -61,8 +61,8 @@ ComputeRHEOInterface::~ComputeRHEOInterface() if (index != -1) atom->remove_custom(index, 1, 0); if (id_fix_pa && modify->nfix) modify->delete_fix(id_fix_pa); + delete[] id_fix_pa; - memory->destroy(fx_m_norm); memory->destroy(norm); memory->destroy(normwf); } @@ -72,7 +72,10 @@ ComputeRHEOInterface::~ComputeRHEOInterface() void ComputeRHEOInterface::init() { compute_kernel = fix_rheo->compute_kernel; + rho0 = fix_rheo->rho0; cut = fix_rheo->cut; + cs = fix_rheo->cs; + cs_inv = 1.0 / cs; cutsq = cut * cut; wall_max = sqrt(3.0) / 12.0 * cut; @@ -87,21 +90,25 @@ void ComputeRHEOInterface::init() int index = atom->find_custom("rheo_chi", tmp1, tmp2); if (index == -1) { index = atom->add_custom("rheo_chi", 1, 0); + memory->destroy(norm); + memory->destroy(normwf); + memory->create(norm, nmax, "rheo/interface:norm"); + memory->create(normwf, nmax, "rheo/interface:normwf"); nmax_old = nmax; } chi = atom->dvector[index]; - // For fpressure, go ahead and create an instance of fix property atom + // For fp_store, go ahead and create an instance of fix property atom // Need restarts + exchanging with neighbors since it needs to persist // between timesteps (fix property atom will handle callbacks) - index = atom->find_custom("rheo_pressure", tmp1, tmp2); + index = atom->find_custom("fp_store", tmp1, tmp2); if (index == -1) { id_fix_pa = utils::strdup(id + std::string("_fix_property_atom")); - modify->add_fix(fmt::format("{} all property/atom d2_f_pressure 3", id_fix_pa))); - index = atom->find_custom("rheo_pressure", tmp1, tmp2); + modify->add_fix(fmt::format("{} all property/atom d2_fp_store 3", id_fix_pa))); + index = atom->find_custom("fp_store", tmp1, tmp2); } - f_pressure = atom->darray[index]; + fp_store = atom->darray[index]; // need an occasional half neighbor list neighbor->add_request(this, NeighConst::REQ_HALF); @@ -116,51 +123,37 @@ void ComputeRHEOInterface::init_list(int /*id*/, NeighList *ptr) /* ---------------------------------------------------------------------- */ -// Left off here void ComputeRHEOInterface::compute_peratom() { - int i, j, ii, jj, jnum, itype, jtype, phase_match; - double xtmp, ytmp, ztmp, delx, dely, delz, rsq; - int *jlist; - double w; + int i, j, ii, jj, jnum, itype, jtype, fluidi, fluidj, status_match; + double xtmp, ytmp, ztmp, delx, dely, delz, rsq, w, dot; - // neighbor list ariables - int inum, *ilist, *numneigh, **firstneigh; + int inum, *ilist, *jlist, *numneigh, **firstneigh; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double **x = atom->x; int *type = atom->type; int newton = force->newton; - int *phase = atom->phase; + int *status = atom->status; double *rho = atom->rho; - double *fx = atom->dvector[index_fx]; - double *fy = atom->dvector[index_fy]; - double *fz = atom->dvector[index_fz]; - double mi, mj; - - //Declare mass pointer to calculate acceleration from force - double *mass = atom->mass; - - cs2 = 1.0; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; - if (atom->nmax > nmax) { - nmax = atom->nmax; - fix_chi->grow_arrays(nmax); - chi = fix_chi->vstore; + if (atom->nmax > nmax_old) { + nmax_old = atom->nmax; memory->destroy(norm); memory->destroy(normwf); - memory->create(norm, nmax, "RHEO/chi:norm"); - memory->create(normwf, nmax, "RHEO/chi:normwf"); + memory->create(norm, nmax_old, "rheo/interface:norm"); + memory->create(normwf, nmax_old, "rheo/interface:normwf"); + memory->grow(chi, nmax_old, "rheo/interface:chi"); } for (i = 0; i < nall; i++) { - if (phase[i] > FixRHEO::FLUID_MAX) rho[i] = 0.0; + if (!(status[i] & FixRHEO::STATUS_FLUID)) rho[i] = 0.0; normwf[i] = 0.0; norm[i] = 0.0; chi[i] = 0.0; @@ -172,9 +165,9 @@ void ComputeRHEOInterface::compute_peratom() ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; + fluidi = status[i] & FixRHEO::STATUS_FLUID; jlist = firstneigh[i]; jnum = numneigh[i]; - mi = mass[type[i]]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -187,37 +180,36 @@ void ComputeRHEOInterface::compute_peratom() if (rsq < cutsq) { jtype = type[j]; - mj = mass[type[j]]; + fluidj = status[j] & FixRHEO::STATUS_FLUID; w = compute_kernel->calc_w_quintic(i, j, delx, dely, delz, sqrt(rsq)); - phase_match = 0; + status_match = 0; norm[i] += w; - if ((phase[i] <= FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) - || (phase[i] > FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX)) { - phase_match = 1; - } + if ((fluidi && fluidj) || ((!fluid) && (!fluidj))) + status_match = 1; - if (phase_match) { + if (status_match) { chi[i] += w; } else { - if (phase[i] > FixRHEO::FLUID_MAX) { - //speed of sound and rho0 assumed to = 1 (units in density not pressure) - //In general, rho is calculated using the force vector on the wall particle - //fx stores f-fp - rho[i] += w*(cs2*(rho[j] - 1.0) - rho[j]*((-fx[j]/mj+fx[i]/mi)*delx + (-fy[j]/mj+fy[i]/mi)*dely + (-fz[j]/mj+fz[i]/mi)*delz)); - //For the specific taste case whre force on wall particles = 0 - //rho[i] += w*(1.0*(rho[j] - 1.0) + rho[j]*(1e-3*delx)); + if (!fluidi) { + dot = (-fp_store[0][j] + fp_store[0][i]) * delx; + dot += (-fp_store[1][j] + fp_store[1][i]) * dely; + dot += (-fp_store[2][j] + fp_store[2][i]) * delz; + rho[i] += w * (cs * (rho[j] - rho0) - rho[j] * dot); normwf[i] += w; } } if (newton || j < nlocal) { norm[j] += w; - if (phase_match) { + if (status_match) { chi[j] += w; } else { - if (phase[j] > FixRHEO::FLUID_MAX) { - rho[j] += w*(cs2*(rho[i] - 1.0) + rho[i]*((-fx[i]/mi+fx[j]/mj)*delx + (-fy[i]/mi+fy[j]/mj)*dely + (-fz[i]/mi+fz[j]/mj)*delz)); + if (!fluidj) { + dot = (-fp_store[0][i] + fp_store[0][j]) * delx; + dot += (-fp_store[1][i] + fp_store[1][j]) * dely; + dot += (-fp_store[2][i] + fp_store[2][j]) * delz; + rho[j] += w * (cs * (rho[i] - rho0) + rho[i] * dot); normwf[j] += w; } } @@ -226,41 +218,41 @@ void ComputeRHEOInterface::compute_peratom() } } - if (newton) comm->reverse_comm_compute(this); + if (newton) comm->reverse_comm(this); for (i = 0; i < nlocal; i++) { if (norm[i] != 0.0) chi[i] /= norm[i]; - if (normwf[i] != 0.0) { // Only if it's a wall particle - rho[i] = 1.0 + (rho[i] / normwf[i])/cs2; // Stores rho for solid particles 1+Pw in Adami Adams 2012 - if (rho[i] < EPSILON) rho[i] = EPSILON; - } - if (normwf[i] == 0.0 && phase[i] > FixRHEO::FLUID_MAX) rho[i] = 1.0; + // Recalculate rho for non-fluid particles + if (!(status[i] & FixRHEO::STATUS_FLUID)) { + if (normwf[i] != 0.0) { + // Stores rho for solid particles 1+Pw in Adami Adams 2012 + rho[i] = MAX(EPSILON, rho0 + (rho[i] / normwf[i]) * cs_inv); + } else { + rho[i] = rho0; + } + } } comm_stage = 1; comm_forward = 2; - comm->forward_comm_compute(this); + comm->forward_comm(this); } /* ---------------------------------------------------------------------- */ -int ComputeRHEOInterface::pack_forward_comm(int n, int *list, double *buf, - int /*pbc_flag*/, int * /*pbc*/) +int ComputeRHEOInterface::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,k,m; m = 0; double *rho = atom->rho; - double *fx = atom->dvector[index_fx]; - double *fy = atom->dvector[index_fy]; - double *fz = atom->dvector[index_fz]; for (i = 0; i < n; i++) { j = list[i]; if (comm_stage == 0) { - buf[m++] = fx[j]; - buf[m++] = fy[j]; - buf[m++] = fz[j]; + buf[m++] = fp_store[j][0]; + buf[m++] = fp_store[j][1]; + buf[m++] = fp_store[j][2]; } else { buf[m++] = chi[j]; buf[m++] = rho[j]; @@ -275,20 +267,16 @@ void ComputeRHEOInterface::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; double *rho = atom->rho; - double *fx = atom->dvector[index_fx]; - double *fy = atom->dvector[index_fy]; - double *fz = atom->dvector[index_fz]; - m = 0; last = first + n; for (i = first; i < last; i++) { if (comm_stage == 0) { - fx[i] = buf[m++]; - fy[i] = buf[m++]; - fz[i] = buf[m++]; + fp_store[i][0] = buf[m++]; + fp_store[i][1] = buf[m++]; + fp_store[i][2] = buf[m++]; } else { chi[i] = buf[m++]; - rho[i] = buf[m++]; // Won't do anything for fluids + rho[i] = buf[m++]; } } } @@ -317,13 +305,13 @@ void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) { int i,k,j,m; double *rho = atom->rho; - int *phase = atom->phase; + int *status = atom->status; m = 0; for (i = 0; i < n; i++) { j = list[i]; norm[j] += buf[m++]; chi[j] += buf[m++]; - if (phase[j] > FixRHEO::FLUID_MAX){ + if (!(status[j] & FixRHEO::STATUS_FLUID)){ normwf[j] += buf[m++]; rho[j] += buf[m++]; } else { @@ -339,22 +327,23 @@ void ComputeRHEOInterface::correct_v(double *vi, double *vj, double *vi_out, int { double wall_prefactor, wall_denom, wall_numer; - wall_numer = 2.0*cut*(chi[i]-0.5); + wall_numer = 2.0 * cut * (chi[i] - 0.5); if (wall_numer < 0) wall_numer = 0; - wall_denom = 2.0*cut*(chi[j]-0.5); + wall_denom = 2.0 * cut * (chi[j] - 0.5); if (wall_denom < wall_max) wall_denom = wall_max; wall_prefactor = wall_numer / wall_denom; - vi_out[0] = (vi[0]-vj[0])*wall_prefactor + vi[0]; - vi_out[1] = (vi[1]-vj[1])*wall_prefactor + vi[1]; - vi_out[2] = (vi[2]-vj[2])*wall_prefactor + vi[2]; + vi_out[0] = (vi[0] - vj[0]) * wall_prefactor + vi[0]; + vi_out[1] = (vi[1] - vj[1]) * wall_prefactor + vi[1]; + vi_out[2] = (vi[2] - vj[2]) * wall_prefactor + vi[2]; } /* ---------------------------------------------------------------------- */ -double ComputeRHEOInterface::correct_rho(int i, int j) // i is wall, j is fluid +double ComputeRHEOInterface::correct_rho(int i, int j) { + // i is wall, j is fluid //In future may depend on atom type j's pressure equation return atom->rho[i]; } @@ -363,42 +352,46 @@ double ComputeRHEOInterface::correct_rho(int i, int j) // i is wall, j is fluid void ComputeRHEOInterface::store_forces() { - double *fx = atom->dvector[index_fx]; - double *fy = atom->dvector[index_fy]; - double *fz = atom->dvector[index_fz]; + double minv; + double mass = atom->mass; + double type = atom->type; double **f = atom->f; - double **fp = atom->fp; int *mask = atom->mask; - int flag; + // When this is called, fp_store stores the pressure force + // After this method, fp_store instead stores non-pressure forces + // and is also normalized by the particles mass + // If forces are overwritten by a fix, there are no pressure forces + // so just normalize int ifix = modify->find_fix_by_style("setforce"); if (ifix != -1) { for (int i = 0; i < atom->nlocal; i++) { + minv = 1.0 / mass[type[i]]; if (mask[i] & modify->fix[ifix]->groupbit) { - fx[i] = f[i][0]; - fy[i] = f[i][1]; - fz[i] = f[i][2]; + fp_store[i][0] = f[i][0] * minv; + fp_store[i][1] = f[i][1] * minv; + fp_store[i][2] = f[i][2] * minv; } else { - fx[i] = f[i][0] - fp[i][0]; - fy[i] = f[i][1] - fp[i][1]; - fz[i] = f[i][2] - fp[i][2]; + fp_store[i][0] = (f[i][0] - fp_store[i][0]) * minv; + fp_store[i][1] = (f[i][1] - fp_store[i][1]) * minv; + fp_store[i][2] = (f[i][2] - fp_store[i][2]) * minv; } } } else { for (int i = 0; i < atom->nlocal; i++) { - fx[i] = f[i][0] - fp[i][0]; - fy[i] = f[i][1] - fp[i][1]; - fz[i] = f[i][2] - fp[i][2]; + minv = 1.0 / mass[type[i]]; + fp_store[i][0] = (f[i][0] - fp_store[i][0]) * minv; + fp_store[i][1] = (f[i][1] - fp_store[i][1]) * minv; + fp_store[i][2] = (f[i][2] - fp_store[i][2]) * minv; } } - //Forward comm forces -note only needed here b/c property atom will forward otherwise + // Forward comm forces comm_forward = 3; comm_stage = 0; - comm->forward_comm_compute(this); + comm->forward_comm(this); } - /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ diff --git a/src/RHEO/compute_rheo_interface.h b/src/RHEO/compute_rheo_interface.h index f314c16aa9..8e190c5430 100644 --- a/src/RHEO/compute_rheo_interface.h +++ b/src/RHEO/compute_rheo_interface.h @@ -44,8 +44,8 @@ class ComputeRHEOInterface : public Compute { private: int nmax_old, comm_stage; - double cut, cutsq, cs, wall_max; - double **fx_m_norm, *norm, *normwf; + double rho0, cut, cutsq, cs, cs_inv, wall_max; + double *norm, *normwf, **fom_store; char *id_fix_pa; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index dccd3867cd..6cbd6e96da 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -125,9 +125,10 @@ void ComputeRHEOVShift::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - if (nmax_old < atom->nmax) + if (nmax_old < atom->nmax) { memory->grow(vshift, atom->nmax, 3, "atom:rheo_vshift"); - nmax_old = atom->nmax; + nmax_old = atom->nmax; + } for (i = 0; i < nall; i++) for (a = 0; a < dim; a++) @@ -231,7 +232,6 @@ void ComputeRHEOVShift::correct_surfaces() int dim = domain->dimension; int tmp1, tmp2; - define after surf int index_nsurf = atom->find_custom("rheo_nsurf", tmp1, tmp2); if (index_nsurf == -1) error->all(FLERR, "Cannot find rheo nsurf"); double **nsurf = atom->darray[index_nsurf]; @@ -239,7 +239,7 @@ void ComputeRHEOVShift::correct_surfaces() double nx,ny,nz,vx,vy,vz; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { - if ((surface[i] & FixRHEO::STATUS_SURFACE) || (surface[i] & FixRHEO::STATUS_LAYER)) { + if ((status[i] & FixRHEO::STATUS_SURFACE) || (status[i] & FixRHEO::STATUS_LAYER)) { nx = nsurf[i][0]; ny = nsurf[i][1]; vx = vshift[i][0]; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 1a5d894ced..1912dc9f8c 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -293,9 +293,10 @@ void FixRHEOThermal::post_neighbor() int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (first_flag && (nmax_old < atom->nmax)) + if (first_flag && (nmax_old < atom->nmax)) { memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); - nmax_old = atom->nmax; + nmax_old = atom->nmax; + } if (conductivity_style == CONSTANT) { for (i = 0; i < nall; i++) @@ -328,9 +329,10 @@ void FixRHEOThermal::pre_force(int /*vflag*/) //int *mask = atom->mask; //int nlocal = atom->nlocal; - //if (first_flag && (nmax_old < atom->nmax)) + //if (first_flag && (nmax_old < atom->nmax)) { // memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); - //nmax_old = atom->nmax; + // nmax_old = atom->nmax; + //} //if (conductivity_style == TBD) { // for (i = 0; i < nlocal; i++) { diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index bb7094c43e..5ae1b95529 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -167,9 +167,10 @@ void FixRHEOViscosity::post_neighbor() int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (first_flag && (nmax_old < atom->nmax)) + if (first_flag && (nmax_old < atom->nmax)) { memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); - nmax_old = atom->nmax; + nmax_old = atom->nmax; + } if (viscosity_style == CONSTANT) { for (i = 0; i < nall; i++) @@ -196,9 +197,10 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) int nlocal = atom->nlocal; int dim = domain->dimension; - if (first_flag && (nmax_old < atom->nmax)) + if (first_flag && (nmax_old < atom->nmax)) { memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); - nmax_old = atom->nmax; + nmax_old = atom->nmax; + } if (viscosity_style == POWER) { for (i = 0; i < nlocal; i++) { diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 7b9425cf20..1eb2a43e1a 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -91,17 +91,21 @@ void PairRHEO::compute(int eflag, int vflag) double **v = atom->v; double **x = atom->x; double **f = atom->f; - double **f_pressure = compute_interface->f_pressure; double *rho = atom->rho; double *mass = atom->mass; double *drho = atom->drho; double *temperature = atom->temperature; double *heatflow = atom->heatflow; double *special_lj = force->special_lj; - tagint *tag = atom->tag; - int *chi = compute_interface->chi; int *type = atom->type; int *status = atom->status; + tagint *tag = atom->tag; + + double **fp_store, *chi; + if (compute_interface) { + fp_store = compute_interface->fp_store; + chi = compute_interface->chi; + } int tmp1, tmp2; int index = atom->find_custom("rheo_viscosity", tmp1, tmp2); @@ -273,9 +277,6 @@ void PairRHEO::compute(int eflag, int vflag) f[i][0] += ft[0]; f[i][1] += ft[1]; f[i][2] += ft[2]; - fp[i][0] += dfp[0]; - fp[i][1] += dfp[1]; - fp[i][2] += dfp[2]; if (evflag) // Does not account for unbalanced forces ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); @@ -289,7 +290,7 @@ void PairRHEO::compute(int eflag, int vflag) // flip sign here b/c -= at accummulator } - scale3(fp_prefact,r dWji, dfp); + scale3(fp_prefactor, dWji, dfp); add3(fv, dfp, ft); add3(fsolid, ft, ft); @@ -297,10 +298,18 @@ void PairRHEO::compute(int eflag, int vflag) f[j][0] -= ft[0]; f[j][1] -= ft[1]; f[j][2] -= ft[2]; + } - fp[j][0] -= dfp[0]; - fp[j][1] -= dfp[1]; - fp[j][2] -= dfp[2]; + if (compute_interface) { + fp_store[i][0] += dfp[0]; + fp_store[i][1] += dfp[1]; + fp_store[i][2] += dfp[2]; + + if (newton_pair || j < nlocal) { + fp_store[j][0] -= dfp[0]; + fp_store[j][1] -= dfp[1]; + fp_store[j][2] -= dfp[2]; + } } } From d85ce6a39247254ec64baaf1b8879c15c0aeecef Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 19 Apr 2023 17:15:00 -0600 Subject: [PATCH 023/385] Initial surface compute --- src/RHEO/compute_rheo_grad.h | 2 +- src/RHEO/compute_rheo_interface.cpp | 2 +- src/RHEO/compute_rheo_interface.h | 2 +- src/RHEO/compute_rheo_kernel.h | 2 +- src/RHEO/compute_rheo_surface.cpp | 595 ++++++++++++++++++++++++++++ src/RHEO/compute_rheo_surface.h | 72 ++++ src/RHEO/compute_rheo_vshift.h | 2 +- src/RHEO/fix_rheo.cpp | 54 ++- src/RHEO/fix_rheo.h | 8 +- 9 files changed, 714 insertions(+), 25 deletions(-) create mode 100644 src/RHEO/compute_rheo_surface.cpp create mode 100644 src/RHEO/compute_rheo_surface.h diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 7804ee72dd..ee4b4a5bd6 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -13,7 +13,7 @@ #ifdef COMPUTE_CLASS // clang-format off -ComputeStyle(rheo/grad,ComputeRHEOGrad) +ComputeStyle(RHEO/GRAD,ComputeRHEOGrad) // clang-format on #else diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index ff76b75f77..55cb81382b 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -398,7 +398,7 @@ void ComputeRHEOInterface::store_forces() double ComputeRHEOInterface::memory_usage() { - double bytes = nmax * sizeof(double); + double bytes = 3 * nmax_old * sizeof(double); return bytes; } diff --git a/src/RHEO/compute_rheo_interface.h b/src/RHEO/compute_rheo_interface.h index 8e190c5430..cdb2eb6c54 100644 --- a/src/RHEO/compute_rheo_interface.h +++ b/src/RHEO/compute_rheo_interface.h @@ -13,7 +13,7 @@ #ifdef COMPUTE_CLASS // clang-format off -ComputeStyle(rheo/interface,ComputeRHEOInterface) +ComputeStyle(RHEO/INTERFACE,ComputeRHEOInterface) // clang-format on #else diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index df659c47de..ed2b6ff5f2 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -13,7 +13,7 @@ #ifdef COMPUTE_CLASS // clang-format off -ComputeStyle(rheo/kernel,ComputeRHEOKernel) +ComputeStyle(RHEO/KERNEL,ComputeRHEOKernel) // clang-format on #else diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp new file mode 100644 index 0000000000..dff5db4cfa --- /dev/null +++ b/src/RHEO/compute_rheo_surface.cpp @@ -0,0 +1,595 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + +#include "compute_rheo_surface.h" + +#include "fix_rheo.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_solids.h" +#include "atom.h" +#include "memory.h" +#include "atom.h" +#include "comm.h" +#include "modify.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "error.h" +#include "force.h" +#include "domain.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOSurface::ComputeRHEOSurface(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (narg < 6) error->all(FLERR,"Illegal fix rheo/surface command"); + + cut = utils::numeric(FLERR,arg[3],false,lmp); + divR_limit = utils::numeric(FLERR,arg[4],false,lmp); + coord_limit = utils::inumeric(FLERR,arg[5],false,lmp); + + divr_flag = 1; + if (narg == 7) { + divr_flag = 0; + } + + int dim = domain->dimension; + + peratom_flag = 1; + size_peratom_cols = dim; + peratom_freq = 1; + + + comm_forward = 2; + comm_reverse = dim*dim + 1; + + cutsq = cut*cut; + + B = nullptr; + gradC = nullptr; + n_surface = nullptr; + + int nall = atom->nlocal + atom->nghost; + nmax = nall; + memory->create(B,nmax,dim*dim,"fix/rheo/surface:B"); + memory->create(gradC,nmax,dim*dim,"fix/rheo/surface:gradC"); + memory->create(n_surface,nmax,dim,"fix/rheo/surface:B"); + array_atom = n_surface; + + compute_kernel = nullptr; + compute_solids = NULL; + fix_rheo = nullptr; +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOSurface::~ComputeRHEOSurface() +{ + if (modify->nfix) modify->delete_fix("PROPERTY_ATOM_RHEO_SURFACE"); + + memory->destroy(B); + memory->destroy(gradC); + memory->destroy(n_surface); +} + +void ComputeRHEOSurface::post_constructor() +{ + //Store persistent per atom quantities + char **fixarg = new char*[5]; + fixarg[0] = (char *) "PROPERTY_ATOM_RHEO_SURFACE"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "property/atom"; + fixarg[3] = (char *) "d_divr"; + fixarg[4] = (char *) "d_rsurf"; + modify->add_fix(5,fixarg,1); + + int temp_flag; + index_divr = atom->find_custom("divr", temp_flag); + if ((index_divr < 0) || (temp_flag != 1)) + error->all(FLERR, "Pair rheo/surface can't find fix property/atom divr"); + + index_rsurf = atom->find_custom("rsurf", temp_flag); + if ((index_rsurf < 0) || (temp_flag != 1)) + error->all(FLERR, "Pair rheo/surface can't find fix property/atom rsurf"); + + delete [] fixarg; + divr = atom->dvector[index_divr]; +} +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOSurface::setmask() +{ + int mask = 0; + mask |= PRE_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOSurface::init() +{ + // need an occasional full neighbor list + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->pair = 0; + neighbor->requests[irequest]->fix = 1; + neighbor->requests[irequest]->half = 1; + neighbor->requests[irequest]->full = 0; + + int flag; + int ifix = modify->find_fix_by_style("rheo"); + if (ifix == -1) error->all(FLERR, "Need to define fix rheo to use fix rheo/surface"); + fix_rheo = ((FixRHEO *) modify->fix[ifix]); + compute_kernel = fix_rheo->compute_kernel; + compute_solids = fix_rheo->compute_solids; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOSurface::setup_pre_force(int /*vflag*/) +{ + pre_force(0); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOSurface::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOSurface::pre_force(int /*vflag*/) +{ + int i, j, ii, jj, jnum, a, b, itype, jtype; + double xtmp, ytmp, ztmp, delx, dely, delz, rsq, r, wp, Voli, Volj, rhoi, rhoj; + int *jlist; + double *dWij, *dWji; + double dx[3]; + + divr = atom->dvector[index_divr]; + + // neighbor list variables + int inum, *ilist, *numneigh, **firstneigh; + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + double **x = atom->x; + int *surface = atom->surface; + int *phase = atom->phase; + double *rsurf = atom->dvector[index_rsurf]; + int newton = force->newton; + int dim = domain->dimension; + int *mask = atom->mask; + int *type = atom->type; + double *mass = atom->mass; + double *rho = atom->rho; + double *temp = atom->temp; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + if (nmax <= nall) { + nmax = nall; + memory->destroy(B); + memory->destroy(gradC); + memory->destroy(n_surface); + + memory->create(B,nmax,dim*dim,"fix/rheo/surface:B"); + memory->create(gradC,nmax,dim*dim,"fix/rheo/surface:gradC"); + memory->create(n_surface,nmax,dim,"fix/rheo/surface:n_surface"); + array_atom = n_surface; + } + + for (i = 0; i < nall; i++) { + for (a = 0; a < dim; a++) { + for (b = 0; b < dim; b++) { + B[i][a*dim + b] = 0.0; + gradC[i][a*dim + b] = 0.0; + } + n_surface[i][a] = 0.0; + } + divr[i] = 0.0; + surface[i] = 0; + } + + // loop over neighbors to calculate the average orientation of neighbors + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + + jlist = firstneigh[i]; + jnum = numneigh[i]; + itype = type[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + dx[0] = delx; + dx[1] = dely; + dx[2] = delz; + rsq = delx * delx + dely * dely + delz * delz; + if (rsq < cutsq) { + jtype = type[j]; + + rhoi = rho[i]; + rhoj = rho[j]; + + // Add corrections for walls + if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { + rhoj = compute_solids->correct_rho(j,i); + } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { + rhoi = compute_solids->correct_rho(i,j); + } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { + rhoi = 1.0; + rhoj = 1.0; + } + + Voli = mass[itype]/rhoi; + Volj = mass[jtype]/rhoj; + + //compute kernel gradient + wp = compute_kernel->calc_dw_quintic(i, j, delx, dely, delz, sqrt(rsq),compute_kernel->dWij,compute_kernel->dWji); + //wp = compute_kernel->calc_dw(i, j, delx, dely, delz, sqrt(rsq));//,compute_kernel->dWij,compute_kernel->dWji); + + dWij = compute_kernel->dWij; + dWji = compute_kernel->dWji; + + for (a=0; areverse_comm_fix(this); + comm->forward_comm_fix(this); + + int *coordination = compute_kernel->coordination; + // Find the free-surface + //0-bulk 1-surf vicinity 2-surface 3-splash + if (divr_flag) { + for (i = 0; i < nall; i++) { + if (mask[i] & groupbit) { + surface[i] = 0; + rsurf[i] = cut; //Maximum range that can be seen + if (divr[i] < divR_limit) { + surface[i] = 2; + rsurf[i] = 0.0; + if (coordination[i] < coord_limit) surface[i] = 3; + } + } + } + } else { + for (i = 0; i < nall; i++) { + if (mask[i] & groupbit) { + surface[i] = 0; + rsurf[i] = cut; //Maximum range that can be seen + if (coordination[i] < divR_limit) { + surface[i] = 2; + rsurf[i] = 0.0; + if (coordination[i] < coord_limit) surface[i] = 3; + } + } + } + } + + //comm_stage = 1; + //comm_forward = 1; + //comm->forward_comm_fix(this); // communicate free surface particles + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + if (rsq < cutsq) { + r = sqrt(rsq); + if (surface[i] == 0 && surface[j] == 2) surface[i] = 1; + if (surface[j] == 0 && surface[i] == 2) surface[j] = 1; + if (surface[j] == 2) rsurf[i] = MIN(rsurf[i], r); + if (surface[i] == 2) rsurf[j] = MIN(rsurf[j], r); + } + } + } + + comm_stage = 1; + comm_reverse = 2; + comm_forward = 2; + if (newton) comm->reverse_comm_fix(this); + comm->forward_comm_fix(this); + + //Now loop again and for each surface particle (2) + // find its neighbors that are bulk (0) and convert to surface vicinity (1) + // if the surface particle has no (0) or (1) neighbors then it is a spash (3) + + //for (ii = 0; ii < inum; ii++) { // is this the right i and j loop for this? + // i = ilist[ii]; + // + // if (surface[i]!=2) continue; //Only consider surface particles + // + // bool nobulkneigh = true; // whether we have no bulk neighbors + // xtmp = x[i][0]; + // ytmp = x[i][1]; + // ztmp = x[i][2]; + // jlist = firstneigh[i]; + // jnum = numneigh[i]; + // + // for (jj = 0; jj < jnum; jj++) { + // j = jlist[jj]; + // j &= NEIGHMASK; + // + // //other surface or splash neighbors do not need labeling + // if (surface[j]>=2){ + // continue; + // } + // + // //check distance criterion rij < h = cutsq/9 for quintic kernel + // delx = xtmp - x[j][0]; + // dely = ytmp - x[j][1]; + // delz = ztmp - x[j][2]; + // dx[0] = 3.0*delx; // multiplied by three here to make criterion rreverse_comm_fix(this); +// +// +// // Now need to invert each B +// int status, s; +// //LU requires a permuation matrix +// gsl_permutation * p = gsl_permutation_alloc(dim); +// for (ii = 0; ii < inum; ii++) { +// i = ilist[ii]; +// if ((surface[i]==0)||(surface[i]==3)){ +// continue; +// } +// +// //Use gsl to get Binv +// //B is not symmteric so we will use a LU decomp +// gsl_matrix_view gB = gsl_matrix_view_array(B[i],dim,dim); +// status = 0; +// status = gsl_linalg_LU_decomp(&gB.matrix,p,&s); //B[i] is now the LU decomp +// // check if decomposition failure +// if (status) { +// fprintf(stderr, "failed, gsl_errno=%d.n", status); +// continue; +// } else { +// gsl_linalg_LU_invx(&gB.matrix,p); //B[i] is now inv(B[i]) +// } +// } +// gsl_permutation_free(p); + double maggC = 0.0; + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + maggC=0; + for (a=0;adimension; + int *surface = atom->surface; + double *rsurf = atom->dvector[index_rsurf]; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (comm_stage == 0) { + buf[m++] = divr[i]; + for (a = 0; a < dim; a ++ ) + for (b = 0; b < dim; b ++) + buf[m++] = gradC[i][a*dim + b]; + } else if (comm_stage == 1) { + buf[m++] = (double) surface[i]; + buf[m++] = rsurf[i]; + } else if (comm_stage == 2) { + for (a = 0; a < dim; a ++ ) + for (b = 0; b < dim; b ++) + buf[m++] = B[i][a*dim + b]; + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOSurface::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i,a,b,k,j,m; + int dim = domain->dimension; + int *surface = atom->surface; + double *rsurf = atom->dvector[index_rsurf]; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + if (comm_stage == 0) { + divr[j] += buf[m++]; + for (a = 0; a < dim; a ++ ) + for (b = 0; b < dim; b ++) + gradC[j][a*dim + b] += buf[m++]; + } else if (comm_stage == 1) { + int temp = (int) buf[m++]; + surface[j] = MAX(surface[j], temp); + double temp2 = buf[m++]; + rsurf[j] = MIN(rsurf[j], temp2); + } else if (comm_stage == 2) { + for (a = 0; a < dim; a ++ ) + for (b = 0; b < dim; b ++) + B[j][a*dim + b] += buf[m++]; + } + } +} + + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOSurface::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,a,b,k,m; + int *surface = atom->surface; + double *rsurf = atom->dvector[index_rsurf]; + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + if (comm_stage == 0) { + buf[m++] = divr[j]; + } else if (comm_stage == 1) { + buf[m++] = (double) surface[j]; + buf[m++] = rsurf[j]; + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOSurface::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, a, b, m, last; + int *surface = atom->surface; + double *rsurf = atom->dvector[index_rsurf]; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (comm_stage == 0) { + divr[i] = buf[m++]; + } else if (comm_stage == 1) { + surface[i] = (int) buf[m++]; + rsurf[i] = buf[m++]; + } + } +} diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h new file mode 100644 index 0000000000..480a8cd8ec --- /dev/null +++ b/src/RHEO/compute_rheo_surface.h @@ -0,0 +1,72 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(RHEO/SURFACE,ComputeRHEOSurface) +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_INTERFACE_H +#define LMP_COMPUTE_RHEO_INTERFACE_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEOSurface : public Compute { + public: + ComputeRHEOSurface(class LAMMPS *, int, char **); + ~ComputeRHEOSurface(); + void init() override; + void init_list(int, class NeighList *) override; + void compute_peratom() override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + + double **gradC, **n_surface; + + private: + double cut, cutsq, threshold; + int surface_style, nmax_old; + double **B, *divr; + int comm_stage; + + int index_divr; + int index_rsurf; + + double divR_limit; + int coord_limit; + + class NeighList *list; + class FixRHEO *fix_rheo; + class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOSolids *compute_solids; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +*/ diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h index af5675fd8d..e76476e7fd 100644 --- a/src/RHEO/compute_rheo_vshift.h +++ b/src/RHEO/compute_rheo_vshift.h @@ -13,7 +13,7 @@ #ifdef COMPUTE_CLASS // clang-format off -ComputeStyle(rheo/vshift,ComputeRHEOVShift) +ComputeStyle(RHEO/VSHIFT,ComputeRHEOVShift) // clang-format on #else diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index e83a95751a..8fc48c0b3b 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -88,12 +88,24 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : thermal_flag = 1; } else if (strcmp(arg[iarg],"surface/detection") == 0) { surface_flag = 1; + if(iarg + 2 >= narg) error->all(FLERR,"Illegal surface/detection option in fix rheo"); + if (strcmp(arg[iarg + 1], "coordination")) { + surface_style = COORDINATION; + zmin_surface = utils::inumeric(FLERR,arg[iarg + 2],false,lmp); + } else if (strcmp(arg[iarg + 1], "divergence")) { + surface_style = DIVR; + divr_surface = utils::numeric(FLERR,arg[iarg + 2],false,lmp); + } else { + error->all(FLERR,"Illegal surface/detection option in fix rheo, {}", arg[iarg + 1]); + } + + iarg += 2; } else if (strcmp(arg[iarg],"interface/reconstruction") == 0) { interface_flag = 1; } else if (strcmp(arg[iarg],"rhosum") == 0) { rhosum_flag = 1; if(iarg + 1 >= narg) error->all(FLERR,"Illegal rhosum option in fix rheo"); - zmin_rhosum = utils::inumeric(FLERR,arg[iarg + 1],false,lmp); + rhosum_zmin = utils::inumeric(FLERR,arg[iarg + 1],false,lmp); iarg += 1; } else if (strcmp(arg[iarg],"rho0") == 0) { if(iarg + 1 >= narg) error->all(FLERR,"Illegal rho0 option in fix rheo"); @@ -117,6 +129,7 @@ FixRHEO::~FixRHEO() if (compute_kernel) modify->delete_compute("rheo_kernel"); if (compute_grad) modify->delete_compute("rheo_grad"); if (compute_interface) modify->delete_compute("rheo_interface"); + if (compute_surface) modify->delete_compute("compute_surface"); if (compute_rhosum) modify->delete_compute("rheo_rhosum"); if (compute_vshift) modify->delete_compute("rheo_vshift"); } @@ -128,28 +141,33 @@ FixRHEO::~FixRHEO() void FixRHEO::post_constructor() { - compute_kernel = dynamic_cast(modify->add_compute("rheo_kernel all rheo/kernel")); + compute_kernel = dynamic_cast(modify->add_compute("rheo_kernel all RHEO/KERNEL")); compute_kernel->fix_rheo = this; - std::string cmd = "rheo_grad all rheo/grad velocity rho viscosity"; + std::string cmd = "rheo_grad all RHEO/GRAD velocity rho viscosity"; if (thermal_flag) cmd += "temperature"; compute_grad = dynamic_cast(modify->add_compute(cmd)); compute_grad->fix_rheo = this; if (rhosum_flag) { - compute_rhosum = dynamic_cast(modify->add_compute("rheo_rhosum all rheo/rho/sum")); + compute_rhosum = dynamic_cast(modify->add_compute("rheo_rhosum all RHEO/RHO/SUM")); compute_rhosum->fix_rheo = this; } if (shift_flag) { - compute_vshift = dynamic_cast(modify->add_compute("rheo_vshift all rheo/vshift")); + compute_vshift = dynamic_cast(modify->add_compute("rheo_vshift all RHEO/VSHIFT")); compute_vshift->fix_rheo = this; } if (interface_flag) { - compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all rheo/interface"))); + compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all RHEO/INTERFACE"))); compute_interface->fix_rheo = this; } + + if (surface_flag) { + compute_surface = dynamic_cast(modify->add_compute(fmt::format("rheo_surface all RHEO/SURFACE"))); + compute_surface->fix_rheo = this; + } } /* ---------------------------------------------------------------------- */ @@ -180,10 +198,11 @@ void FixRHEO::setup_pre_force(int /*vflag*/) { // Check to confirm accessory fixes do not preceed FixRHEO // Note: these fixes set this flag in setup_pre_force() - if (viscosity_fix_defined || pressure_fix_defined || thermal_fix_defined || surface_fix_defined) + if (viscosity_fix_defined || pressure_fix_defined || thermal_fix_defined) error->all(FLERR, "Fix RHEO must be defined before all other RHEO fixes"); - pre_force(0); + // Calculate surfaces + if (surface_flag) compute_surface->compute_peratom(); } /* ---------------------------------------------------------------------- */ @@ -201,14 +220,10 @@ void FixRHEO::setup() if(!thermal_fix_defined && thermal_flag) error->all(FLERR, "Missing fix rheo/thermal"); - if(!surface_fix_defined && surface_flag) - error->all(FLERR, "Missing fix rheo/surface"); - // Reset to zero for next run thermal_fix_defined = 0; viscosity_fix_defined = 0; pressure_fix_defined = 0; - surface_fix_defined = 0; // Check fixes cover all atoms (doesnt ensure user covers atoms created midrun) // (pressure is currently required to be group all) @@ -259,7 +274,8 @@ void FixRHEO::initial_integrate(int /*vflag*/) double **gradr = compute_grad->gradr; double **gradv = compute_grad->gradv; - double **vshift = compute_vshift->vshift; + double **vshift; + if (shift_flag) compute_vshift->vshift; int *type = atom->type; int *mask = atom->mask; @@ -287,8 +303,11 @@ void FixRHEO::initial_integrate(int /*vflag*/) // Update gradients and interpolate solid properties compute_grad->forward_fields(); // also forwards v and rho for chi - compute_interface->store_forces(); // Need to save, wiped in exchange - compute_interface->compute_peratom(); + if (interface_flag) { + // Need to save, wiped in exchange + compute_interface->store_forces(); + compute_interface->compute_peratom(); + } compute_grad->compute_peratom(); // Position half-step @@ -350,7 +369,7 @@ void FixRHEO::pre_force(int /*vflag*/) compute_grad->forward_fields(); // also forwards v and rho for chi compute_kernel->compute_peratom(); - compute_interface->compute_peratom(); + if (interface_flag) compute_interface->compute_peratom(); compute_grad->compute_peratom(); compute_grad->forward_gradients(); @@ -369,6 +388,9 @@ void FixRHEO::pre_force(int /*vflag*/) status[i] &= ~STATUS_SHIFT; } } + + // Calculate surfaces, update status + if (surface_flag) compute_surface->compute_peratom(); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 89304fe22f..d2097ade71 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -40,9 +40,11 @@ class FixRHEO : public Fix { // Model parameters double h, rho0, csq; - int zmin_kernel, rhosum_zmin; - int kernel_style; + int zmin_kernel, zmin_rhosum, zmin_surface; + int kernel_style, surface_style; + double divr_surface; enum {QUINTIC, CRK0, CRK1, CRK2}; + enum {COORDINATION, DIVR}; // Status variables enum { @@ -75,8 +77,6 @@ class FixRHEO : public Fix { int viscosity_fix_defined; int pressure_fix_defined; int thermal_fix_defined; - int interface_fix_defined; - int surface_fix_defined; class ComputeRHEOGrad *compute_grad; class ComputeRHEOKernel *compute_kernel; From a4d971df526e71f04a8de31b642ddd512100e89c Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 20 Apr 2023 14:45:35 -0600 Subject: [PATCH 024/385] Updating surface compute --- src/RHEO/compute_rheo_grad.cpp | 2 +- src/RHEO/compute_rheo_interface.cpp | 1 - src/RHEO/compute_rheo_kernel.cpp | 12 +- src/RHEO/compute_rheo_surface.cpp | 528 ++++++++++------------------ src/RHEO/compute_rheo_surface.h | 13 +- src/RHEO/compute_rheo_vshift.cpp | 2 +- src/RHEO/fix_rheo.cpp | 2 +- src/RHEO/fix_rheo_thermal.cpp | 4 +- src/RHEO/pair_rheo.cpp | 4 +- 9 files changed, 195 insertions(+), 373 deletions(-) diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 31f60550c1..add3ed712d 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -38,7 +38,7 @@ enum{COMMGRAD, COMMFIELD}; /* ---------------------------------------------------------------------- */ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), fix_rheo(nullptr), compute_interface(nullptr), compute_kernel(nullptr), + Compute(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), compute_interface(nullptr), compute_kernel(nullptr), gradv(nullptr), gradr(nullptr), gradt(nullptr), gradn(nullptr) { if (narg < 4) error->all(FLERR,"Illegal compute rheo/grad command"); diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 55cb81382b..059f4057f4 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -84,7 +84,6 @@ void ComputeRHEOInterface::init() // Do not create grow callback as there's no reason to copy/exchange data // Manually grow if nmax_old exceeded - int create_flag = 0; int tmp1, tmp2; int nmax = atom->nmax; int index = atom->find_custom("rheo_chi", tmp1, tmp2); diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index ac9ea75fc4..2fd189e1e4 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -55,7 +55,7 @@ Move away from h notation, use cut? ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), - C(nullptr), C0(nullptr), coordination(nullptr), compute_interface(nullptr) + list(nullptr), C(nullptr), C0(nullptr), coordination(nullptr), compute_interface(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute rheo/kernel command"); @@ -137,18 +137,18 @@ void ComputeRHEOKernel::init() ncor = 0; Mdim = 0; if (kernel_type == CRK0) { - memory->create(C0, nmax, "rheo/kernel:C0"); + memory->create(C0, nmax_old, "rheo/kernel:C0"); } else if (kernel_type == CRK1) { Mdim = 1 + dim; ncor = 1 + dim; - memory->create(C, nmax, ncor, Mdim, "rheo/kernel:C"); + memory->create(C, nmax_old, ncor, Mdim, "rheo/kernel:C"); comm_forward = ncor * Mdim; } else if (kernel_type == CRK2) { //Polynomial basis size (up to quadratic order) Mdim = 1 + dim + dim * (dim + 1) / 2; //Number of sets of correction coefficients (1 x y xx yy) + z zz (3D) ncor = 1 + 2 * dim; - memory->create(C, nmax, ncor, Mdim, "rheo/kernel:C"); + memory->create(C, nmax_old, ncor, Mdim, "rheo/kernel:C"); comm_forward = ncor * Mdim; } } @@ -491,7 +491,7 @@ void ComputeRHEOKernel::compute_peratom() gsl_error_flag = 0; gsl_error_tags.clear(); - int i, j, ii, jj, jnum, g, a, b, gsl_error; + int i, j, ii, jj, inum, jnum, g, a, b, gsl_error; double xtmp, ytmp, ztmp, r, rsq, w, vj; double dx[3]; gsl_matrix_view gM; @@ -506,7 +506,7 @@ void ComputeRHEOKernel::compute_peratom() int *status = atom->status; tagint *tag = atom->tag; - int inum, *ilist, *jlist, *numneigh, **firstneigh; + int *ilist, *jlist, *numneigh, **firstneigh; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index dff5db4cfa..5b3aeabf26 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -18,135 +18,97 @@ #include "compute_rheo_surface.h" -#include "fix_rheo.h" -#include "compute_rheo_kernel.h" -#include "compute_rheo_solids.h" -#include "atom.h" -#include "memory.h" #include "atom.h" #include "comm.h" -#include "modify.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_solids.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "math_extra.h" +#include "memory.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" -#include "error.h" -#include "force.h" -#include "domain.h" using namespace LAMMPS_NS; using namespace FixConst; +using namespace MathExtra; + +#define epsilon 1e-10; /* ---------------------------------------------------------------------- */ ComputeRHEOSurface::ComputeRHEOSurface(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg) + Fix(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), compute_kernel(nullptr), compute_solids(nullptr), + B(nullptr), gradC(nullptr), nsurface(nullptr), divr(nullptr), rsurface(nullptr) { - if (narg < 6) error->all(FLERR,"Illegal fix rheo/surface command"); - - cut = utils::numeric(FLERR,arg[3],false,lmp); - divR_limit = utils::numeric(FLERR,arg[4],false,lmp); - coord_limit = utils::inumeric(FLERR,arg[5],false,lmp); - - divr_flag = 1; - if (narg == 7) { - divr_flag = 0; - } + if (narg != 3) error->all(FLERR,"Illegal fix RHEO/SURFACE command"); int dim = domain->dimension; - - peratom_flag = 1; - size_peratom_cols = dim; - peratom_freq = 1; - - comm_forward = 2; - comm_reverse = dim*dim + 1; - - cutsq = cut*cut; - - B = nullptr; - gradC = nullptr; - n_surface = nullptr; - - int nall = atom->nlocal + atom->nghost; - nmax = nall; - memory->create(B,nmax,dim*dim,"fix/rheo/surface:B"); - memory->create(gradC,nmax,dim*dim,"fix/rheo/surface:gradC"); - memory->create(n_surface,nmax,dim,"fix/rheo/surface:B"); - array_atom = n_surface; - - compute_kernel = nullptr; - compute_solids = NULL; - fix_rheo = nullptr; + comm_reverse = dim * dim + 1; } /* ---------------------------------------------------------------------- */ ComputeRHEOSurface::~ComputeRHEOSurface() { - if (modify->nfix) modify->delete_fix("PROPERTY_ATOM_RHEO_SURFACE"); + // Remove custom property if it exists + int tmp1, tmp2, index; + index = atom->find_custom("rheo_divr", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 0); + + index = atom->find_custom("rheo_rsurface", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 0); + + index = atom->find_custom("rheo_nsurface", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 3); memory->destroy(B); memory->destroy(gradC); - memory->destroy(n_surface); -} - -void ComputeRHEOSurface::post_constructor() -{ - //Store persistent per atom quantities - char **fixarg = new char*[5]; - fixarg[0] = (char *) "PROPERTY_ATOM_RHEO_SURFACE"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "property/atom"; - fixarg[3] = (char *) "d_divr"; - fixarg[4] = (char *) "d_rsurf"; - modify->add_fix(5,fixarg,1); - - int temp_flag; - index_divr = atom->find_custom("divr", temp_flag); - if ((index_divr < 0) || (temp_flag != 1)) - error->all(FLERR, "Pair rheo/surface can't find fix property/atom divr"); - - index_rsurf = atom->find_custom("rsurf", temp_flag); - if ((index_rsurf < 0) || (temp_flag != 1)) - error->all(FLERR, "Pair rheo/surface can't find fix property/atom rsurf"); - - delete [] fixarg; - divr = atom->dvector[index_divr]; -} -/* ---------------------------------------------------------------------- */ - -int ComputeRHEOSurface::setmask() -{ - int mask = 0; - mask |= PRE_FORCE; - return mask; } /* ---------------------------------------------------------------------- */ void ComputeRHEOSurface::init() { - // need an occasional full neighbor list - int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->pair = 0; - neighbor->requests[irequest]->fix = 1; - neighbor->requests[irequest]->half = 1; - neighbor->requests[irequest]->full = 0; - - int flag; - int ifix = modify->find_fix_by_style("rheo"); - if (ifix == -1) error->all(FLERR, "Need to define fix rheo to use fix rheo/surface"); - fix_rheo = ((FixRHEO *) modify->fix[ifix]); compute_kernel = fix_rheo->compute_kernel; compute_solids = fix_rheo->compute_solids; -} + cut = fix_rheo->cut; + rho0 = fix_rheo->rho0; + threshold_style = fix_rheo->surface_style; + threshold_divr = fix_rheo->divrsurface; + threshold_z = fix_rheo->zminsurface; -/* ---------------------------------------------------------------------- */ + cutsq = cut * cut; -void ComputeRHEOSurface::setup_pre_force(int /*vflag*/) -{ - pre_force(0); + // Create rsurface, divr, nsurface arrays if they don't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_old exceeded + // For B and gradC, create a local array since they are unlikely to be printed + + int tmp1, tmp2; + int index = atom->find_custom("rheo_divr", tmp1, tmp2); + if (index == -1) index = atom->add_custom("rheo_divr", 1, 0); + divr = atom->dvector[index]; + + index = atom->find_custom("rheo_rsurface", tmp1, tmp2); + if (index == -1) index = atom->add_custom("rheo_rsurface", 1, 0); + rsurface = atom->dvector[index]; + + index = atom->find_custom("rheo_nsurface", tmp1, tmp2); + if (index == -1) index = atom->add_custom("rheo_nsurface", 1, 3); + nsurface = atom->darray[index]; + + nmax_old = atom->nmax; + memory->create(B, nmax_old, dim * dim, "rheo/surface:B"); + memory->create(gradC, nmax_old, dim * dim, "rheo/surface:gradC"); + + // need an occasional half neighbor list + neighbor->add_request(this, NeighConst::REQ_HALF); } /* ---------------------------------------------------------------------- */ @@ -158,60 +120,56 @@ void ComputeRHEOSurface::init_list(int /*id*/, NeighList *ptr) /* ---------------------------------------------------------------------- */ -void ComputeRHEOSurface::pre_force(int /*vflag*/) +void ComputeRHEOSurface::compute_peratom() { - int i, j, ii, jj, jnum, a, b, itype, jtype; - double xtmp, ytmp, ztmp, delx, dely, delz, rsq, r, wp, Voli, Volj, rhoi, rhoj; - int *jlist; + int i, j, ii, jj, inum, jnum, a, b, itype, jtype, fluidi, fluidj; + double xtmp, ytmp, ztmp, rsq, Voli, Volj, rhoi, rhoj; double *dWij, *dWji; double dx[3]; + int *ilist, *jlist, *numneigh, **firstneigh; - divr = atom->dvector[index_divr]; - - // neighbor list variables - int inum, *ilist, *numneigh, **firstneigh; int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; double **x = atom->x; - int *surface = atom->surface; - int *phase = atom->phase; - double *rsurf = atom->dvector[index_rsurf]; + int *status = atom->status; int newton = force->newton; int dim = domain->dimension; int *mask = atom->mask; int *type = atom->type; double *mass = atom->mass; double *rho = atom->rho; - double *temp = atom->temp; + int *coordination = compute_kernel->coordination; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; - if (nmax <= nall) { - nmax = nall; - memory->destroy(B); - memory->destroy(gradC); - memory->destroy(n_surface); + int nmax = atom->nmax; + if (nmax_old <= nmax) { + memory->grow(divr, nmax, "atom:rheo_divr"); + memory->grow(rsurface, nmax, "atom:rheo_rsurface"); + memory->grow(nsurface, nmax, 3, "atom:rheo_nsurface"); - memory->create(B,nmax,dim*dim,"fix/rheo/surface:B"); - memory->create(gradC,nmax,dim*dim,"fix/rheo/surface:gradC"); - memory->create(n_surface,nmax,dim,"fix/rheo/surface:n_surface"); - array_atom = n_surface; + memory->grow(B, nmax, dim * dim, "rheo/surface:B"); + memory->grow(gradC, nmax, dim * dim, "rheo/surface:gradC"); + + nmax_old = atom->nmax; } + int nall = nlocal + atom->nghost; for (i = 0; i < nall; i++) { for (a = 0; a < dim; a++) { for (b = 0; b < dim; b++) { - B[i][a*dim + b] = 0.0; - gradC[i][a*dim + b] = 0.0; + B[i][a * dim + b] = 0.0; + gradC[i][a * dim + b] = 0.0; } - n_surface[i][a] = 0.0; + nsurface[i][a] = 0.0; } divr[i] = 0.0; - surface[i] = 0; + + // Remove surface settings + status[i] &= FixRHEO::surfacemask; } // loop over neighbors to calculate the average orientation of neighbors @@ -224,98 +182,105 @@ void ComputeRHEOSurface::pre_force(int /*vflag*/) jlist = firstneigh[i]; jnum = numneigh[i]; itype = type[i]; + fluidi = status[i] & FixRHEO::STATUS_FLUID; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - dx[0] = delx; - dx[1] = dely; - dx[2] = delz; - rsq = delx * delx + dely * dely + delz * delz; + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + + rsq = lensq(dx); if (rsq < cutsq) { jtype = type[j]; + fluidj = status[j] & FixRHEO::STATUS_FLUID; rhoi = rho[i]; rhoj = rho[j]; // Add corrections for walls - if (phase[i] <= FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { - rhoj = compute_solids->correct_rho(j,i); - } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] <= FixRHEO::FLUID_MAX) { - rhoi = compute_solids->correct_rho(i,j); - } else if (phase[i] > FixRHEO::FLUID_MAX && phase[j] > FixRHEO::FLUID_MAX) { - rhoi = 1.0; - rhoj = 1.0; + if (fluidi && (!fluidj)) { + rhoj = compute_solids->correct_rho(j, i); + } else if ((!fluidi) && fluidj) { + rhoi = compute_solids->correct_rho(i, j); + } else if ((!fluidi) && (!fluidj)) { + rhoi = rho0; + rhoj = rho0; } - Voli = mass[itype]/rhoi; - Volj = mass[jtype]/rhoj; + Voli = mass[itype] / rhoi; + Volj = mass[jtype] / rhoj; - //compute kernel gradient - wp = compute_kernel->calc_dw_quintic(i, j, delx, dely, delz, sqrt(rsq),compute_kernel->dWij,compute_kernel->dWji); - //wp = compute_kernel->calc_dw(i, j, delx, dely, delz, sqrt(rsq));//,compute_kernel->dWij,compute_kernel->dWji); + wp = compute_kernel->calc_dw_quintic(i, j, dx[0], dx[1], dx[2], sqrt(rsq),dWij, dWji); - dWij = compute_kernel->dWij; - dWji = compute_kernel->dWji; - - for (a=0; areverse_comm_fix(this); - comm->forward_comm_fix(this); + comm_reverse = dim * dim + 1; + comm_forward = 1; + if (newton) comm->reverse_comm(this); + comm->forward_comm(this); + + // calculate nsurface for local atoms + // Note, this isn't forwarded to ghosts + double maggC; + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + maggC = 0.0; + for (a = 0;a < dim; a++) + maggC += gradC[i][a] * gradC[i][a]; + maggC = sqrt(maggC) + EPSILON; + maggC = 1.0 / maggC; + for (a = 0; a < dim; a++) + nsurface[i][a] = -gradC[i][a] * maggC; + } + } - int *coordination = compute_kernel->coordination; // Find the free-surface - //0-bulk 1-surf vicinity 2-surface 3-splash - if (divr_flag) { + if (threshold_style == FixRHEO::DIVR) { for (i = 0; i < nall; i++) { if (mask[i] & groupbit) { - surface[i] = 0; - rsurf[i] = cut; //Maximum range that can be seen - if (divr[i] < divR_limit) { - surface[i] = 2; - rsurf[i] = 0.0; - if (coordination[i] < coord_limit) surface[i] = 3; + status[i] |= FixRHEO::STATUS_BULK; + rsurface[i] = cut; + if (divr[i] < threshold_divr) { + status[i] |= FixRHEO::STATUS_SURFACE; + rsurface[i] = 0.0; + if (coordination[i] < threshold_z) + status[i] |= FixRHEO::STATUS_SPLASH; } } } } else { for (i = 0; i < nall; i++) { if (mask[i] & groupbit) { - surface[i] = 0; - rsurf[i] = cut; //Maximum range that can be seen + status[i] |= FixRHEO::STATUS_BULK; + rsurface[i] = cut; if (coordination[i] < divR_limit) { - surface[i] = 2; - rsurf[i] = 0.0; - if (coordination[i] < coord_limit) surface[i] = 3; + status[i] |= FixRHEO::STATUS_SURFACE; + rsurface[i] = 0.0; + if (coordination[i] < threshold_z) + status[i] |= FixRHEO::STATUS_SPLASH; } } } } - //comm_stage = 1; - //comm_forward = 1; - //comm->forward_comm_fix(this); // communicate free surface particles - for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; @@ -329,167 +294,37 @@ void ComputeRHEOSurface::pre_force(int /*vflag*/) j = jlist[jj]; j &= NEIGHMASK; - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx * delx + dely * dely + delz * delz; + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = lensq(dx); if (rsq < cutsq) { - r = sqrt(rsq); - if (surface[i] == 0 && surface[j] == 2) surface[i] = 1; - if (surface[j] == 0 && surface[i] == 2) surface[j] = 1; - if (surface[j] == 2) rsurf[i] = MIN(rsurf[i], r); - if (surface[i] == 2) rsurf[j] = MIN(rsurf[j], r); + if ((status[i] & FixRHEO::STATUS_BULK) && (status[j] & FixRHEO::STATUS_SURFACE)) { + status[i] &= FixRHEO::surfacemask; + status[i] |= FixRHEO::STATUS_LAYER; + } + + if (status[j] & FixRHEO::STATUS_SURFACE) rsurface[i] = MIN(rsurface[i], sqrt(rsq)); + + + if (j < nlocal || newton) { + if ((status[j] & FixRHEO::STATUS_BULK) && (status[i] & FixRHEO::STATUS_SURFACE)) { + status[j] &= FixRHEO::surfacemask; + status[j] |= FixRHEO::STATUS_LAYER; + } + + if (status[i] & FixRHEO::STATUS_SURFACE) rsurface[j] = MIN(rsurface[j], sqrt(rsq)); + } } } } + // forward/reverse status and rsurface comm_stage = 1; comm_reverse = 2; comm_forward = 2; - if (newton) comm->reverse_comm_fix(this); - comm->forward_comm_fix(this); - - //Now loop again and for each surface particle (2) - // find its neighbors that are bulk (0) and convert to surface vicinity (1) - // if the surface particle has no (0) or (1) neighbors then it is a spash (3) - - //for (ii = 0; ii < inum; ii++) { // is this the right i and j loop for this? - // i = ilist[ii]; - // - // if (surface[i]!=2) continue; //Only consider surface particles - // - // bool nobulkneigh = true; // whether we have no bulk neighbors - // xtmp = x[i][0]; - // ytmp = x[i][1]; - // ztmp = x[i][2]; - // jlist = firstneigh[i]; - // jnum = numneigh[i]; - // - // for (jj = 0; jj < jnum; jj++) { - // j = jlist[jj]; - // j &= NEIGHMASK; - // - // //other surface or splash neighbors do not need labeling - // if (surface[j]>=2){ - // continue; - // } - // - // //check distance criterion rij < h = cutsq/9 for quintic kernel - // delx = xtmp - x[j][0]; - // dely = ytmp - x[j][1]; - // delz = ztmp - x[j][2]; - // dx[0] = 3.0*delx; // multiplied by three here to make criterion rreverse_comm_fix(this); -// -// -// // Now need to invert each B -// int status, s; -// //LU requires a permuation matrix -// gsl_permutation * p = gsl_permutation_alloc(dim); -// for (ii = 0; ii < inum; ii++) { -// i = ilist[ii]; -// if ((surface[i]==0)||(surface[i]==3)){ -// continue; -// } -// -// //Use gsl to get Binv -// //B is not symmteric so we will use a LU decomp -// gsl_matrix_view gB = gsl_matrix_view_array(B[i],dim,dim); -// status = 0; -// status = gsl_linalg_LU_decomp(&gB.matrix,p,&s); //B[i] is now the LU decomp -// // check if decomposition failure -// if (status) { -// fprintf(stderr, "failed, gsl_errno=%d.n", status); -// continue; -// } else { -// gsl_linalg_LU_invx(&gB.matrix,p); //B[i] is now inv(B[i]) -// } -// } -// gsl_permutation_free(p); - double maggC = 0.0; - for (i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) { - maggC=0; - for (a=0;areverse_comm(this); + comm->forward_comm(this); } /* ---------------------------------------------------------------------- */ @@ -498,8 +333,7 @@ int ComputeRHEOSurface::pack_reverse_comm(int n, int first, double *buf) { int i,a,b,k,m,last; int dim = domain->dimension; - int *surface = atom->surface; - double *rsurf = atom->dvector[index_rsurf]; + int *status = atom->status; m = 0; last = first + n; @@ -508,14 +342,10 @@ int ComputeRHEOSurface::pack_reverse_comm(int n, int first, double *buf) buf[m++] = divr[i]; for (a = 0; a < dim; a ++ ) for (b = 0; b < dim; b ++) - buf[m++] = gradC[i][a*dim + b]; + buf[m++] = gradC[i][a * dim + b]; } else if (comm_stage == 1) { - buf[m++] = (double) surface[i]; - buf[m++] = rsurf[i]; - } else if (comm_stage == 2) { - for (a = 0; a < dim; a ++ ) - for (b = 0; b < dim; b ++) - buf[m++] = B[i][a*dim + b]; + buf[m++] = (double) status[i]; + buf[m++] = rsurface[i]; } } return m; @@ -527,8 +357,8 @@ void ComputeRHEOSurface::unpack_reverse_comm(int n, int *list, double *buf) { int i,a,b,k,j,m; int dim = domain->dimension; - int *surface = atom->surface; - double *rsurf = atom->dvector[index_rsurf]; + int *status = atom->status; + int temp; m = 0; for (i = 0; i < n; i++) { @@ -537,16 +367,14 @@ void ComputeRHEOSurface::unpack_reverse_comm(int n, int *list, double *buf) divr[j] += buf[m++]; for (a = 0; a < dim; a ++ ) for (b = 0; b < dim; b ++) - gradC[j][a*dim + b] += buf[m++]; + gradC[j][a * dim + b] += buf[m++]; } else if (comm_stage == 1) { - int temp = (int) buf[m++]; - surface[j] = MAX(surface[j], temp); - double temp2 = buf[m++]; - rsurf[j] = MIN(rsurf[j], temp2); - } else if (comm_stage == 2) { - for (a = 0; a < dim; a ++ ) - for (b = 0; b < dim; b ++) - B[j][a*dim + b] += buf[m++]; + + temp = (int) buf[m++]; + if ((status[j] & FixRHEO::STATUS_BULK) && (temp & FixRHEO::STATUS_LAYER)) + status[j] = temp; + + rsurface[j] = MIN(rsurface[j], buf[m++]); } } } @@ -558,8 +386,7 @@ int ComputeRHEOSurface::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,a,b,k,m; - int *surface = atom->surface; - double *rsurf = atom->dvector[index_rsurf]; + int *status = atom->status; m = 0; for (i = 0; i < n; i++) { @@ -567,8 +394,8 @@ int ComputeRHEOSurface::pack_forward_comm(int n, int *list, double *buf, if (comm_stage == 0) { buf[m++] = divr[j]; } else if (comm_stage == 1) { - buf[m++] = (double) surface[j]; - buf[m++] = rsurf[j]; + buf[m++] = (double) status[j]; + buf[m++] = rsurface[j]; } } return m; @@ -579,8 +406,7 @@ int ComputeRHEOSurface::pack_forward_comm(int n, int *list, double *buf, void ComputeRHEOSurface::unpack_forward_comm(int n, int first, double *buf) { int i, k, a, b, m, last; - int *surface = atom->surface; - double *rsurf = atom->dvector[index_rsurf]; + int *status = atom->status; m = 0; last = first + n; @@ -588,8 +414,8 @@ void ComputeRHEOSurface::unpack_forward_comm(int n, int first, double *buf) if (comm_stage == 0) { divr[i] = buf[m++]; } else if (comm_stage == 1) { - surface[i] = (int) buf[m++]; - rsurf[i] = buf[m++]; + status[i] = (int) buf[m++]; + rsurface[i] = buf[m++]; } } } diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 480a8cd8ec..8d0b681c6f 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -36,16 +36,13 @@ class ComputeRHEOSurface : public Compute { int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; - double **gradC, **n_surface; + double **nsurface, **rsurface; private: - double cut, cutsq, threshold; - int surface_style, nmax_old; - double **B, *divr; - int comm_stage; - - int index_divr; - int index_rsurf; + double cut, cutsq, rho0, threshold_divr; + int surface_style, nmax_old, threshold_z; + double **B, **gradC, *divr; + int threshold_style, comm_stage; double divR_limit; int coord_limit; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 6cbd6e96da..1b3edcffd8 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -36,7 +36,7 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ ComputeRHEOVShift::ComputeRHEOVShift(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), vshift(nullptr), fix_rheo(nullptr), fix_rheo(nullptr), + Compute(lmp, narg, arg), list(nullptr), vshift(nullptr), fix_rheo(nullptr), compute_kernel(nullptr), compute_interface(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute RHEO/VShift command"); diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 8fc48c0b3b..5358cc4cba 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -377,7 +377,7 @@ void FixRHEO::pre_force(int /*vflag*/) if (shift_flag) compute_vshift->compute_peratom(); - // Remove extra shifting/no force options options + // Remove extra shifting/no force options int *status = atom->status; int nall = atom->nlocal + atom->nghost; for (int i = 0; i < nall; i++) { diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 1912dc9f8c..fd08f39fd7 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -269,10 +269,10 @@ void FixRHEOThermal::post_integrate() } if (Ti > Tci) { - status[i] &= phasemask; + status[i] &= FixRHEO::phasemask; status[i] |= FixRHEO::STATUS_FLUID; } else if (!(status[i] & FixRHEO::STATUS_SOLID)) - status[i] &= phasemask; + status[i] &= FixRHEO::phasemask; status[i] |= FixRHEO::STATUS_FREEZING; } } diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 1eb2a43e1a..5974b9b756 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -216,8 +216,8 @@ void PairRHEO::compute(int eflag, int vflag) fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; } else if ((!fluidi) && (!fluidj)) { - rhoi = 1.0; - rhoj = 1.0; + rhoi = rho0; + rhoj = rho0; } // Repel if close to inner solid particle From de0e4bb170f7a2f7ae59616ca4f4d203e6eccc68 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 20 Apr 2023 16:17:04 -0600 Subject: [PATCH 025/385] Rho sum compute --- src/RHEO/compute_rheo_kernel.cpp | 234 ++++++++++++++++-------------- src/RHEO/compute_rheo_kernel.h | 3 + src/RHEO/compute_rheo_rho_sum.cpp | 184 +++++++++++++++++++++++ src/RHEO/compute_rheo_rho_sum.h | 50 +++++++ src/RHEO/compute_rheo_surface.cpp | 2 +- src/RHEO/compute_rheo_surface.h | 17 +-- src/RHEO/fix_rheo.cpp | 6 +- 7 files changed, 371 insertions(+), 125 deletions(-) create mode 100644 src/RHEO/compute_rheo_rho_sum.cpp create mode 100644 src/RHEO/compute_rheo_rho_sum.h diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 2fd189e1e4..c0b61daae3 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -47,21 +47,46 @@ using namespace MathExtra; enum {QUINTIC, CRK0, CRK1, CRK2}; #define DELTA 2000 -Todo: convert delx dely delz to an array -Should vshift be using kernel quintic? -Move away from h notation, use cut? - /* ---------------------------------------------------------------------- */ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), list(nullptr), C(nullptr), C0(nullptr), coordination(nullptr), compute_interface(nullptr) { - if (narg != 3) error->all(FLERR,"Illegal compute rheo/kernel command"); + if (narg != 4) error->all(FLERR,"Illegal compute rheo/kernel command"); + + kernel_style = (SubModelType) utils::inumeric(FLERR,arg[3],false,lmp); + + + if (kernel_style == FixRHEO::QUINTIC) { + correction_order = -1; + } else if (kernel_style == FixRHEO::CRK0) { + correction_order = 0; + } else if (kernel_style == FixRHEO::CRK1) { + correction_order = 1; + } else if (kernel_style == FixRHEO::CRK2) { + correction_order = 2; + } - comm_forward = 1; // Always minimum for coordination solid_flag = 0; dim = domain->dimension; + + comm_forward = 1; + ncor = 0; + Mdim = 0; + if (kernel_type == CRK1) { + Mdim = 1 + dim; + ncor = 1 + dim; + comm_forward = ncor * Mdim; + } else if (kernel_type == CRK2) { + //Polynomial basis size (up to quadratic order) + Mdim = 1 + dim + dim * (dim + 1) / 2; + //Number of sets of correction coefficients (1 x y xx yy) + z zz (3D) + ncor = 1 + 2 * dim; + comm_forward = ncor * Mdim; + } + + comm_forward_save = comm_forward; } /* ---------------------------------------------------------------------- */ @@ -93,22 +118,12 @@ void ComputeRHEOKernel::init() solid_flag = 1; } - kernel_style = fix_rheo->kernel_style; zmin = fix_rheo->zmin_kernel; h = fix_rheo->h; hsq = h * h; hinv = 1.0 / h; hsqinv = hinv * hinv; - if (kernel_style == FixRHEO::QUINTIC) { - correction_order = -1; - } else if (kernel_style == FixRHEO::CRK0) { - correction_order = 0; - } else if (kernel_style == FixRHEO::CRK1) { - correction_order = 1; - } else if (kernel_style == FixRHEO::CRK2) { - correction_order = 2; - } if (dim == 3) { pre_w = 0.002652582384864922 * 27.0 * ihsq * ih; @@ -133,23 +148,13 @@ void ComputeRHEOKernel::init() coordination = atom->ivector[index]; // Create local arrays for kernel arrays, I can't foresee a reason to print - comm_forward = 1; - ncor = 0; - Mdim = 0; + if (kernel_type == CRK0) { memory->create(C0, nmax_old, "rheo/kernel:C0"); } else if (kernel_type == CRK1) { - Mdim = 1 + dim; - ncor = 1 + dim; memory->create(C, nmax_old, ncor, Mdim, "rheo/kernel:C"); - comm_forward = ncor * Mdim; } else if (kernel_type == CRK2) { - //Polynomial basis size (up to quadratic order) - Mdim = 1 + dim + dim * (dim + 1) / 2; - //Number of sets of correction coefficients (1 x y xx yy) + z zz (3D) - ncor = 1 + 2 * dim; memory->create(C, nmax_old, ncor, Mdim, "rheo/kernel:C"); - comm_forward = ncor * Mdim; } } @@ -491,6 +496,8 @@ void ComputeRHEOKernel::compute_peratom() gsl_error_flag = 0; gsl_error_tags.clear(); + if (kernel_type == FixRHEO::QUINTIC) return; + int i, j, ii, jj, inum, jnum, g, a, b, gsl_error; double xtmp, ytmp, ztmp, r, rsq, w, vj; double dx[3]; @@ -513,48 +520,11 @@ void ComputeRHEOKernel::compute_peratom() firstneigh = list->firstneigh; // Grow arrays if necessary - int nmax = atom->nmax; - if (nmax_old < nmax) - memory->grow(coordination, nmax, "atom:rheo_coordination"); + if (nmax_old < atom->nmax) grow_arrays(atom->nmax); - if (kernel_type == FixRHEO::CRK0) { - memory->grow(C0, nmax, "rheo/kernel:C0"); - } else if (correction_order > 0) { - memory->grow(C, nmax, ncor, Mdim, "rheo/kernel:C"); - } - - nmax_old = atom->nmax; - } - - if (kernel_type == FixRHEO::QUINTIC) { - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - - jlist = firstneigh[i]; - jnum = numneigh[i]; - coordination[i] = 0; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - dx[0] = xtmp - x[j][0]; - dx[1] = ytmp - x[j][1]; - dx[2] = ztmp - x[j][2]; - rsq = lensq(dx); - - if (rsq < hsq) { - coordination[i] += 1; - } - } - } - } else if (kernel_type == FixRHEO::CRK0) { + if (kernel_type == FixRHEO::CRK0) { double M; - for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; @@ -566,7 +536,6 @@ void ComputeRHEOKernel::compute_peratom() //Initialize M to zero: M = 0; - coordination[i] = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -584,7 +553,6 @@ void ComputeRHEOKernel::compute_peratom() vj = mass[type[j]] / compute_interface->correct_rho(j,i); } else vj = mass[type[j]] / rho[j]; - coordination[i] += 1; M += w * vj; } } @@ -613,7 +581,6 @@ void ComputeRHEOKernel::compute_peratom() M[a * Mdim + b] = 0; } } - coordination[i] = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -658,8 +625,6 @@ void ComputeRHEOKernel::compute_peratom() } } - coordination[i] += 1; - // Populate the upper triangle for (a = 0; a < Mdim; a++) { for (b = a; b < Mdim; b++) { @@ -733,7 +698,74 @@ void ComputeRHEOKernel::compute_peratom() } // communicate calculated quantities - comm->forward_comm_compute(this); + comm_stage = 1; + comm_forward = comm_forward_save; + comm->forward_comm(this); +} + + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::compute_coordination() +{ + int i, j, ii, jj, inum, jnum; + double xtmp, ytmp, ztmp, rsq; + double dx[3]; + + double **x = atom->x; + + int *ilist, *jlist, *numneigh, **firstneigh; + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // Grow arrays if necessary + if (nmax_old < atom->nmax) grow_arrays(atom->nmax); + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + + jlist = firstneigh[i]; + jnum = numneigh[i]; + coordination[i] = 0; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = lensq(dx); + + if (rsq < hsq) + coordination[i] += 1; + } + } + + // communicate calculated quantities + comm_stage = 0; + comm_forward = 1; + comm->forward_comm(this); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOKernel::grow_arrays(int nmax) +{ + memory->grow(coordination, nmax, "atom:rheo_coordination"); + + if (kernel_type == FixRHEO::CRK0) { + memory->grow(C0, nmax, "rheo/kernel:C0"); + } else if (correction_order > 0) { + memory->grow(C, nmax, ncor, Mdim, "rheo/kernel:C"); + } + + nmax_old = nmax; } /* ---------------------------------------------------------------------- */ @@ -743,26 +775,19 @@ int ComputeRHEOKernel::pack_forward_comm(int n, int *list, double *buf, { int i,j,k,m,a,b; m = 0; - if (correction_order > 0) { - for (i = 0; i < n; i++) { - j = list[i]; - for (a = 0; a < ncor; a++) { - for (b = 0; b < Mdim; b++) { - buf[m++] = C[j][a][b]; - } + + for (i = 0; i < n; i++) { + j = list[i]; + if (comm_stage == 0) { + buf[m++] = coordination[j]; + } else { + if (kernel_type == FixRHEO::CRK0) { + buf[m++] = C0[j]; + } else { + for (a = 0; a < ncor; a++) + for (b = 0; b < Mdim; b++) + buf[m++] = C[j][a][b]; } - buf[m++] = coordination[j]; - } - } else if (kernel_type == FixRHEO::CRK0) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = C0[j]; - buf[m++] = coordination[j]; - } - } else { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = coordination[j]; } } return m; @@ -775,23 +800,18 @@ void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) int i, k, m, last,a,b; m = 0; last = first + n; - if (correction_order > 0) { - for (i = first; i < last; i++) { - for (a = 0; a < ncor; a++) { - for (b = 0; b < Mdim; b++) { - C[i][a][b] = buf[m++]; - } + + for (i = first; i < last; i++) { + if (comm_stage == 0) { + coordination[i] = buf[m++]; + } else { + if (kernel_type == FixRHEO::CRK0) { + C0[i] = buf[m++]; + } else { + for (a = 0; a < ncor; a++) + for (b = 0; b < Mdim; b++) + C[i][a][b] = buf[m++]; } - coordination[i] = buf[m++]; - } - } else if (kernel_type == FixRHEO::CRK0) { - for (i = first; i < last; i++) { - C0[i] = buf[m++]; - coordination[i] = buf[m++]; - } - } else { - for (i = first; i < last; i++) { - coordination[i] = buf[m++]; } } } diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index ed2b6ff5f2..4fbdb966b4 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -35,16 +35,19 @@ class ComputeRHEOKernel : public Compute { int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; double memory_usage() override; + void compute_coordination(); double calc_w(int,int,double,double,double,double); double calc_dw(int,int,double,double,double,double); double calc_w_quintic(int,int,double,double,double,double); double calc_dw_quintic(int,int,double,double,double,double,double *,double *); + void grow_arrays(int); double dWij[3], dWji[3], Wij, Wji; int correction_order; int *coordination; private: + int comm_stage, comm_forward_save; int solid_flag; int gsl_error_flag; std::unordered_set gsl_error_tags; diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp new file mode 100644 index 0000000000..fafd948538 --- /dev/null +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -0,0 +1,184 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + 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_rheo_rho_sum.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_kernel.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeRHEORhoSum::ComputeRHEORhoSum(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), fix_rheo(nullptr), compute_kernel(nullptr) +{ + if (narg != 3) error->all(FLERR,"Illegal compute RHEO/rho command"); + + comm_forward = 1; + comm_reverse = 1; +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEORhoSum::~ComputeRHEORhoSum() {} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEORhoSum::init() +{ + compute_kernel = fix_rheo->compute_kernel; + cut = fix_rheo->cut; + cutsq = cut * cut; + + // need an occasional half neighbor list + neighbor->add_request(this, NeighConst::REQ_HALF); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEORhoSum::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + + +void ComputeRHEORhoSum::compute_peratom() +{ + int i, j, ii, jj, inum, jnum, itype, jtype; + double xtmp, ytmp, ztmp, delx, dely, delz; + int *ilist, *jlist, *numneigh, **firstneigh; + double rsq, w; + + int nlocal = atom->nlocal; + + double **x = atom->x; + double *rho = atom->rho; + int *type = atom->type; + int *status = atom->status; + double *mass = atom->mass; + int newton = force->newton; + + double jmass; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + int nall = nlocal + atom->nghost; + + // initialize arrays, local with quintic self-contribution, ghosts are zeroed + for (i = 0; i < nlocal; i++) { + w = compute_kernel->calc_w_quintic(i, i, 0.0, 0.0, 0.0, 0.0); + rho[i] += w * mass[type[i]]; + } + + for (i = nlocal; i < nall; i++) rho[i] = 0.0; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + if (rsq < cutsq) { + w = compute_kernel->calc_w(i, j, delx, dely, delz, sqrt(rsq)); + rho[i] += w * mass[type[i]]; + if (newton || j < nlocal) { + rho[j] += w * mass[type[j]]; + } + } + } + } + + if (newton) comm->reverse_comm(this); + comm->forward_comm(this); +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEORhoSum::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,k,m; + double * rho = atom->rho; + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = coordination[j]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ +void ComputeRHEORhoSum::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double * rho = atom->rho; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + rho[i] = buf[m++]; + } +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEORhoSum::pack_reverse_comm(int n, int first, double *buf) +{ + int i,k,m,last; + double *rho = atom->rho; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = rho[i]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEORhoSum::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i,k,j,m; + double *rho = atom->rho; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + rho[j] += buf[m++]; + } +} diff --git a/src/RHEO/compute_rheo_rho_sum.h b/src/RHEO/compute_rheo_rho_sum.h new file mode 100644 index 0000000000..a411d5ed29 --- /dev/null +++ b/src/RHEO/compute_rheo_rho_sum.h @@ -0,0 +1,50 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(RHEO/RHO/SUM,ComputeRHEORhoSum) +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_RHO_SUM_H +#define LMP_COMPUTE_RHEO_RHO_SUM_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEORhoSum : public Compute { + public: + ComputeRHEORhoSum(class LAMMPS *, int, char **); + ~ComputeRHEORhoSum() override; + void init() override; + void init_list(int, class NeighList *) override; + void compute_peratom() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; + + private: + double cut, cutsq; + + class NeighList *list; + class FixRHEO *fix_rheo; + class ComputeRHEOKernel *compute_kernel; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 5b3aeabf26..9a94ea6a76 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -36,7 +36,7 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathExtra; -#define epsilon 1e-10; +#define EPSILON 1e-10; /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 8d0b681c6f..00cfb56b31 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -27,7 +27,7 @@ namespace LAMMPS_NS { class ComputeRHEOSurface : public Compute { public: ComputeRHEOSurface(class LAMMPS *, int, char **); - ~ComputeRHEOSurface(); + ~ComputeRHEOSurface() override; void init() override; void init_list(int, class NeighList *) override; void compute_peratom() override; @@ -44,26 +44,13 @@ class ComputeRHEOSurface : public Compute { double **B, **gradC, *divr; int threshold_style, comm_stage; - double divR_limit; - int coord_limit; - class NeighList *list; class FixRHEO *fix_rheo; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOSolids *compute_solids; }; -} +} // namespace LAMMPS_NS #endif #endif - -/* ERROR/WARNING messages: - -E: Illegal ... command - -Self-explanatory. Check the input script syntax and compare to the -documentation for the command. You can use -echo screen as a -command-line option when running LAMMPS to see the offending line. - -*/ diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 5358cc4cba..e2f9467b34 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -141,7 +141,7 @@ FixRHEO::~FixRHEO() void FixRHEO::post_constructor() { - compute_kernel = dynamic_cast(modify->add_compute("rheo_kernel all RHEO/KERNEL")); + compute_kernel = dynamic_cast(modify->add_compute("rheo_kernel all RHEO/KERNEL {}", kernel_style)); compute_kernel->fix_rheo = this; std::string cmd = "rheo_grad all RHEO/GRAD velocity rho viscosity"; @@ -150,7 +150,7 @@ void FixRHEO::post_constructor() compute_grad->fix_rheo = this; if (rhosum_flag) { - compute_rhosum = dynamic_cast(modify->add_compute("rheo_rhosum all RHEO/RHO/SUM")); + compute_rhosum = dynamic_cast(modify->add_compute("rheo_rho_sum all RHEO/RHO/SUM")); compute_rhosum->fix_rheo = this; } @@ -364,6 +364,8 @@ void FixRHEO::initial_integrate(int /*vflag*/) void FixRHEO::pre_force(int /*vflag*/) { + compute_kernel->compute_coordination(); // Needed for rho sum + if (rhosum_flag) compute_rhosum->compute_peratom(); From 35d1178cfaf29a543ee58e9b230738750966523a Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 20 Apr 2023 20:15:17 -0600 Subject: [PATCH 026/385] Adding cmake options, fixing a few misc errors --- cmake/CMakeLists.txt | 1 + cmake/presets/all_off.cmake | 1 + cmake/presets/all_on.cmake | 1 + cmake/presets/mingw-cross.cmake | 1 + cmake/presets/most.cmake | 1 + cmake/presets/windows.cmake | 1 + src/.gitignore | 25 +++++++++++++++++++++++++ src/RHEO/compute_rheo_grad.h | 2 +- src/RHEO/compute_rheo_interface.h | 2 +- src/RHEO/compute_rheo_kernel.h | 2 +- src/RHEO/compute_rheo_rho_sum.h | 3 ++- src/RHEO/compute_rheo_surface.h | 2 +- src/RHEO/compute_rheo_vshift.h | 3 ++- src/RHEO/fix_rheo.cpp | 8 ++------ src/RHEO/fix_rheo.h | 12 ++++++------ 15 files changed, 47 insertions(+), 18 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 14961209c8..f4a8b9c1ef 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -295,6 +295,7 @@ set(STANDARD_PACKAGES REACTION REAXFF REPLICA + RHEO RIGID SCAFACOS SHOCK diff --git a/cmake/presets/all_off.cmake b/cmake/presets/all_off.cmake index 3d5ee95b3d..64cc88d669 100644 --- a/cmake/presets/all_off.cmake +++ b/cmake/presets/all_off.cmake @@ -83,6 +83,7 @@ set(ALL_PACKAGES REACTION REAXFF REPLICA + RHEO RIGID SCAFACOS SHOCK diff --git a/cmake/presets/all_on.cmake b/cmake/presets/all_on.cmake index 474051f6ec..ac721b30fd 100644 --- a/cmake/presets/all_on.cmake +++ b/cmake/presets/all_on.cmake @@ -85,6 +85,7 @@ set(ALL_PACKAGES REACTION REAXFF REPLICA + RHEO RIGID SCAFACOS SHOCK diff --git a/cmake/presets/mingw-cross.cmake b/cmake/presets/mingw-cross.cmake index 6c6170acd3..ec21809edd 100644 --- a/cmake/presets/mingw-cross.cmake +++ b/cmake/presets/mingw-cross.cmake @@ -67,6 +67,7 @@ set(WIN_PACKAGES REACTION REAXFF REPLICA + RHEO RIGID SHOCK SMTBQ diff --git a/cmake/presets/most.cmake b/cmake/presets/most.cmake index 00c74c81b8..2a2cac2755 100644 --- a/cmake/presets/most.cmake +++ b/cmake/presets/most.cmake @@ -58,6 +58,7 @@ set(ALL_PACKAGES REACTION REAXFF REPLICA + RHEO RIGID SHOCK SPH diff --git a/cmake/presets/windows.cmake b/cmake/presets/windows.cmake index aa9a4656af..9253d439a8 100644 --- a/cmake/presets/windows.cmake +++ b/cmake/presets/windows.cmake @@ -56,6 +56,7 @@ set(WIN_PACKAGES REACTION REAXFF REPLICA + RHEO RIGID SHOCK SMTBQ diff --git a/src/.gitignore b/src/.gitignore index ac4a776cfc..d0fcaf495c 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -197,6 +197,31 @@ /pair_tdpd.cpp /pair_tdpd.h +/atom_vec_rheo.cpp +/atom_vec_rheo.h +/compute_rheo_grad.cpp +/compute_rheo_grad.h +/compute_rheo_interface.cpp +/compute_rheo_interface.h +/compute_rheo_kernel.cpp +/compute_rheo_kernel.h +/compute_rheo_rho_sum.cpp +/compute_rheo_rho_sum.h +/compute_rheo_surface.cpp +/compute_rheo_surface.h +/compute_rheo_vshift.cpp +/compute_rheo_vshift.h +/fix_rheo.cpp +/fix_rheo.h +/fix_rheo_pressure.cpp +/fix_rheo_pressure.h +/fix_rheo_thermal.cpp +/fix_rheo_thermal.h +/fix_rheo_viscosity.cpp +/fix_rheo_viscosity.h +/pair_rheo.cpp +/pair_rheo.h + /compute_grid.cpp /compute_grid.h /compute_grid_local.cpp diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index ee4b4a5bd6..4c2461c73f 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -42,13 +42,13 @@ class ComputeRHEOGrad : public Compute { double **gradr; double **gradt; double **gradn; + class FixRHEO *fix_rheo; private: int comm_stage, ncomm_grad, ncomm_field, nmax_old; double cut, cutsq, rho0; class NeighList *list; - class FixRHEO *fix_rheo; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; diff --git a/src/RHEO/compute_rheo_interface.h b/src/RHEO/compute_rheo_interface.h index cdb2eb6c54..04733ff334 100644 --- a/src/RHEO/compute_rheo_interface.h +++ b/src/RHEO/compute_rheo_interface.h @@ -41,6 +41,7 @@ class ComputeRHEOInterface : public Compute { void store_forces(); double *chi, **f_pressure; + class FixRHEO *fix_rheo; private: int nmax_old, comm_stage; @@ -50,7 +51,6 @@ class ComputeRHEOInterface : public Compute { char *id_fix_pa; class NeighList *list; - class FixRHEO *fix_rheo; class ComputeRHEOKernel *compute_kernel; }; diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 4fbdb966b4..19062e483b 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -45,6 +45,7 @@ class ComputeRHEOKernel : public Compute { double dWij[3], dWji[3], Wij, Wji; int correction_order; int *coordination; + class FixRHEO *fix_rheo; private: int comm_stage, comm_forward_save; @@ -60,7 +61,6 @@ class ComputeRHEOKernel : public Compute { class NeighList *list; class ComputeRHEOInterface *compute_interface; - class FixRHEO *fix_rheo; int check_corrections(int); diff --git a/src/RHEO/compute_rheo_rho_sum.h b/src/RHEO/compute_rheo_rho_sum.h index a411d5ed29..6ec2547b95 100644 --- a/src/RHEO/compute_rheo_rho_sum.h +++ b/src/RHEO/compute_rheo_rho_sum.h @@ -36,11 +36,12 @@ class ComputeRHEORhoSum : public Compute { int pack_reverse_comm(int, int, double *) override; void unpack_reverse_comm(int, int *, double *) override; + class FixRHEO *fix_rheo; + private: double cut, cutsq; class NeighList *list; - class FixRHEO *fix_rheo; class ComputeRHEOKernel *compute_kernel; }; diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 00cfb56b31..224b2594a1 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -37,6 +37,7 @@ class ComputeRHEOSurface : public Compute { void unpack_forward_comm(int, int, double *) override; double **nsurface, **rsurface; + class FixRHEO *fix_rheo; private: double cut, cutsq, rho0, threshold_divr; @@ -45,7 +46,6 @@ class ComputeRHEOSurface : public Compute { int threshold_style, comm_stage; class NeighList *list; - class FixRHEO *fix_rheo; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOSolids *compute_solids; }; diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h index e76476e7fd..88a9cdcd1d 100644 --- a/src/RHEO/compute_rheo_vshift.h +++ b/src/RHEO/compute_rheo_vshift.h @@ -37,13 +37,14 @@ class ComputeRHEOVShift : public Compute { void correct_surfaces(); double **vshift; + class FixRHEO *fix_rheo; + private: int nmax_old; double dtv, cut, cutsq, cutthird; int surface_flag; class NeighList *list; - class FixRHEO *fix_rheo; class ComputeRHEOInterface *compute_interface ; class ComputeRHEOKernel *compute_kernel; }; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index e2f9467b34..2b55320c4e 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -23,7 +23,7 @@ #include "compute_rheo_interface.h" #include "compute_rheo_surface.h" #include "compute_rheo_kernel.h" -#include "compute_rheo_rhosum.h" +#include "compute_rheo_rho_sum.h" #include "compute_rheo_vshift.h" #include "domain.h" #include "error.h" @@ -46,7 +46,6 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : viscosity_fix_defined = 0; pressure_fix_defined = 0; thermal_fix_defined = 0; - surface_fix_defined = 0; thermal_flag = 0; rhosum_flag = 0; @@ -104,9 +103,6 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : interface_flag = 1; } else if (strcmp(arg[iarg],"rhosum") == 0) { rhosum_flag = 1; - if(iarg + 1 >= narg) error->all(FLERR,"Illegal rhosum option in fix rheo"); - rhosum_zmin = utils::inumeric(FLERR,arg[iarg + 1],false,lmp); - iarg += 1; } else if (strcmp(arg[iarg],"rho0") == 0) { if(iarg + 1 >= narg) error->all(FLERR,"Illegal rho0 option in fix rheo"); rho0 = utils::numeric(FLERR,arg[iarg + 1],false,lmp); @@ -207,7 +203,7 @@ void FixRHEO::setup_pre_force(int /*vflag*/) /* ---------------------------------------------------------------------- */ -void FixRHEO::setup() +void FixRHEO::setup(int /*vflag*/) { // Confirm all accessory fixes are defined // Note: these fixes set this flag in setup_pre_force() diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index d2097ade71..0064f4c90b 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -32,7 +32,7 @@ class FixRHEO : public Fix { void post_constructor() override; void init() override; void setup_pre_force(int) override; - void setup() override; + void setup(int) override; void pre_force(int) override; void initial_integrate(int) override; void final_integrate() override; @@ -40,7 +40,7 @@ class FixRHEO : public Fix { // Model parameters double h, rho0, csq; - int zmin_kernel, zmin_rhosum, zmin_surface; + int zmin_kernel, zmin_surface; int kernel_style, surface_style; double divr_surface; enum {QUINTIC, CRK0, CRK1, CRK2}; @@ -52,7 +52,7 @@ class FixRHEO : public Fix { STATUS_FLUID = 1 << 0, STATUS_REACTIVE = 1 << 1, STATUS_SOLID = 1 << 2, - STATUS_FREEZING = 1 << 3 + STATUS_FREEZING = 1 << 3, // Surface status STATUS_BULK = 1 << 4, @@ -62,10 +62,10 @@ class FixRHEO : public Fix { // Temporary status options - reset in preforce STATUS_SHIFT = 1 << 8, - STATUS_NO_FORCE = 1 << 9, + STATUS_NO_FORCE = 1 << 9 }; - int phasemask = FFFFFFF0; - int surfacemask = FFFFFF0F; + int phasemask = 0xFFFFFFF0; + int surfacemask = 0xFFFFFF0F; // Accessory fixes/computes int thermal_flag; From 47b8cdc94fa750bc088225124e1f911d40d63885 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 24 Apr 2023 19:46:27 -0600 Subject: [PATCH 027/385] Fixing compilation errors --- src/RHEO/atom_vec_rheo.cpp | 2 +- src/RHEO/compute_rheo_grad.cpp | 66 +++++++++------- src/RHEO/compute_rheo_grad.h | 5 +- src/RHEO/compute_rheo_interface.cpp | 91 +++++++++++----------- src/RHEO/compute_rheo_interface.h | 10 +-- src/RHEO/compute_rheo_kernel.cpp | 112 ++++++++++++++-------------- src/RHEO/compute_rheo_kernel.h | 2 +- src/RHEO/compute_rheo_rho_sum.cpp | 13 ++-- src/RHEO/compute_rheo_surface.cpp | 83 +++++++++++---------- src/RHEO/compute_rheo_surface.h | 10 +-- src/RHEO/compute_rheo_vshift.cpp | 38 +++++----- src/RHEO/compute_rheo_vshift.h | 2 +- src/RHEO/fix_rheo.cpp | 79 +++++++++++--------- src/RHEO/fix_rheo.h | 51 +++++++------ src/RHEO/fix_rheo_pressure.cpp | 25 ++++--- src/RHEO/fix_rheo_pressure.h | 5 +- src/RHEO/fix_rheo_thermal.cpp | 57 +++++++------- src/RHEO/fix_rheo_thermal.h | 6 +- src/RHEO/fix_rheo_viscosity.cpp | 27 ++++--- src/RHEO/fix_rheo_viscosity.h | 2 +- src/RHEO/pair_rheo.cpp | 39 ++++------ 21 files changed, 379 insertions(+), 346 deletions(-) diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp index a8496a18e9..de2e2f77ad 100644 --- a/src/RHEO/atom_vec_rheo.cpp +++ b/src/RHEO/atom_vec_rheo.cpp @@ -120,7 +120,7 @@ void AtomVecRHEO::pack_property_atom(int index, double *buf, int nvalues, int gr buf[n] = 0.0; n += nvalues; } - } if else (index == 1) { + } else if (index == 1) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = rho[i]; diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index add3ed712d..606cec7dfc 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -21,11 +21,12 @@ #include "atom.h" #include "comm.h" #include "compute_rheo_kernel.h" -#include "compute_rheo_solids.h" +#include "compute_rheo_interface.h" #include "domain.h" #include "error.h" #include "fix_rheo.h" #include "force.h" +#include "memory.h" #include "neighbor.h" #include "neigh_list.h" #include "update.h" @@ -33,6 +34,8 @@ #include using namespace LAMMPS_NS; +using namespace RHEO_NS; + enum{COMMGRAD, COMMFIELD}; /* ---------------------------------------------------------------------- */ @@ -112,10 +115,13 @@ void ComputeRHEOGrad::init() compute_kernel = fix_rheo->compute_kernel; compute_interface = fix_rheo->compute_interface; + int tmp1, tmp2; + index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); + // Create coordination array if it doesn't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded int index; int dim = domain->dimension; @@ -139,7 +145,7 @@ void ComputeRHEOGrad::init() gradn = atom->darray[index]; } - nmax_old = 0; + nmax_store = 0; grow_arrays(atom->nmax); } @@ -158,7 +164,7 @@ void ComputeRHEOGrad::compute_peratom() double xtmp, ytmp, ztmp, delx, dely, delz; double rsq, imass, jmass; double rhoi, rhoj, Voli, Volj, drho, dT, deta; - double vij[3]; + double vi[3], vj[3], vij[3]; double wp, *dWij, *dWji; int inum, *ilist, *numneigh, **firstneigh; @@ -169,26 +175,22 @@ void ComputeRHEOGrad::compute_peratom() double **v = atom->v; double *rho = atom->rho; double *temperature = atom->temperature; + double *viscosity = atom->dvector[index_visc]; int *status = atom->status; int *type = atom->type; double *mass = atom->mass; int newton = force->newton; int dim = domain->dimension; - int tmp1, tmp2; - int index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index_visc == -1) error->all(FLERR, "Cannot find rheo viscosity"); - double *viscosity = atom->dvector[index_visc]; - inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // initialize arrays - if (nmax > nmax_old) grow_arrays(nmax); + if (atom->nmax > nmax_store) grow_arrays(atom->nmax); - for (i = 0; i < nmax; i++) { + for (i = 0; i < nmax_store; i++) { if (velocity_flag) { for (k = 0; k < dim * dim; k++) gradv[i][k] = 0.0; @@ -212,6 +214,9 @@ void ComputeRHEOGrad::compute_peratom() xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; + vi[0] = v[i][0]; + vi[1] = v[i][1]; + vi[2] = v[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; @@ -230,14 +235,18 @@ void ComputeRHEOGrad::compute_peratom() rhoi = rho[i]; rhoj = rho[j]; + vj[0] = v[j][0]; + vj[1] = v[j][1]; + vj[2] = v[j][2]; + // Add corrections for walls - if ((status[i] & FixRHEO::STATUS_FLUID) && !(status[j] & FixRHEO::STATUS_FLUID)) { - compute_interface->correct_v(v[i], v[j], vi, i, j); - rhoj = compute_interface->correct_rho(j,i); - } else if (!(status[i] & FixRHEO::STATUS_FLUID) && (status[j] & FixRHEO::STATUS_FLUID)) { - compute_interface->correct_v(v[j], v[i], vj, j, i); - rhoi = compute_interface->correct_rho(i,j); - } else if (!(status[i] & FixRHEO::STATUS_FLUID) && !(status[j] & FixRHEO::STATUS_FLUID)) { + if ((status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { + compute_interface->correct_v(vi, vj, i, j); + rhoj = compute_interface->correct_rho(j, i); + } else if (!(status[i] & STATUS_FLUID) && (status[j] & STATUS_FLUID)) { + compute_interface->correct_v(vj, vi, j, i); + rhoi = compute_interface->correct_rho(i, j); + } else if (!(status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { rhoi = rho0; rhoj = rho0; } @@ -324,7 +333,6 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, int i,j,k,m; double *rho = atom->rho; double *temperature = atom->temperature; - double *eta = atom->viscosity; double **v = atom->v; int dim = domain->dimension; @@ -371,9 +379,9 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; - double * rho = atom->rho; - double * temperature = atom->temperature; - double ** v = atom->v; + double *rho = atom->rho; + double *temperature = atom->temperature; + double **v = atom->v; int dim = domain->dimension; m = 0; @@ -483,25 +491,27 @@ void ComputeRHEOGrad::grow_arrays(int nmax) if (eta_flag) memory->grow(gradn, nmax, dim, "atom:rheo_grad_eta"); - nmax_old = nmax; + nmax_store = nmax; } /* ---------------------------------------------------------------------- */ -double ComputeRHEOKernel::memory_usage() +double ComputeRHEOGrad::memory_usage() { double bytes = 0.0; + int dim = domain->dimension; + if (velocity_flag) - bytes = (size_t) nmax_old * dim * dim * sizeof(double); + bytes = (size_t) nmax_store * dim * dim * sizeof(double); if (rho_flag) - bytes = (size_t) nmax_old * dim * sizeof(double); + bytes = (size_t) nmax_store * dim * sizeof(double); if (temperature_flag) - bytes = (size_t) nmax_old * dim * sizeof(double); + bytes = (size_t) nmax_store * dim * sizeof(double); if (eta_flag) - bytes = (size_t) nmax_old * dim * sizeof(double); + bytes = (size_t) nmax_store * dim * sizeof(double); return bytes; } diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 4c2461c73f..8c7962a978 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -45,7 +45,8 @@ class ComputeRHEOGrad : public Compute { class FixRHEO *fix_rheo; private: - int comm_stage, ncomm_grad, ncomm_field, nmax_old; + int comm_stage, ncomm_grad, ncomm_field, nmax_store; + int index_visc; double cut, cutsq, rho0; class NeighList *list; @@ -53,6 +54,8 @@ class ComputeRHEOGrad : public Compute { class ComputeRHEOInterface *compute_interface; int velocity_flag, temperature_flag, rho_flag, eta_flag; + + void grow_arrays(int); }; } // namespace LAMMPS_NS diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 059f4057f4..72dcdc17d7 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -34,18 +34,19 @@ #include using namespace LAMMPS_NS; +using namespace RHEO_NS; -#define EPSILON 1e-1 +static constexpr double EPSILON = 1e-1; /* ---------------------------------------------------------------------- */ ComputeRHEOInterface::ComputeRHEOInterface(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), fix_rheo(nullptr), compute_kernel(nullptr), fx_m_norm(nullptr), - norm(nullptr), normwf(nullptr), chi(nullptr), f_pressure(nullptr), id_fix_pa(nullptr) + Compute(lmp, narg, arg), fix_rheo(nullptr), compute_kernel(nullptr), fp_store(nullptr), + norm(nullptr), normwf(nullptr), chi(nullptr), id_fix_pa(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute rheo/interface command"); - nmax = 0; + nmax_store = 0; comm_forward = 3; comm_reverse = 4; @@ -74,15 +75,15 @@ void ComputeRHEOInterface::init() compute_kernel = fix_rheo->compute_kernel; rho0 = fix_rheo->rho0; cut = fix_rheo->cut; - cs = fix_rheo->cs; - cs_inv = 1.0 / cs; + csq = fix_rheo->csq; + csq_inv = 1.0 / csq; cutsq = cut * cut; wall_max = sqrt(3.0) / 12.0 * cut; // Create chi array if it doesn't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded int tmp1, tmp2; int nmax = atom->nmax; @@ -93,7 +94,7 @@ void ComputeRHEOInterface::init() memory->destroy(normwf); memory->create(norm, nmax, "rheo/interface:norm"); memory->create(normwf, nmax, "rheo/interface:normwf"); - nmax_old = nmax; + nmax_store = nmax; } chi = atom->dvector[index]; @@ -104,13 +105,13 @@ void ComputeRHEOInterface::init() index = atom->find_custom("fp_store", tmp1, tmp2); if (index == -1) { id_fix_pa = utils::strdup(id + std::string("_fix_property_atom")); - modify->add_fix(fmt::format("{} all property/atom d2_fp_store 3", id_fix_pa))); + modify->add_fix(fmt::format("{} all property/atom d2_fp_store 3", id_fix_pa)); index = atom->find_custom("fp_store", tmp1, tmp2); } fp_store = atom->darray[index]; // need an occasional half neighbor list - neighbor->add_request(this, NeighConst::REQ_HALF); + neighbor->add_request(this, NeighConst::REQ_DEFAULT); } /* ---------------------------------------------------------------------- */ @@ -142,17 +143,17 @@ void ComputeRHEOInterface::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - if (atom->nmax > nmax_old) { - nmax_old = atom->nmax; + if (atom->nmax > nmax_store) { + nmax_store = atom->nmax; memory->destroy(norm); memory->destroy(normwf); - memory->create(norm, nmax_old, "rheo/interface:norm"); - memory->create(normwf, nmax_old, "rheo/interface:normwf"); - memory->grow(chi, nmax_old, "rheo/interface:chi"); + memory->create(norm, nmax_store, "rheo/interface:norm"); + memory->create(normwf, nmax_store, "rheo/interface:normwf"); + memory->grow(chi, nmax_store, "rheo/interface:chi"); } for (i = 0; i < nall; i++) { - if (!(status[i] & FixRHEO::STATUS_FLUID)) rho[i] = 0.0; + if (!(status[i] & STATUS_FLUID)) rho[i] = 0.0; normwf[i] = 0.0; norm[i] = 0.0; chi[i] = 0.0; @@ -164,7 +165,7 @@ void ComputeRHEOInterface::compute_peratom() ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; - fluidi = status[i] & FixRHEO::STATUS_FLUID; + fluidi = status[i] & STATUS_FLUID; jlist = firstneigh[i]; jnum = numneigh[i]; @@ -179,12 +180,12 @@ void ComputeRHEOInterface::compute_peratom() if (rsq < cutsq) { jtype = type[j]; - fluidj = status[j] & FixRHEO::STATUS_FLUID; + fluidj = status[j] & STATUS_FLUID; w = compute_kernel->calc_w_quintic(i, j, delx, dely, delz, sqrt(rsq)); status_match = 0; norm[i] += w; - if ((fluidi && fluidj) || ((!fluid) && (!fluidj))) + if ((fluidi && fluidj) || ((!fluidi) && (!fluidj))) status_match = 1; if (status_match) { @@ -194,7 +195,7 @@ void ComputeRHEOInterface::compute_peratom() dot = (-fp_store[0][j] + fp_store[0][i]) * delx; dot += (-fp_store[1][j] + fp_store[1][i]) * dely; dot += (-fp_store[2][j] + fp_store[2][i]) * delz; - rho[i] += w * (cs * (rho[j] - rho0) - rho[j] * dot); + rho[i] += w * (csq * (rho[j] - rho0) - rho[j] * dot); normwf[i] += w; } } @@ -208,7 +209,7 @@ void ComputeRHEOInterface::compute_peratom() dot = (-fp_store[0][i] + fp_store[0][j]) * delx; dot += (-fp_store[1][i] + fp_store[1][j]) * dely; dot += (-fp_store[2][i] + fp_store[2][j]) * delz; - rho[j] += w * (cs * (rho[i] - rho0) + rho[i] * dot); + rho[j] += w * (csq * (rho[i] - rho0) + rho[i] * dot); normwf[j] += w; } } @@ -223,10 +224,10 @@ void ComputeRHEOInterface::compute_peratom() if (norm[i] != 0.0) chi[i] /= norm[i]; // Recalculate rho for non-fluid particles - if (!(status[i] & FixRHEO::STATUS_FLUID)) { + if (!(status[i] & STATUS_FLUID)) { if (normwf[i] != 0.0) { // Stores rho for solid particles 1+Pw in Adami Adams 2012 - rho[i] = MAX(EPSILON, rho0 + (rho[i] / normwf[i]) * cs_inv); + rho[i] = MAX(EPSILON, rho0 + (rho[i] / normwf[i]) * csq_inv); } else { rho[i] = rho0; } @@ -310,7 +311,7 @@ void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) j = list[i]; norm[j] += buf[m++]; chi[j] += buf[m++]; - if (!(status[j] & FixRHEO::STATUS_FLUID)){ + if (!(status[j] & STATUS_FLUID)){ normwf[j] += buf[m++]; rho[j] += buf[m++]; } else { @@ -322,7 +323,7 @@ void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) /* ---------------------------------------------------------------------- */ -void ComputeRHEOInterface::correct_v(double *vi, double *vj, double *vi_out, int i, int j) +void ComputeRHEOInterface::correct_v(double *vi, double *vj, int i, int j) { double wall_prefactor, wall_denom, wall_numer; @@ -333,9 +334,9 @@ void ComputeRHEOInterface::correct_v(double *vi, double *vj, double *vi_out, int wall_prefactor = wall_numer / wall_denom; - vi_out[0] = (vi[0] - vj[0]) * wall_prefactor + vi[0]; - vi_out[1] = (vi[1] - vj[1]) * wall_prefactor + vi[1]; - vi_out[2] = (vi[2] - vj[2]) * wall_prefactor + vi[2]; + vi[0] = (vi[0] - vj[0]) * wall_prefactor + vi[0]; + vi[1] = (vi[1] - vj[1]) * wall_prefactor + vi[1]; + vi[2] = (vi[2] - vj[2]) * wall_prefactor + vi[2]; } /* ---------------------------------------------------------------------- */ @@ -352,28 +353,30 @@ double ComputeRHEOInterface::correct_rho(int i, int j) void ComputeRHEOInterface::store_forces() { double minv; - double mass = atom->mass; - double type = atom->type; - double **f = atom->f; + int *type = atom->type; int *mask = atom->mask; + double *mass = atom->mass; + double **f = atom->f; // When this is called, fp_store stores the pressure force // After this method, fp_store instead stores non-pressure forces // and is also normalized by the particles mass // If forces are overwritten by a fix, there are no pressure forces // so just normalize - int ifix = modify->find_fix_by_style("setforce"); - if (ifix != -1) { - for (int i = 0; i < atom->nlocal; i++) { - minv = 1.0 / mass[type[i]]; - if (mask[i] & modify->fix[ifix]->groupbit) { - fp_store[i][0] = f[i][0] * minv; - fp_store[i][1] = f[i][1] * minv; - fp_store[i][2] = f[i][2] * minv; - } else { - fp_store[i][0] = (f[i][0] - fp_store[i][0]) * minv; - fp_store[i][1] = (f[i][1] - fp_store[i][1]) * minv; - fp_store[i][2] = (f[i][2] - fp_store[i][2]) * minv; + auto fixlist = modify->get_fix_by_style("setforce"); + if (fixlist.size() == 0) { + for (const auto &fix : fixlist) { + for (int i = 0; i < atom->nlocal; i++) { + minv = 1.0 / mass[type[i]]; + if (mask[i] & fix->groupbit) { + fp_store[i][0] = f[i][0] * minv; + fp_store[i][1] = f[i][1] * minv; + fp_store[i][2] = f[i][2] * minv; + } else { + fp_store[i][0] = (f[i][0] - fp_store[i][0]) * minv; + fp_store[i][1] = (f[i][1] - fp_store[i][1]) * minv; + fp_store[i][2] = (f[i][2] - fp_store[i][2]) * minv; + } } } } else { @@ -397,7 +400,7 @@ void ComputeRHEOInterface::store_forces() double ComputeRHEOInterface::memory_usage() { - double bytes = 3 * nmax_old * sizeof(double); + double bytes = 3 * nmax_store * sizeof(double); return bytes; } diff --git a/src/RHEO/compute_rheo_interface.h b/src/RHEO/compute_rheo_interface.h index 04733ff334..50cec97790 100644 --- a/src/RHEO/compute_rheo_interface.h +++ b/src/RHEO/compute_rheo_interface.h @@ -36,17 +36,17 @@ class ComputeRHEOInterface : public Compute { int pack_reverse_comm(int, int, double *) override; void unpack_reverse_comm(int, int *, double *) override; double memory_usage() override; - void correct_v(double *, double *, double *, int, int); + void correct_v(double *, double *, int, int); double correct_rho(int, int); void store_forces(); - double *chi, **f_pressure; + double *chi, **fp_store; class FixRHEO *fix_rheo; private: - int nmax_old, comm_stage; - double rho0, cut, cutsq, cs, cs_inv, wall_max; - double *norm, *normwf, **fom_store; + int nmax_store, comm_stage; + double rho0, cut, cutsq, csq, csq_inv, wall_max; + double *norm, *normwf; char *id_fix_pa; diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index c0b61daae3..d96d8d234e 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -42,10 +42,10 @@ #include using namespace LAMMPS_NS; +using namespace RHEO_NS; using namespace MathExtra; -enum {QUINTIC, CRK0, CRK1, CRK2}; -#define DELTA 2000 +static constexpr int DELTA = 2000; /* ---------------------------------------------------------------------- */ @@ -55,16 +55,16 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : { if (narg != 4) error->all(FLERR,"Illegal compute rheo/kernel command"); - kernel_style = (SubModelType) utils::inumeric(FLERR,arg[3],false,lmp); + kernel_style = utils::inumeric(FLERR,arg[3],false,lmp); - if (kernel_style == FixRHEO::QUINTIC) { + if (kernel_style == QUINTIC) { correction_order = -1; - } else if (kernel_style == FixRHEO::CRK0) { + } else if (kernel_style == CRK0) { correction_order = 0; - } else if (kernel_style == FixRHEO::CRK1) { + } else if (kernel_style == CRK1) { correction_order = 1; - } else if (kernel_style == FixRHEO::CRK2) { + } else if (kernel_style == CRK2) { correction_order = 2; } @@ -74,11 +74,11 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : comm_forward = 1; ncor = 0; Mdim = 0; - if (kernel_type == CRK1) { + if (kernel_style == CRK1) { Mdim = 1 + dim; ncor = 1 + dim; comm_forward = ncor * Mdim; - } else if (kernel_type == CRK2) { + } else if (kernel_style == CRK2) { //Polynomial basis size (up to quadratic order) Mdim = 1 + dim + dim * (dim + 1) / 2; //Number of sets of correction coefficients (1 x y xx yy) + z zz (3D) @@ -126,35 +126,35 @@ void ComputeRHEOKernel::init() if (dim == 3) { - pre_w = 0.002652582384864922 * 27.0 * ihsq * ih; - pre_wp = pre_w * 3.0 * ih; + pre_w = 0.002652582384864922 * 27.0 * hsqinv * hinv; + pre_wp = pre_w * 3.0 * hinv; } else { - pre_w = 0.004661441847879780 * 9 * ihsq; - pre_wp = pre_w * 3.0 * ih; + pre_w = 0.004661441847879780 * 9 * hsqinv; + pre_wp = pre_w * 3.0 * hinv; } // Create coordination array if it doesn't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded int tmp1, tmp2; int nmax = atom->nmax; int index = atom->find_custom("rheo_coordination", tmp1, tmp2); if (index == -1) { index = atom->add_custom("rheo_coordination", 0, 0); - nmax_old = nmax; + nmax_store = nmax; } coordination = atom->ivector[index]; // Create local arrays for kernel arrays, I can't foresee a reason to print - if (kernel_type == CRK0) { - memory->create(C0, nmax_old, "rheo/kernel:C0"); - } else if (kernel_type == CRK1) { - memory->create(C, nmax_old, ncor, Mdim, "rheo/kernel:C"); - } else if (kernel_type == CRK2) { - memory->create(C, nmax_old, ncor, Mdim, "rheo/kernel:C"); + if (kernel_style == CRK0) { + memory->create(C0, nmax_store, "rheo/kernel:C0"); + } else if (kernel_style == CRK1) { + memory->create(C, nmax_store, ncor, Mdim, "rheo/kernel:C"); + } else if (kernel_style == CRK2) { + memory->create(C, nmax_store, ncor, Mdim, "rheo/kernel:C"); } } @@ -192,10 +192,10 @@ double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double int corrections_j = check_corrections(j); int corrections = corrections_i & corrections_j; - if (kernel_type == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); - else if (kernel_type == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); - else if (kernel_type == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); - else if (kernel_type == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); + if (kernel_style == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); + else if (kernel_style == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); + else if (kernel_style == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); + else if (kernel_style == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); return w; } @@ -211,11 +211,11 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double // Calc wp and default dW's, a bit inefficient but can redo later wp = calc_dw_quintic(i,j,delx,dely,delz,r,dWij,dWji); - if(kernel_type == CRK1) { + if(kernel_style == CRK1) { //check if kernel correction calculated successfully. If not, revert to quintic if (corrections_i) calc_dw_crk1(i,j,delx,dely,delz,r,dWij); if (corrections_j) calc_dw_crk1(j,i,-delx,-dely,-delz,r,dWji); - } else if(kernel_type == CRK2) { + } else if(kernel_style == CRK2) { if (corrections_i) calc_dw_crk2(i,j,delx,dely,delz,r,dWij); if (corrections_j) calc_dw_crk2(j,i,-delx,-dely,-delz,r,dWji); } @@ -228,7 +228,7 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double double ComputeRHEOKernel::calc_w_quintic(int i, int j, double delx, double dely, double delz, double r) { double w, tmp1, tmp2, tmp3, tmp1sq, tmp2sq, tmp3sq, s; - s = r * 3.0 * ih; + s = r * 3.0 * hinv; if (s > 3.0) { w = 0.0; @@ -266,7 +266,7 @@ double ComputeRHEOKernel::calc_dw_quintic(int i, int j, double delx, double dely double *mass = atom->mass; int *type = atom->type; - s = r * 3.0 * ih; + s = r * 3.0 * hinv; if (s > 3.0) { wp = 0.0; @@ -496,9 +496,9 @@ void ComputeRHEOKernel::compute_peratom() gsl_error_flag = 0; gsl_error_tags.clear(); - if (kernel_type == FixRHEO::QUINTIC) return; + if (kernel_style == QUINTIC) return; - int i, j, ii, jj, inum, jnum, g, a, b, gsl_error; + int i, j, ii, jj, inum, jnum, itype, g, a, b, gsl_error; double xtmp, ytmp, ztmp, r, rsq, w, vj; double dx[3]; gsl_matrix_view gM; @@ -520,9 +520,9 @@ void ComputeRHEOKernel::compute_peratom() firstneigh = list->firstneigh; // Grow arrays if necessary - if (nmax_old < atom->nmax) grow_arrays(atom->nmax); + if (nmax_store < atom->nmax) grow_arrays(atom->nmax); - if (kernel_type == FixRHEO::CRK0) { + if (kernel_style == CRK0) { double M; for (ii = 0; ii < inum; ii++) { @@ -544,12 +544,12 @@ void ComputeRHEOKernel::compute_peratom() dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = lensq(dx); + rsq = lensq3(dx); if (rsq < hsq) { r = sqrt(rsq); w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); - if (!(status[j] & FixRHEO::STATUS_FLUID) && solid_flag) { + if (!(status[j] & STATUS_FLUID) && solid_flag) { vj = mass[type[j]] / compute_interface->correct_rho(j,i); } else vj = mass[type[j]] / rho[j]; @@ -590,22 +590,24 @@ void ComputeRHEOKernel::compute_peratom() dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = lensq(dx); + rsq = lensq3(dx); - if (rsq < cutsq) { + if (rsq < hsq) { r = sqrt(rsq); w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); - if (status[j] > FixRHEO::FLUID_MAX && solid_flag) - vj = mass[type[j]]/compute_interface->correct_rho(j,i); - else vj = mass[type[j]]/rho[j]; + if (solid_flag) + if (!(status[j] & STATUS_FLUID)) + vj = mass[type[j]]/compute_interface->correct_rho(j,i); + else + vj = mass[type[j]]/rho[j]; //Populate the H-vector of polynomials (2D) if (dim == 2) { H[0] = 1.0; H[1] = dx[0] * hinv; H[2] = dx[1] * hinv; - if (kernel_type == FixRHEO::CRK2) { + if (kernel_style == CRK2) { H[3] = 0.5 * dx[0] * dx[0] * hsqinv; H[4] = 0.5 * dx[1] * dx[1] * hsqinv; H[5] = dx[0] * dx[1] * hsqinv; @@ -615,7 +617,7 @@ void ComputeRHEOKernel::compute_peratom() H[1] = dx[0] * hinv; H[2] = dx[1] * hinv; H[3] = dx[2] * hinv; - if (kernel_type == FixRHEO::CRK2) { + if (kernel_style == CRK2) { H[4] = 0.5 * dx[0] * dx[0] * hsqinv; H[5] = 0.5 * dx[1] * dx[1] * hsqinv; H[6] = 0.5 * dx[2] * dx[2] * hsqinv; @@ -642,7 +644,7 @@ void ComputeRHEOKernel::compute_peratom() } // Skip if undercoordinated - if (coordination[i] < zmin) continue + if (coordination[i] < zmin) continue; // Use gsl to get Minv, use Cholesky decomposition since the // polynomials are independent, M is symmetrix & positive-definite @@ -656,7 +658,7 @@ void ComputeRHEOKernel::compute_peratom() //check if not positive-definite if (gsl_error != GSL_EDOM) - error->warn(FLERR, "Failed decomposition in rheo/kernel, gsl_error = {}", gsl_error); + error->warning(FLERR, "Failed decomposition in rheo/kernel, gsl_error = {}", gsl_error); continue; } @@ -689,7 +691,7 @@ void ComputeRHEOKernel::compute_peratom() // columns 1-2 (2D) or 1-3 (3D) //Second derivatives - if (kernel_type == FixRHEO::CRK2) + if (kernel_style == CRK2) C[i][1 + dim + b][a] = M[a * Mdim + b + 1 + dim] * hsqinv; // columns 3-4 (2D) or 4-6 (3D) } @@ -721,7 +723,7 @@ void ComputeRHEOKernel::compute_coordination() firstneigh = list->firstneigh; // Grow arrays if necessary - if (nmax_old < atom->nmax) grow_arrays(atom->nmax); + if (nmax_store < atom->nmax) grow_arrays(atom->nmax); for (ii = 0; ii < inum; ii++) { i = ilist[ii]; @@ -740,7 +742,7 @@ void ComputeRHEOKernel::compute_coordination() dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = lensq(dx); + rsq = lensq3(dx); if (rsq < hsq) coordination[i] += 1; @@ -759,13 +761,13 @@ void ComputeRHEOKernel::grow_arrays(int nmax) { memory->grow(coordination, nmax, "atom:rheo_coordination"); - if (kernel_type == FixRHEO::CRK0) { + if (kernel_style == CRK0) { memory->grow(C0, nmax, "rheo/kernel:C0"); } else if (correction_order > 0) { memory->grow(C, nmax, ncor, Mdim, "rheo/kernel:C"); } - nmax_old = nmax; + nmax_store = nmax; } /* ---------------------------------------------------------------------- */ @@ -781,7 +783,7 @@ int ComputeRHEOKernel::pack_forward_comm(int n, int *list, double *buf, if (comm_stage == 0) { buf[m++] = coordination[j]; } else { - if (kernel_type == FixRHEO::CRK0) { + if (kernel_style == CRK0) { buf[m++] = C0[j]; } else { for (a = 0; a < ncor; a++) @@ -805,7 +807,7 @@ void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) if (comm_stage == 0) { coordination[i] = buf[m++]; } else { - if (kernel_type == FixRHEO::CRK0) { + if (kernel_style == CRK0) { C0[i] = buf[m++]; } else { for (a = 0; a < ncor; a++) @@ -821,12 +823,12 @@ void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) double ComputeRHEOKernel::memory_usage() { double bytes = 0.0; - bytes = (size_t) nmax_old * sizeof(int); + bytes = (size_t) nmax_store * sizeof(int); - if (kernel_type == FixRHEO::CRK0) { - bytes += (size_t) nmax_old * sizeof(double); + if (kernel_style == CRK0) { + bytes += (size_t) nmax_store * sizeof(double); } else if (correction_order > 0) { - bytes += (size_t) nmax_old * ncor * Mdim * sizeof(double); + bytes += (size_t) nmax_store * ncor * Mdim * sizeof(double); } return bytes; } diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 19062e483b..1842406977 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -54,7 +54,7 @@ class ComputeRHEOKernel : public Compute { std::unordered_set gsl_error_tags; int kernel_style, zmin, dim, Mdim, ncor; - int nmax_old; + int nmax_store; double h, hsq, hinv, hsqinv, pre_w, pre_wp; double ***C; double *C0; diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp index fafd948538..726d876ea1 100644 --- a/src/RHEO/compute_rheo_rho_sum.cpp +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -49,7 +49,7 @@ void ComputeRHEORhoSum::init() cutsq = cut * cut; // need an occasional half neighbor list - neighbor->add_request(this, NeighConst::REQ_HALF); + neighbor->add_request(this, NeighConst::REQ_DEFAULT); } /* ---------------------------------------------------------------------- */ @@ -130,8 +130,9 @@ void ComputeRHEORhoSum::compute_peratom() int ComputeRHEORhoSum::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { - int i,j,k,m; - double * rho = atom->rho; + int i, j, k, m; + double *rho = atom->rho; + int *coordination = compute_kernel->coordination; m = 0; for (i = 0; i < n; i++) { @@ -145,7 +146,7 @@ int ComputeRHEORhoSum::pack_forward_comm(int n, int *list, double *buf, void ComputeRHEORhoSum::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; - double * rho = atom->rho; + double *rho = atom->rho; m = 0; last = first + n; @@ -158,7 +159,7 @@ void ComputeRHEORhoSum::unpack_forward_comm(int n, int first, double *buf) int ComputeRHEORhoSum::pack_reverse_comm(int n, int first, double *buf) { - int i,k,m,last; + int i, k, m, last; double *rho = atom->rho; m = 0; @@ -173,7 +174,7 @@ int ComputeRHEORhoSum::pack_reverse_comm(int n, int first, double *buf) void ComputeRHEORhoSum::unpack_reverse_comm(int n, int *list, double *buf) { - int i,k,j,m; + int i, k, j, m; double *rho = atom->rho; m = 0; diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 9a94ea6a76..180c430dd1 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -20,8 +20,8 @@ #include "atom.h" #include "comm.h" +#include "compute_rheo_interface.h" #include "compute_rheo_kernel.h" -#include "compute_rheo_solids.h" #include "domain.h" #include "error.h" #include "fix_rheo.h" @@ -33,18 +33,19 @@ #include "neigh_request.h" using namespace LAMMPS_NS; +using namespace RHEO_NS; using namespace FixConst; using namespace MathExtra; -#define EPSILON 1e-10; +static constexpr double EPSILON = 1e-10; /* ---------------------------------------------------------------------- */ ComputeRHEOSurface::ComputeRHEOSurface(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), compute_kernel(nullptr), compute_solids(nullptr), + Compute(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), compute_kernel(nullptr), compute_interface(nullptr), B(nullptr), gradC(nullptr), nsurface(nullptr), divr(nullptr), rsurface(nullptr) { - if (narg != 3) error->all(FLERR,"Illegal fix RHEO/SURFACE command"); + if (narg != 3) error->all(FLERR,"Illegal compute RHEO/SURFACE command"); int dim = domain->dimension; comm_forward = 2; @@ -75,19 +76,19 @@ ComputeRHEOSurface::~ComputeRHEOSurface() void ComputeRHEOSurface::init() { compute_kernel = fix_rheo->compute_kernel; - compute_solids = fix_rheo->compute_solids; + compute_interface = fix_rheo->compute_interface; cut = fix_rheo->cut; rho0 = fix_rheo->rho0; threshold_style = fix_rheo->surface_style; - threshold_divr = fix_rheo->divrsurface; - threshold_z = fix_rheo->zminsurface; + threshold_divr = fix_rheo->divr_surface; + threshold_z = fix_rheo->zmin_surface; cutsq = cut * cut; // Create rsurface, divr, nsurface arrays if they don't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded // For B and gradC, create a local array since they are unlikely to be printed int tmp1, tmp2; @@ -103,12 +104,13 @@ void ComputeRHEOSurface::init() if (index == -1) index = atom->add_custom("rheo_nsurface", 1, 3); nsurface = atom->darray[index]; - nmax_old = atom->nmax; - memory->create(B, nmax_old, dim * dim, "rheo/surface:B"); - memory->create(gradC, nmax_old, dim * dim, "rheo/surface:gradC"); + nmax_store = atom->nmax; + int dim = domain->dimension; + memory->create(B, nmax_store, dim * dim, "rheo/surface:B"); + memory->create(gradC, nmax_store, dim * dim, "rheo/surface:gradC"); // need an occasional half neighbor list - neighbor->add_request(this, NeighConst::REQ_HALF); + neighbor->add_request(this, NeighConst::REQ_DEFAULT); } /* ---------------------------------------------------------------------- */ @@ -123,9 +125,8 @@ void ComputeRHEOSurface::init_list(int /*id*/, NeighList *ptr) void ComputeRHEOSurface::compute_peratom() { int i, j, ii, jj, inum, jnum, a, b, itype, jtype, fluidi, fluidj; - double xtmp, ytmp, ztmp, rsq, Voli, Volj, rhoi, rhoj; - double *dWij, *dWji; - double dx[3]; + double xtmp, ytmp, ztmp, rsq, Voli, Volj, rhoi, rhoj, wp; + double *dWij, *dWji, dx[3]; int *ilist, *jlist, *numneigh, **firstneigh; int nlocal = atom->nlocal; @@ -146,7 +147,7 @@ void ComputeRHEOSurface::compute_peratom() firstneigh = list->firstneigh; int nmax = atom->nmax; - if (nmax_old <= nmax) { + if (nmax_store <= nmax) { memory->grow(divr, nmax, "atom:rheo_divr"); memory->grow(rsurface, nmax, "atom:rheo_rsurface"); memory->grow(nsurface, nmax, 3, "atom:rheo_nsurface"); @@ -154,7 +155,7 @@ void ComputeRHEOSurface::compute_peratom() memory->grow(B, nmax, dim * dim, "rheo/surface:B"); memory->grow(gradC, nmax, dim * dim, "rheo/surface:gradC"); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } int nall = nlocal + atom->nghost; @@ -169,7 +170,7 @@ void ComputeRHEOSurface::compute_peratom() divr[i] = 0.0; // Remove surface settings - status[i] &= FixRHEO::surfacemask; + status[i] &= SURFACEMASK; } // loop over neighbors to calculate the average orientation of neighbors @@ -182,7 +183,7 @@ void ComputeRHEOSurface::compute_peratom() jlist = firstneigh[i]; jnum = numneigh[i]; itype = type[i]; - fluidi = status[i] & FixRHEO::STATUS_FLUID; + fluidi = status[i] & STATUS_FLUID; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -192,19 +193,19 @@ void ComputeRHEOSurface::compute_peratom() dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = lensq(dx); + rsq = lensq3(dx); if (rsq < cutsq) { jtype = type[j]; - fluidj = status[j] & FixRHEO::STATUS_FLUID; + fluidj = status[j] & STATUS_FLUID; rhoi = rho[i]; rhoj = rho[j]; // Add corrections for walls if (fluidi && (!fluidj)) { - rhoj = compute_solids->correct_rho(j, i); + rhoj = compute_interface->correct_rho(j, i); } else if ((!fluidi) && fluidj) { - rhoi = compute_solids->correct_rho(i, j); + rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { rhoi = rho0; rhoj = rho0; @@ -253,29 +254,29 @@ void ComputeRHEOSurface::compute_peratom() } // Find the free-surface - if (threshold_style == FixRHEO::DIVR) { + if (threshold_style == DIVR) { for (i = 0; i < nall; i++) { if (mask[i] & groupbit) { - status[i] |= FixRHEO::STATUS_BULK; + status[i] |= STATUS_BULK; rsurface[i] = cut; if (divr[i] < threshold_divr) { - status[i] |= FixRHEO::STATUS_SURFACE; + status[i] |= STATUS_SURFACE; rsurface[i] = 0.0; if (coordination[i] < threshold_z) - status[i] |= FixRHEO::STATUS_SPLASH; + status[i] |= STATUS_SPLASH; } } } } else { for (i = 0; i < nall; i++) { if (mask[i] & groupbit) { - status[i] |= FixRHEO::STATUS_BULK; + status[i] |= STATUS_BULK; rsurface[i] = cut; - if (coordination[i] < divR_limit) { - status[i] |= FixRHEO::STATUS_SURFACE; + if (coordination[i] < threshold_divr) { + status[i] |= STATUS_SURFACE; rsurface[i] = 0.0; if (coordination[i] < threshold_z) - status[i] |= FixRHEO::STATUS_SPLASH; + status[i] |= STATUS_SPLASH; } } } @@ -297,23 +298,23 @@ void ComputeRHEOSurface::compute_peratom() dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; - rsq = lensq(dx); + rsq = lensq3(dx); if (rsq < cutsq) { - if ((status[i] & FixRHEO::STATUS_BULK) && (status[j] & FixRHEO::STATUS_SURFACE)) { - status[i] &= FixRHEO::surfacemask; - status[i] |= FixRHEO::STATUS_LAYER; + if ((status[i] & STATUS_BULK) && (status[j] & STATUS_SURFACE)) { + status[i] &= SURFACEMASK; + status[i] |= STATUS_LAYER; } - if (status[j] & FixRHEO::STATUS_SURFACE) rsurface[i] = MIN(rsurface[i], sqrt(rsq)); + if (status[j] & STATUS_SURFACE) rsurface[i] = MIN(rsurface[i], sqrt(rsq)); if (j < nlocal || newton) { - if ((status[j] & FixRHEO::STATUS_BULK) && (status[i] & FixRHEO::STATUS_SURFACE)) { - status[j] &= FixRHEO::surfacemask; - status[j] |= FixRHEO::STATUS_LAYER; + if ((status[j] & STATUS_BULK) && (status[i] & STATUS_SURFACE)) { + status[j] &= SURFACEMASK; + status[j] |= STATUS_LAYER; } - if (status[i] & FixRHEO::STATUS_SURFACE) rsurface[j] = MIN(rsurface[j], sqrt(rsq)); + if (status[i] & STATUS_SURFACE) rsurface[j] = MIN(rsurface[j], sqrt(rsq)); } } } @@ -371,7 +372,7 @@ void ComputeRHEOSurface::unpack_reverse_comm(int n, int *list, double *buf) } else if (comm_stage == 1) { temp = (int) buf[m++]; - if ((status[j] & FixRHEO::STATUS_BULK) && (temp & FixRHEO::STATUS_LAYER)) + if ((status[j] & STATUS_BULK) && (temp & STATUS_LAYER)) status[j] = temp; rsurface[j] = MIN(rsurface[j], buf[m++]); diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 224b2594a1..58a3e3b9c4 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -17,8 +17,8 @@ ComputeStyle(RHEO/SURFACE,ComputeRHEOSurface) // clang-format on #else -#ifndef LMP_COMPUTE_RHEO_INTERFACE_H -#define LMP_COMPUTE_RHEO_INTERFACE_H +#ifndef LMP_COMPUTE_RHEO_SURFACE_H +#define LMP_COMPUTE_RHEO_SURFACE_H #include "compute.h" @@ -36,18 +36,18 @@ class ComputeRHEOSurface : public Compute { int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; - double **nsurface, **rsurface; + double **nsurface, *rsurface; class FixRHEO *fix_rheo; private: double cut, cutsq, rho0, threshold_divr; - int surface_style, nmax_old, threshold_z; + int surface_style, nmax_store, threshold_z; double **B, **gradC, *divr; int threshold_style, comm_stage; class NeighList *list; class ComputeRHEOKernel *compute_kernel; - class ComputeRHEOSolids *compute_solids; + class ComputeRHEOInterface *compute_interface; }; } // namespace LAMMPS_NS diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 1b3edcffd8..440bfc7fc7 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -32,6 +32,7 @@ #include "neigh_request.h" using namespace LAMMPS_NS; +using namespace RHEO_NS; /* ---------------------------------------------------------------------- */ @@ -47,15 +48,15 @@ ComputeRHEOVShift::ComputeRHEOVShift(LAMMPS *lmp, int narg, char **arg) : // Create vshift array if it doesn't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded int tmp1, tmp2; int index = atom->find_custom("rheo_vshift", tmp1, tmp2); if (index == -1) { index = atom->add_custom("rheo_vshift", 1, 3); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } - vshift = atom->dvector[index]; + vshift = atom->darray[index]; } /* ---------------------------------------------------------------------- */ @@ -108,16 +109,17 @@ void ComputeRHEOVShift::compute_peratom() int *jlist; int inum, *ilist, *numneigh, **firstneigh; - int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; - double **x = atom->x; - double **v = atom->v; int *type = atom->type; int *status = atom->status; - int *surface = atom->surface; + int *mask = atom->mask; + double **x = atom->x; + double **v = atom->v; double *rho = atom->rho; double *mass = atom->mass; + + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; int newton_pair = force->newton_pair; inum = list->inum; @@ -125,9 +127,9 @@ void ComputeRHEOVShift::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - if (nmax_old < atom->nmax) { + if (nmax_store < atom->nmax) { memory->grow(vshift, atom->nmax, 3, "atom:rheo_vshift"); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } for (i = 0; i < nall; i++) @@ -143,15 +145,15 @@ void ComputeRHEOVShift::compute_peratom() jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; - fluidi = status[i] & FixRHEO::STATUS_FLUID; + fluidi = status[i] & STATUS_FLUID; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; - fluidj = status[j] & FixRHEO::STATUS_FLUID; + fluidj = status[j] & STATUS_FLUID; if ((!fluidi) && (!fluidj)) continue; - if (!(status[i] & FixRHEO::STATUS_SHIFT) && !(status[j] & FixRHEO::STATUS_SHIFT)) continue; + if (!(status[i] & STATUS_SHIFT) && !(status[j] & STATUS_SHIFT)) continue; dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; @@ -175,10 +177,10 @@ void ComputeRHEOVShift::compute_peratom() // Add corrections for walls if (fluidi && (!fluidj)) { - compute_interface->correct_v(v[i], v[j], vi, i, j); + compute_interface->correct_v(vi, vj, i, j); rhoj = compute_interface->correct_rho(j,i); } else if ((!fluidi) && fluidj) { - compute_interface->correct_v(v[j], v[i], vj, j, i); + compute_interface->correct_v(vj, vi, j, i); rhoi = compute_interface->correct_rho(i,j); } else if ((!fluidi) && (!fluidj)) { rhoi = 1.0; @@ -215,7 +217,7 @@ void ComputeRHEOVShift::compute_peratom() } } - if (newton_pair) comm->reverse_comm_compute(this); + if (newton_pair) comm->reverse_comm(this); } @@ -239,7 +241,7 @@ void ComputeRHEOVShift::correct_surfaces() double nx,ny,nz,vx,vy,vz; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { - if ((status[i] & FixRHEO::STATUS_SURFACE) || (status[i] & FixRHEO::STATUS_LAYER)) { + if ((status[i] & STATUS_SURFACE) || (status[i] & STATUS_LAYER)) { nx = nsurf[i][0]; ny = nsurf[i][1]; vx = vshift[i][0]; @@ -297,6 +299,6 @@ void ComputeRHEOVShift::unpack_reverse_comm(int n, int *list, double *buf) double ComputeRHEOVShift::memory_usage() { - double bytes = 3 * nmax_old * sizeof(double); + double bytes = 3 * nmax_store * sizeof(double); return bytes; } diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h index 88a9cdcd1d..8611e177d1 100644 --- a/src/RHEO/compute_rheo_vshift.h +++ b/src/RHEO/compute_rheo_vshift.h @@ -40,7 +40,7 @@ class ComputeRHEOVShift : public Compute { class FixRHEO *fix_rheo; private: - int nmax_old; + int nmax_store; double dtv, cut, cutsq, cutthird; int surface_flag; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 2b55320c4e..ff804fe007 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -33,6 +33,7 @@ #include "utils.h" using namespace LAMMPS_NS; +using namespace RHEO_NS; using namespace FixConst; /* ---------------------------------------------------------------------- */ @@ -68,6 +69,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR,"Insufficient arguments for fix rheo command"); h = utils::numeric(FLERR,arg[3],false,lmp); + cut = h; if (strcmp(arg[4],"Quintic") == 0) { kernel_style = QUINTIC; } else if (strcmp(arg[4],"CRK0") == 0) { @@ -101,7 +103,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : iarg += 2; } else if (strcmp(arg[iarg],"interface/reconstruction") == 0) { interface_flag = 1; - } else if (strcmp(arg[iarg],"rhosum") == 0) { + } else if (strcmp(arg[iarg],"rho/sum") == 0) { rhosum_flag = 1; } else if (strcmp(arg[iarg],"rho0") == 0) { if(iarg + 1 >= narg) error->all(FLERR,"Illegal rho0 option in fix rheo"); @@ -137,7 +139,8 @@ FixRHEO::~FixRHEO() void FixRHEO::post_constructor() { - compute_kernel = dynamic_cast(modify->add_compute("rheo_kernel all RHEO/KERNEL {}", kernel_style)); + compute_kernel = dynamic_cast(modify->add_compute( + fmt::format("rheo_kernel all RHEO/KERNEL {}", kernel_style))); compute_kernel->fix_rheo = this; std::string cmd = "rheo_grad all RHEO/GRAD velocity rho viscosity"; @@ -146,22 +149,26 @@ void FixRHEO::post_constructor() compute_grad->fix_rheo = this; if (rhosum_flag) { - compute_rhosum = dynamic_cast(modify->add_compute("rheo_rho_sum all RHEO/RHO/SUM")); + compute_rhosum = dynamic_cast(modify->add_compute( + "rheo_rho_sum all RHEO/RHO/SUM")); compute_rhosum->fix_rheo = this; } if (shift_flag) { - compute_vshift = dynamic_cast(modify->add_compute("rheo_vshift all RHEO/VSHIFT")); + compute_vshift = dynamic_cast(modify->add_compute( + "rheo_vshift all RHEO/VSHIFT")); compute_vshift->fix_rheo = this; } if (interface_flag) { - compute_interface = dynamic_cast(modify->add_compute(fmt::format("rheo_interface all RHEO/INTERFACE"))); + compute_interface = dynamic_cast(modify->add_compute( + "rheo_interface all RHEO/INTERFACE")); compute_interface->fix_rheo = this; } if (surface_flag) { - compute_surface = dynamic_cast(modify->add_compute(fmt::format("rheo_surface all RHEO/SURFACE"))); + compute_surface = dynamic_cast(modify->add_compute( + "rheo_surface all RHEO/SURFACE")); compute_surface->fix_rheo = this; } } @@ -193,7 +200,7 @@ void FixRHEO::init() void FixRHEO::setup_pre_force(int /*vflag*/) { // Check to confirm accessory fixes do not preceed FixRHEO - // Note: these fixes set this flag in setup_pre_force() + // Note: fixes set this flag in setup_pre_force() if (viscosity_fix_defined || pressure_fix_defined || thermal_fix_defined) error->all(FLERR, "Fix RHEO must be defined before all other RHEO fixes"); @@ -206,23 +213,23 @@ void FixRHEO::setup_pre_force(int /*vflag*/) void FixRHEO::setup(int /*vflag*/) { // Confirm all accessory fixes are defined - // Note: these fixes set this flag in setup_pre_force() + // Note: fixes set this flag in setup_pre_force() if (!viscosity_fix_defined) error->all(FLERR, "Missing fix rheo/viscosity"); if (!pressure_fix_defined) error->all(FLERR, "Missing fix rheo/pressure"); - if(!thermal_fix_defined && thermal_flag) + if((!thermal_fix_defined) && thermal_flag) error->all(FLERR, "Missing fix rheo/thermal"); - // Reset to zero for next run + // Reset to zero for future runs thermal_fix_defined = 0; viscosity_fix_defined = 0; pressure_fix_defined = 0; - // Check fixes cover all atoms (doesnt ensure user covers atoms created midrun) - // (pressure is currently required to be group all) + // Check fixes cover all atoms (may still fail if atoms are created) + // FixRHEOPressure currently requires group all auto visc_fixes = modify->get_fix_by_style("rheo/viscosity"); auto therm_fixes = modify->get_fix_by_style("rheo/thermal"); @@ -232,12 +239,12 @@ void FixRHEO::setup(int /*vflag*/) int covered; for (int i = 0; i < atom->nlocal; i++) { covered = 0; - for (auto fix in visc_fixes) + for (auto fix : visc_fixes) if (mask[i] & fix->groupbit) covered = 1; if (!covered) v_coverage_flag = 0; if (thermal_flag) { covered = 0; - for (auto fix in therm_fixes) + for (auto fix : therm_fixes) if (mask[i] & fix->groupbit) covered = 1; if (!covered) v_coverage_flag = 0; } @@ -253,11 +260,12 @@ void FixRHEO::setup(int /*vflag*/) void FixRHEO::initial_integrate(int /*vflag*/) { - // update v and x and rho of atoms in group + // update v, x and rho of atoms in group int i, a, b; double dtfm, divu; - int dim = domain->dimension; + int *type = atom->type; + int *mask = atom->mask; int *status = atom->status; double **x = atom->x; double **v = atom->v; @@ -266,16 +274,14 @@ void FixRHEO::initial_integrate(int /*vflag*/) double *drho = atom->drho; double *mass = atom->mass; double *rmass = atom->rmass; - int rmass_flag = atom->rmass_flag; - double **gradr = compute_grad->gradr; double **gradv = compute_grad->gradv; double **vshift; if (shift_flag) compute_vshift->vshift; - int *type = atom->type; - int *mask = atom->mask; int nlocal = atom->nlocal; + int rmass_flag = atom->rmass_flag; + int dim = domain->dimension; if (igroup == atom->firstgroup) nlocal = atom->nfirst; @@ -333,7 +339,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) // Shifting atoms if (shift_flag) { - compute_vshift->correct_surfaces(); // COuld this be moved to preforce after the surface fix runs? + compute_vshift->correct_surfaces(); // Could this be moved to preforce after the surface fix runs? for (i = 0; i < nlocal; i++) { if (!(status[i] & STATUS_SHIFT)) continue; @@ -376,6 +382,7 @@ void FixRHEO::pre_force(int /*vflag*/) compute_vshift->compute_peratom(); // Remove extra shifting/no force options + int *mask = atom->mask; int *status = atom->status; int nall = atom->nlocal + atom->nghost; for (int i = 0; i < nall; i++) { @@ -393,26 +400,28 @@ void FixRHEO::pre_force(int /*vflag*/) /* ---------------------------------------------------------------------- */ -void FixRHEO::final_integrate() { - int *status = atom->status; - double **gradv = compute_grad->gradv; - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - - double *rho = atom->rho; - double *drho = atom->drho; - int *type = atom->type; - int *mask = atom->mask; - double *mass = atom->mass; +void FixRHEO::final_integrate() +{ int nlocal = atom->nlocal; if (igroup == atom->firstgroup) nlocal = atom->nfirst; + double dtfm, divu; - double *rmass = atom->rmass; - int rmass_flag = atom->rmass_flag; int i, a; + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + double **gradv = compute_grad->gradv; + double *rho = atom->rho; + double *drho = atom->drho; + double *mass = atom->mass; + double *rmass = atom->rmass; + int *type = atom->type; + int *mask = atom->mask; + int *status = atom->status; + + int rmass_flag = atom->rmass_flag; int dim = domain->dimension; // Update velocity diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 0064f4c90b..1d8ae06159 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -39,33 +39,10 @@ class FixRHEO : public Fix { void reset_dt() override; // Model parameters - double h, rho0, csq; + double h, cut, rho0, csq; int zmin_kernel, zmin_surface; int kernel_style, surface_style; double divr_surface; - enum {QUINTIC, CRK0, CRK1, CRK2}; - enum {COORDINATION, DIVR}; - - // Status variables - enum { - // Phase status - STATUS_FLUID = 1 << 0, - STATUS_REACTIVE = 1 << 1, - STATUS_SOLID = 1 << 2, - STATUS_FREEZING = 1 << 3, - - // Surface status - STATUS_BULK = 1 << 4, - STATUS_LAYER = 1 << 5, - STATUS_SURFACE = 1 << 6, - STATUS_SPLASH = 1 << 7, - - // Temporary status options - reset in preforce - STATUS_SHIFT = 1 << 8, - STATUS_NO_FORCE = 1 << 9 - }; - int phasemask = 0xFFFFFFF0; - int surfacemask = 0xFFFFFF0F; // Accessory fixes/computes int thermal_flag; @@ -89,6 +66,32 @@ class FixRHEO : public Fix { double dtv, dtf; }; +namespace RHEO_NS { + + enum {QUINTIC, CRK0, CRK1, CRK2}; + enum {COORDINATION, DIVR}; + + // Status variables + enum Status{ + // Phase status + STATUS_FLUID = 1 << 0, + STATUS_REACTIVE = 1 << 1, + STATUS_SOLID = 1 << 2, + STATUS_FREEZING = 1 << 3, + // Surface status + STATUS_BULK = 1 << 4, + STATUS_LAYER = 1 << 5, + STATUS_SURFACE = 1 << 6, + STATUS_SPLASH = 1 << 7, + // Temporary status options - reset in preforce + STATUS_SHIFT = 1 << 8, + STATUS_NO_FORCE = 1 << 9 + }; + + int PHASEMASK = 0xFFFFFFF0; + int SURFACEMASK = 0xFFFFFF0F; + +} // namespace RHEO_NS } // namespace LAMMPS_NS #endif diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 726c44c32b..75edf42572 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -33,6 +33,8 @@ using namespace LAMMPS_NS; using namespace FixConst; enum {NONE, LINEAR, CUBIC, TAITWATER}; +static constexpr double SEVENTH = 1.0 / 7.0; + /* ---------------------------------------------------------------------- */ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : @@ -43,7 +45,7 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : pressure_style = NONE; comm_forward = 1; - nmax_old = 0; + nmax_store = 0; // Currently can only have one instance of fix rheo/pressure if (igroup != 0) @@ -112,13 +114,13 @@ void FixRHEOPressure::setup_pre_force(int /*vflag*/) // Create pressure array if it doesn't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded int tmp1, tmp2; int index = atom->find_custom("rheo_pressure", tmp1, tmp2); if (index == -1) { index = atom->add_custom("rheo_pressure", 1, 0); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } pressure = atom->dvector[index]; @@ -139,13 +141,11 @@ void FixRHEOPressure::pre_force(int /*vflag*/) int nlocal = atom->nlocal; - if (nmax_old < atom->nmax) { + if (nmax_store < atom->nmax) { memory->grow(pressure, atom->nmax, "atom:rheo_pressure"); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } - if (pressure_style == TAITWATER) inv7 = 1.0 / 7.0; - for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (pressure_style == LINEAR) { @@ -156,7 +156,7 @@ void FixRHEOPressure::pre_force(int /*vflag*/) } else if (pressure_style == TAITWATER) { rho_ratio = rho[i] / rho0inv; rr3 = rho_ratio * rho_ratio * rho_ratio; - pressure[i] = csq * rho0 * inv7 * (rr3 * rr3 * rho_ratio - 1.0); + pressure[i] = csq * rho0 * SEVENTH * (rr3 * rr3 * rho_ratio - 1.0); } } } @@ -194,9 +194,10 @@ void FixRHEOPressure::unpack_forward_comm(int n, int first, double *buf) /* ---------------------------------------------------------------------- */ -double FixRHEOPressure::calculate_p(double rho) +double FixRHEOPressure::calc_pressure(double rho) { - double rho; + double p, dr, rr3, rho_ratio; + if (pressure_style == LINEAR) { p = csq * (rho - rho0); } else if (pressure_style == CUBIC) { @@ -205,7 +206,7 @@ double FixRHEOPressure::calculate_p(double rho) } else if (pressure_style == TAITWATER) { rho_ratio = rho / rho0inv; rr3 = rho_ratio * rho_ratio * rho_ratio; - p = csq * rho0 * inv7 * (rr3 * rr3 * rho_ratio - 1.0); + p = csq * rho0 * SEVENTH * (rr3 * rr3 * rho_ratio - 1.0); } return rho; } @@ -215,6 +216,6 @@ double FixRHEOPressure::calculate_p(double rho) double FixRHEOPressure::memory_usage() { double bytes = 0.0; - bytes += (size_t) nmax_old * sizeof(double); + bytes += (size_t) nmax_store * sizeof(double); return bytes; } diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index 197cab6e5c..c257f1dbfb 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -35,13 +35,14 @@ class FixRHEOPressure : public Fix { int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; double memory_usage() override; - double calculate_p(double); + double calc_pressure(double); + private: double c_cubic, csq, rho0, rho0inv; double *pressure; int pressure_style; int first_flag, last_flag; - int nmax_old; + int nmax_store; class FixRHEO *fix_rheo; }; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index fd08f39fd7..5df8c1c506 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -22,6 +22,7 @@ #include "comm.h" #include "compute_rheo_grad.h" #include "compute_rheo_vshift.h" +#include "domain.h" #include "error.h" #include "fix_rheo.h" #include "force.h" @@ -31,14 +32,15 @@ #include "update.h" using namespace LAMMPS_NS; +using namespace RHEO_NS; using namespace FixConst; enum {NONE, CONSTANT, TYPE}; /* ---------------------------------------------------------------------- */ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), - conductivity(nullptr) + Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), compute_vshift(nullptr), + Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), conductivity(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -47,7 +49,7 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : conductivity_style = NONE; comm_forward = 1; - nmax_old = 0; + nmax_store = 0; int ntypes = atom->ntypes; int iarg = 3; @@ -181,13 +183,13 @@ void FixRHEOThermal::setup_pre_force(int /*vflag*/) // Identify whether this is the first/last instance of fix thermal // First will grow arrays, last will communicate - first_flag = 0 + first_flag = 0; last_flag = 0; int i = 0; auto fixlist = modify->get_fix_by_style("rheo/thermal"); - for (const auto &ifix : fixlist) { - if (strcmp(ifix->id, id) == 0) break; + for (const auto &fix : fixlist) { + if (strcmp(fix->id, id) == 0) break; i++; } @@ -197,13 +199,13 @@ void FixRHEOThermal::setup_pre_force(int /*vflag*/) // Create conductivity array if it doesn't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded int tmp1, tmp2; - index = atom->find_custom("rheo_conductivity", tmp1, tmp2); + int index = atom->find_custom("rheo_conductivity", tmp1, tmp2); if (index== -1) { index = atom->add_custom("rheo_conductivity", 1, 0); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } conductivity = atom->dvector[index]; @@ -217,13 +219,16 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) { // update temperature from shifting if (!fix_rheo->shift_flag) return; - int i; + int i, a; + int *status = atom->status; + int *mask = atom->mask; + double *temperature = atom->temperature; double **gradt = compute_grad->gradt; double **vshift = compute_vshift->array_atom; - int *mask = atom->mask; int nlocal = atom->nlocal; + int dim = domain->dimension; if (igroup == atom->firstgroup) nlocal = atom->nfirst; @@ -248,14 +253,14 @@ void FixRHEOThermal::post_integrate() double *heatflow = atom->heatflow; double *rho = atom->rho; int *mask = atom->mask; - int *type = aotm->type; + int *type = atom->type; double cvi, Tci, Ti; //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { - if (status[i] == FixRHEO::FLUID_NO_FORCE) continue; + if (status[i] & STATUS_NO_FORCE) continue; cvi = calc_cv(i); temperature[i] += dtf * heatflow[i] / cvi; @@ -265,15 +270,15 @@ void FixRHEOThermal::post_integrate() if (Tc_style == CONSTANT) { Tci = Tc; } else if (Tc_style == TYPE) { - Tci = Tc_type[type[i]]); + Tci = Tc_type[type[i]]; } if (Ti > Tci) { - status[i] &= FixRHEO::phasemask; - status[i] |= FixRHEO::STATUS_FLUID; - } else if (!(status[i] & FixRHEO::STATUS_SOLID)) - status[i] &= FixRHEO::phasemask; - status[i] |= FixRHEO::STATUS_FREEZING; + status[i] &= PHASEMASK; + status[i] |= STATUS_FLUID; + } else if (!(status[i] & STATUS_SOLID)) { + status[i] &= PHASEMASK; + status[i] |= STATUS_FREEZING; } } } @@ -288,14 +293,13 @@ void FixRHEOThermal::post_neighbor() { int i; int *type = atom->type; - double *conductivity = atom->dvector[index_cond]; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (first_flag && (nmax_old < atom->nmax)) { + if (first_flag && (nmax_store < atom->nmax)) { memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } if (conductivity_style == CONSTANT) { @@ -304,7 +308,6 @@ void FixRHEOThermal::post_neighbor() } else if (conductivity_style == TYPE) { for (i = 0; i < nall; i++) if (mask[i] & groupbit) conductivity[i] = kappa_type[type[i]]; - } } } @@ -329,9 +332,9 @@ void FixRHEOThermal::pre_force(int /*vflag*/) //int *mask = atom->mask; //int nlocal = atom->nlocal; - //if (first_flag && (nmax_old < atom->nmax)) { + //if (first_flag && (nmax_store < atom->nmax)) { // memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); - // nmax_old = atom->nmax; + // nmax_store = atom->nmax; //} //if (conductivity_style == TBD) { @@ -358,7 +361,7 @@ void FixRHEOThermal::final_integrate() //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { - if (status[i] & FixRHEO::STATUS_NO_FORCE) continue; + if (status[i] & STATUS_NO_FORCE) continue; cvi = calc_cv(i); temperature[i] += dtf * heatflow[i] / cvi; @@ -447,6 +450,6 @@ void FixRHEOThermal::unpack_reverse_comm(int n, int *list, double *buf) double FixRHEOThermal::memory_usage() { double bytes = 0.0; - bytes += (size_t) nmax_old * sizeof(double); + bytes += (size_t) nmax_store * sizeof(double); return bytes; } diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index 4f0e89f17c..cf64c0b8d1 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -31,7 +31,7 @@ class FixRHEOThermal : public Fix { int setmask() override; void init() override; void setup_pre_force(int) override; - void initial_integrate() override; + void initial_integrate(int) override; void post_integrate() override; void post_neighbor() override; void pre_force(int) override; @@ -53,9 +53,11 @@ class FixRHEOThermal : public Fix { int cv_style; int conductivity_style; int first_flag, last_flag; - int nmax_old; + int nmax_store; class FixRHEO *fix_rheo; + class ComputeRHEOGrad *compute_grad; + class ComputeRHEOVShift *compute_vshift; double calc_cv(int); }; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 5ae1b95529..b15f488370 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -44,7 +44,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : viscosity_style = NONE; comm_forward = 0; - nmax_old = 0; + nmax_store = 0; int ntypes = atom->ntypes; int iarg = 3; @@ -89,7 +89,7 @@ FixRHEOViscosity::~FixRHEOViscosity() // Remove custom property if it exists int tmp1, tmp2, index; index = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index != -1) atom->remove_custom(index_visc, 1, 0); + if (index != -1) atom->remove_custom(index, 1, 0); memory->destroy(eta_type); } @@ -123,13 +123,13 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) // Identify whether this is the first/last instance of fix viscosity // First will grow arrays, last will communicate - first_flag = 0 + first_flag = 0; last_flag = 0; int i = 0; auto fixlist = modify->get_fix_by_style("rheo/viscosity"); - for (const auto &ifix : fixlist) { - if (strcmp(ifix->id, id) == 0) break; + for (const auto &fix : fixlist) { + if (strcmp(fix->id, id) == 0) break; i++; } @@ -139,13 +139,13 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) // Create viscosity array if it doesn't already exist // Create a custom atom property so it works with compute property/atom // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_old exceeded + // Manually grow if nmax_store exceeded int tmp1, tmp2; int index = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index_visc == -1) { + if (index == -1) { index = atom->add_custom("rheo_viscosity", 1, 0); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } viscosity = atom->dvector[index]; @@ -167,9 +167,9 @@ void FixRHEOViscosity::post_neighbor() int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (first_flag && (nmax_old < atom->nmax)) { + if (first_flag && (nmax_store < atom->nmax)) { memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } if (viscosity_style == CONSTANT) { @@ -178,7 +178,6 @@ void FixRHEOViscosity::post_neighbor() } else if (viscosity_style == TYPE) { for (i = 0; i < nall; i++) if (mask[i] & groupbit) viscosity[i] = eta_type[type[i]]; - } } } @@ -197,9 +196,9 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) int nlocal = atom->nlocal; int dim = domain->dimension; - if (first_flag && (nmax_old < atom->nmax)) { + if (first_flag && (nmax_store < atom->nmax)) { memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); - nmax_old = atom->nmax; + nmax_store = atom->nmax; } if (viscosity_style == POWER) { @@ -260,6 +259,6 @@ void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) double FixRHEOViscosity::memory_usage() { double bytes = 0.0; - bytes += (size_t) nmax_old * sizeof(double); + bytes += (size_t) nmax_store * sizeof(double); return bytes; } diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index 14f8b70de9..66df51601e 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -43,7 +43,7 @@ class FixRHEOViscosity : public Fix { double *viscosity; int viscosity_style; int first_flag, last_flag; - int nmax_old; + int nmax_store; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 5974b9b756..c61d613d82 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -39,9 +39,10 @@ #include using namespace LAMMPS_NS; +using namespace RHEO_NS; using namespace MathExtra; -#define EPSILON 1e-2 +static constexpr double EPSILON = 1e-2; /* ---------------------------------------------------------------------- */ @@ -83,6 +84,10 @@ void PairRHEO::compute(int eflag, int vflag) int *ilist, *jlist, *numneigh, **firstneigh; double imass, jmass, rsq, r, rinv; + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + int dim = domain->dimension; + ev_init(eflag, vflag); double **gradv = compute_grad->gradv; @@ -123,11 +128,6 @@ void PairRHEO::compute(int eflag, int vflag) conductivity = atom->dvector[index]; } - int *ilist, *jlist, *numneigh, **firstneigh; - int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; - int dim = domain->dimension; - inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; @@ -145,7 +145,7 @@ void PairRHEO::compute(int eflag, int vflag) jnum = numneigh[i]; imass = mass[itype]; etai = viscosity[i]; - fluidi = status[i] & FixRHEO::STATUS_FLUID; + fluidi = status[i] & STATUS_FLUID; if (thermal_flag) { kappai = conductivity[i]; Ti = temperature[i]; @@ -167,7 +167,7 @@ void PairRHEO::compute(int eflag, int vflag) jmass = mass[jtype]; etaj = viscosity[j]; - fluidj = status[j] & FixRHEO::STATUS_FLUID; + fluidj = status[j] & STATUS_FLUID; if (thermal_flag) { Tj = temperature[j]; kappaj = conductivity[j]; @@ -202,7 +202,7 @@ void PairRHEO::compute(int eflag, int vflag) if (fluidi && (!fluidj)) { compute_interface->correct_v(vi, vj, i, j); rhoj = compute_interface->correct_rho(j, i); - Pj = fix_pressure->calculate_p(rhoj); + Pj = fix_pressure->calc_pressure(rhoj); if ((chi[j] > 0.9) && (r < (h * 0.5))) fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; @@ -210,9 +210,9 @@ void PairRHEO::compute(int eflag, int vflag) } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vj, vi, j, i); rhoi = compute_interface->correct_rho(i, j); - Pi = calc_pressure(rhoi, itype); + Pi = fix_pressure->calc_pressure(rhoi); - if (chi[i] > 0.9 && r < (h * 0.5)) { + if (chi[i] > 0.9 && r < (h * 0.5)) fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; } else if ((!fluidi) && (!fluidj)) { @@ -244,7 +244,7 @@ void PairRHEO::compute(int eflag, int vflag) //Hydrostatic pressure forces fp_prefactor = voli * volj * (Pj + Pi); - sub3(v1, vj, du); + sub3(vi, vj, du); //Add artificial viscous pressure if required if (artificial_visc_flag && pair_avisc_flag){ @@ -423,15 +423,11 @@ void PairRHEO::setup() if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use pair rheo"); fix_rheo = dynamic_cast(fixes[0]); + // Currently only allow one instance of fix rheo/pressure fixes = modify->get_fix_by_style("rheo/pressure"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo/pressure to use pair rheo"); fix_pressure = dynamic_cast(fixes[0]); - int tmp1, tmp2; - index_pressure = atom->find_custom("rheo_pressure", tmp1, tmp2); - if (index_pressure == -1) index_pressure = atom->add_custom("rheo_pressure", 1, 0); - else error->all(FLERR, "Cannot find pressure value in pair rheo"); - compute_kernel = fix_rheo->compute_kernel; compute_grad = fix_rheo->compute_grad; compute_interface = fix_rheo->compute_interface; @@ -449,9 +445,9 @@ void PairRHEO::setup() error->all(FLERR,"Pair RHEO requires ghost atoms store velocity"); if (laplacian_order == -1) { - if (fix_rheo->kernel_type == FixRHEO::CRK2) + if (fix_rheo->kernel_style == CRK2) laplacian_order = 2; - else if (fix_rheo->kernel_type == FixRHEO::CRK1) + else if (fix_rheo->kernel_style == CRK1) laplacian_order = 1; else laplacian_order = 0; @@ -468,8 +464,5 @@ double PairRHEO::init_one(int i, int j) error->all(FLERR,"All pair rheo coeffs are not set"); } - cut[i][j] = h; - cut[j][i] = cut[i][j]; - - return cut[i][j]; + return h; } From 7cfe45c00b9da61a911de193b0c3682cff291357 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 25 Apr 2023 10:29:39 -0600 Subject: [PATCH 028/385] Adding gsl version, cmake options, readme files --- cmake/CMakeLists.txt | 2 +- cmake/Modules/Packages/RHEO.cmake | 2 ++ cmake/presets/mingw-cross.cmake | 1 - cmake/presets/most.cmake | 1 - cmake/presets/windows.cmake | 1 - src/RHEO/README | 7 +++++++ src/RHEO/compute_rheo_kernel.cpp | 2 +- src/RHEO/fix_rheo.h | 4 ++-- 8 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 cmake/Modules/Packages/RHEO.cmake create mode 100644 src/RHEO/README diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f4a8b9c1ef..abcc392263 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -442,7 +442,7 @@ if(BUILD_OMP) target_link_libraries(lmp PRIVATE OpenMP::OpenMP_CXX) endif() -if(PKG_MSCG OR PKG_ATC OR PKG_AWPMD OR PKG_ML-QUIP OR PKG_ML-POD OR PKG_LATTE OR PKG_ELECTRODE) +if(PKG_MSCG OR PKG_ATC OR PKG_AWPMD OR PKG_ML-QUIP OR PKG_ML-POD OR PKG_LATTE OR PKG_ELECTRODE OR PKG_RHEO) enable_language(C) if (NOT USE_INTERNAL_LINALG) find_package(LAPACK) diff --git a/cmake/Modules/Packages/RHEO.cmake b/cmake/Modules/Packages/RHEO.cmake new file mode 100644 index 0000000000..970a141bbd --- /dev/null +++ b/cmake/Modules/Packages/RHEO.cmake @@ -0,0 +1,2 @@ +find_package(GSL REQUIRED) +target_link_libraries(lammps PRIVATE GSL::gsl) diff --git a/cmake/presets/mingw-cross.cmake b/cmake/presets/mingw-cross.cmake index ec21809edd..6c6170acd3 100644 --- a/cmake/presets/mingw-cross.cmake +++ b/cmake/presets/mingw-cross.cmake @@ -67,7 +67,6 @@ set(WIN_PACKAGES REACTION REAXFF REPLICA - RHEO RIGID SHOCK SMTBQ diff --git a/cmake/presets/most.cmake b/cmake/presets/most.cmake index 2a2cac2755..00c74c81b8 100644 --- a/cmake/presets/most.cmake +++ b/cmake/presets/most.cmake @@ -58,7 +58,6 @@ set(ALL_PACKAGES REACTION REAXFF REPLICA - RHEO RIGID SHOCK SPH diff --git a/cmake/presets/windows.cmake b/cmake/presets/windows.cmake index 9253d439a8..aa9a4656af 100644 --- a/cmake/presets/windows.cmake +++ b/cmake/presets/windows.cmake @@ -56,7 +56,6 @@ set(WIN_PACKAGES REACTION REAXFF REPLICA - RHEO RIGID SHOCK SMTBQ diff --git a/src/RHEO/README b/src/RHEO/README new file mode 100644 index 0000000000..00fff2d694 --- /dev/null +++ b/src/RHEO/README @@ -0,0 +1,7 @@ +RHEO or Reproducing Hydrodynamics and Elastic Objects is a package to model multiphase fluid +systems. The authors include Joel Clemmer (Sandia), Thomas O'Connor (Carnegie Mellon), and +Eric Palermo (Carnegie Mellon). + +This package requires the GNU scientific library (GSL) version 2.7 or later. To build this +package, one must first separately install GSL in a location that can be found by your +environment. diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index d96d8d234e..b7ad1c9b3f 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -649,7 +649,7 @@ void ComputeRHEOKernel::compute_peratom() // Use gsl to get Minv, use Cholesky decomposition since the // polynomials are independent, M is symmetrix & positive-definite gM = gsl_matrix_view_array(M,Mdim,Mdim); - gsl_error = gsl_linalg_cholesky_decomp(&gM.matrix); + gsl_error = gsl_linalg_cholesky_decomp1(&gM.matrix); if (gsl_error) { //Revert to uncorrected SPH for this particle diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 1d8ae06159..f936206811 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -88,8 +88,8 @@ namespace RHEO_NS { STATUS_NO_FORCE = 1 << 9 }; - int PHASEMASK = 0xFFFFFFF0; - int SURFACEMASK = 0xFFFFFF0F; + #define PHASEMASK 0xFFFFFFF0; + #define SURFACEMASK 0xFFFFFF0F; } // namespace RHEO_NS } // namespace LAMMPS_NS From 7fc916a1d40d547cf1371b515a4c5e22a441db46 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 25 Apr 2023 13:38:37 -0600 Subject: [PATCH 029/385] Prototyping example and accessory commands --- src/RHEO/README | 6 +- src/RHEO/compute_rheo_property_atom.cpp | 162 ++++++++++++++++++++++++ src/RHEO/compute_rheo_property_atom.h | 68 ++++++++++ src/RHEO/fix_rheo.h | 4 +- src/set.cpp | 27 +++- 5 files changed, 261 insertions(+), 6 deletions(-) create mode 100644 src/RHEO/compute_rheo_property_atom.cpp create mode 100644 src/RHEO/compute_rheo_property_atom.h diff --git a/src/RHEO/README b/src/RHEO/README index 00fff2d694..7090fc828c 100644 --- a/src/RHEO/README +++ b/src/RHEO/README @@ -2,6 +2,6 @@ RHEO or Reproducing Hydrodynamics and Elastic Objects is a package to model mult systems. The authors include Joel Clemmer (Sandia), Thomas O'Connor (Carnegie Mellon), and Eric Palermo (Carnegie Mellon). -This package requires the GNU scientific library (GSL) version 2.7 or later. To build this -package, one must first separately install GSL in a location that can be found by your -environment. +This package requires the GNU scientific library (GSL). We recommend version 2.7 or later. To +build this package, one must first separately install GSL in a location that can be found by +your environment. diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp new file mode 100644 index 0000000000..a23ba5a639 --- /dev/null +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -0,0 +1,162 @@ +// 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + +#include "compute_rheo_property_atom.h" + +#include "atom.h" +#include "atom_vec.h" +#include "error.h" +#include "memory.h" +#include "update.h" + +#include +#include + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), + index(nullptr), colindex(nullptr), pack_choice(nullptr) +{ + if (narg < 4) utils::missing_cmd_args(FLERR, "compute property/atom", error); + + peratom_flag = 1; + nvalues = narg - 3; + if (nvalues == 1) size_peratom_cols = 0; + else size_peratom_cols = nvalues; + + // parse input values + // customize a new keyword by adding to if statement + + pack_choice = new FnPtrPack[nvalues]; + + int i; + for (int iarg = 3; iarg < narg; iarg++) { + i = iarg-3; + + if (strcmp(arg[iarg],"id") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_id; + } else if (strcmp(arg[iarg],"mol") == 0) { + if (!atom->molecule_flag) + error->all(FLERR,"Compute property/atom {} is not available", arg[iarg]); + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_molecule; + } else if (strcmp(arg[iarg],"proc") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_proc; + } else if (strcmp(arg[iarg],"type") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_type; + } else if (strcmp(arg[iarg],"mass") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_mass; + + + } else { + error->all(FLERR,"Invalid keyword {} for compute rheo/property/atom command ", arg[iarg]); + } + } + + nmax = 0; +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() +{ + delete[] pack_choice; + memory->destroy(vector_atom); + memory->destroy(array_atom); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow vector or array if necessary + + if (atom->nmax > nmax) { + nmax = atom->nmax; + if (nvalues == 1) { + memory->destroy(vector_atom); + memory->create(vector_atom,nmax,"rheo/property/atom:vector"); + } else { + memory->destroy(array_atom); + memory->create(array_atom,nmax,nvalues,"rheo/property/atom:array"); + } + } + + // fill vector or array with per-atom values + + if (nvalues == 1) { + buf = vector_atom; + (this->*pack_choice[0])(0); + } else { + if (nmax) buf = &array_atom[0][0]; + else buf = nullptr; + for (int n = 0; n < nvalues; n++) + (this->*pack_choice[n])(n); + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeRHEOPropertyAtom::memory_usage() +{ + double bytes = (double)nmax * nvalues * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- + one method for every keyword compute rheo/property/atom can output + the atom property is packed into buf starting at n with stride nvalues + customize a new keyword by adding a method +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_rho(int n) +{ + double *rho = atom->rho; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = rho[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_status(int n) +{ + int *status = atom->status; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = status[i]; + else buf[n] = 0.0; + n += nvalues; + } +} diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h new file mode 100644 index 0000000000..26ca004da0 --- /dev/null +++ b/src/RHEO/compute_rheo_property_atom.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(rheo/property/atom,ComputeRHEOPropertyAtom); +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_PROPERTY_ATOM_H +#define LMP_COMPUTE_RHEO_PROPERTY_ATOM_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEOPropertyAtom : public Compute { + public: + ComputeRHEOPropertyAtom(class LAMMPS *, int, char **); + ~ComputeRHEOPropertyAtom() override; + void compute_peratom() override; + double memory_usage() override; + + private: + int nvalues; + int nmax; + double *buf; + + typedef void (ComputeRHEOPropertyAtom::*FnPtrPack)(int); + FnPtrPack *pack_choice; // ptrs to pack functions + + void pack_rho(int); + void pack_drho(int); + void pack_temperature(int); + void pack_heatflow(int); + void pack_status(int); + void pack_phase(int); + void pack_surface(int); + void pack_r_surface(int); + void pack_divr_surface(int); + void pack_nx_surface(int); + void pack_ny_surface(int); + void pack_nz_surface(int); + void pack_coordination(int); + void pack_viscosity(int); + void pack_pressure(int); + void pack_conductivity(int); + void pack_cv(int); + void pack_vx_shift(int); + void pack_vy_shift(int); + void pack_vz_shift(int); + +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index f936206811..a74696e68c 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -75,8 +75,8 @@ namespace RHEO_NS { enum Status{ // Phase status STATUS_FLUID = 1 << 0, - STATUS_REACTIVE = 1 << 1, - STATUS_SOLID = 1 << 2, + STATUS_SOLID = 1 << 1, + STATUS_REACTIVE = 1 << 2, STATUS_FREEZING = 1 << 3, // Surface status STATUS_BULK = 1 << 4, diff --git a/src/set.cpp b/src/set.cpp index 3a175cbfe2..92033b772e 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -49,7 +49,7 @@ enum{TYPE,TYPE_FRACTION,TYPE_RATIO,TYPE_SUBSET, DIPOLE,DIPOLE_RANDOM,SPIN_ATOM,SPIN_RANDOM,SPIN_ELECTRON,RADIUS_ELECTRON, QUAT,QUAT_RANDOM,THETA,THETA_RANDOM,ANGMOM,OMEGA,TEMPERATURE, DIAMETER,RADIUS_ATOM,DENSITY,VOLUME,IMAGE,BOND,ANGLE,DIHEDRAL,IMPROPER, - SPH_E,SPH_CV,SPH_RHO,EDPD_TEMP,EDPD_CV,CC,SMD_MASS_DENSITY, + RHEO_STATUS,SPH_E,SPH_CV,SPH_RHO,EDPD_TEMP,EDPD_CV,CC,SMD_MASS_DENSITY, SMD_CONTACT_RADIUS,DPDTHETA,EPSILON,IVEC,DVEC,IARRAY,DARRAY}; #define BIG INT_MAX @@ -515,6 +515,24 @@ void Set::command(int narg, char **arg) topology(IMPROPER); iarg += 2; + } else if (strcmp(arg[iarg],"rheo/rho") == 0) { + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "set rheo/rho", error); + if (utils::strmatch(arg[iarg+1],"^v_")) varparse(arg[iarg+1],1); + else dvalue = utils::numeric(FLERR,arg[iarg+1],false,lmp); + if (!atom->rho_flag) + error->all(FLERR,"Cannot set attribute {} for atom style {}", arg[iarg], atom->get_style()); + set(SPH_RHO); + iarg += 2; + + } else if (strcmp(arg[iarg],"rheo/status") == 0) { + if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "set rheo/status", error); + if (utils::strmatch(arg[iarg+1],"^v_")) varparse(arg[iarg+1],1); + else ivalue = utils::inumeric(FLERR,arg[iarg+1],false,lmp); + if (!atom->status_flag) + error->all(FLERR,"Cannot set attribute {} for atom style {}", arg[iarg], atom->get_style()); + set(RHEO_STATUS); + iarg += 2; + } else if (strcmp(arg[iarg],"sph/e") == 0) { if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "set sph/e", error); if (utils::strmatch(arg[iarg+1],"^v_")) varparse(arg[iarg+1],1); @@ -881,6 +899,13 @@ void Set::set(int keyword) if (dvalue <= 0.0) error->one(FLERR,"Invalid volume in set command"); atom->vfrac[i] = dvalue; } + + else if (keyword == RHEO_STATUS) { + if (ivalue != 0 && ivalue !=2) + error->one(FLERR,"Invalid value {} in set command for rheo/status", ivalue); + atom->status[i] = ivalue; + } + else if (keyword == SPH_E) atom->esph[i] = dvalue; else if (keyword == SPH_CV) atom->cv[i] = dvalue; else if (keyword == SPH_RHO) atom->rho[i] = dvalue; From be568d257d34a7133a1851adf9fce9ddb7c1184c Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 25 Apr 2023 16:29:29 -0600 Subject: [PATCH 030/385] Adding output option for reorganized peratom values --- src/RHEO/atom_vec_rheo.cpp | 36 ++- src/RHEO/atom_vec_rheo.h | 2 +- src/RHEO/atom_vec_rheo_thermal.cpp | 200 ++++++++++++ src/RHEO/atom_vec_rheo_thermal.h | 46 +++ src/RHEO/compute_rheo_grad.cpp | 85 ++--- src/RHEO/compute_rheo_grad.h | 8 +- src/RHEO/compute_rheo_interface.cpp | 66 ++-- src/RHEO/compute_rheo_kernel.cpp | 53 +-- src/RHEO/compute_rheo_kernel.h | 2 +- src/RHEO/compute_rheo_property_atom.cpp | 293 +++++++++++++++-- src/RHEO/compute_rheo_property_atom.h | 39 +-- src/RHEO/compute_rheo_surface.h | 4 +- src/RHEO/compute_rheo_vshift.cpp | 69 ++-- src/RHEO/compute_rheo_vshift.h | 5 +- src/RHEO/fix_rheo.cpp | 4 + src/RHEO/fix_rheo_pressure.cpp | 2 +- src/RHEO/fix_rheo_thermal.cpp | 141 +------- src/RHEO/fix_rheo_thermal.h | 11 +- src/RHEO/fix_rheo_viscosity.cpp | 54 +--- src/RHEO/fix_rheo_viscosity.h | 6 +- src/RHEO/pair_rheo.cpp | 19 +- src/atom.cpp | 14 +- src/atom.h | 5 +- src/atom_vec_rheo_thermal.cpp | 200 ++++++++++++ src/atom_vec_rheo_thermal.h | 46 +++ src/compute_rheo_property_atom.cpp | 411 ++++++++++++++++++++++++ src/compute_rheo_property_atom.h | 71 ++++ 27 files changed, 1443 insertions(+), 449 deletions(-) create mode 100644 src/RHEO/atom_vec_rheo_thermal.cpp create mode 100644 src/RHEO/atom_vec_rheo_thermal.h create mode 100644 src/atom_vec_rheo_thermal.cpp create mode 100644 src/atom_vec_rheo_thermal.h create mode 100644 src/compute_rheo_property_atom.cpp create mode 100644 src/compute_rheo_property_atom.h diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp index de2e2f77ad..ea9e2a3c10 100644 --- a/src/RHEO/atom_vec_rheo.cpp +++ b/src/RHEO/atom_vec_rheo.cpp @@ -33,15 +33,17 @@ AtomVecRHEO::AtomVecRHEO(LAMMPS *lmp) : AtomVec(lmp) forceclearflag = 1; atom->status_flag = 1; + atom->pressure_flag = 1; atom->rho_flag = 1; + atom->viscosity_flag = 1; // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings // order of fields in a string does not matter // except: fields_data_atom & fields_data_vel must match data file - fields_grow = {"status", "rho", "drho"}; - fields_copy = {"status", "rho", "drho"}; + fields_grow = {"status", "rho", "drho", "pressure", "viscosity"}; + fields_copy = {"status", "rho", "drho", "pressure", "viscosity"}; fields_comm = {"status", "rho"}; fields_comm_vel = {"status", "rho"}; fields_reverse = {"drho"}; @@ -49,7 +51,7 @@ AtomVecRHEO::AtomVecRHEO(LAMMPS *lmp) : AtomVec(lmp) fields_border_vel = {"status", "rho"}; fields_exchange = {"status", "rho"}; fields_restart = {"status", "rho"}; - fields_create = {"status", "rho", "drho"}; + fields_create = {"status", "rho", "drho", "pressure", "viscosity"}; fields_data_atom = {"id", "type", "status", "rho", "x"}; fields_data_vel = {"id", "v"}; @@ -64,8 +66,10 @@ AtomVecRHEO::AtomVecRHEO(LAMMPS *lmp) : AtomVec(lmp) void AtomVecRHEO::grow_pointers() { status = atom->status; + pressure = atom->pressure; rho = atom->rho; drho = atom->drho; + viscosity = atom->viscosity; } /* ---------------------------------------------------------------------- @@ -86,6 +90,8 @@ void AtomVecRHEO::force_clear(int n, size_t nbytes) void AtomVecRHEO::data_atom_post(int ilocal) { drho[ilocal] = 0.0; + pressure[ilocal] = 0.0; + viscosity[ilocal] = 0.0; } /* ---------------------------------------------------------------------- @@ -96,8 +102,10 @@ void AtomVecRHEO::data_atom_post(int ilocal) int AtomVecRHEO::property_atom(const std::string &name) { if (name == "status") return 0; - if (name == "rho") return 1; - if (name == "drho") return 2; + if (name == "pressure") return 1; + if (name == "rho") return 2; + if (name == "drho") return 3; + if (name == "viscosity") return 4; return -1; } @@ -123,12 +131,20 @@ void AtomVecRHEO::pack_property_atom(int index, double *buf, int nvalues, int gr } else if (index == 1) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) - buf[n] = rho[i]; + buf[n] = pressure[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 2) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = rho[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 3) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = drho[i]; @@ -136,5 +152,13 @@ void AtomVecRHEO::pack_property_atom(int index, double *buf, int nvalues, int gr buf[n] = 0.0; n += nvalues; } + } else if (index == 4) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = viscosity[i]; + else + buf[n] = 0.0; + n += nvalues; + } } } diff --git a/src/RHEO/atom_vec_rheo.h b/src/RHEO/atom_vec_rheo.h index bdd617a01d..68cc224ba5 100644 --- a/src/RHEO/atom_vec_rheo.h +++ b/src/RHEO/atom_vec_rheo.h @@ -36,7 +36,7 @@ class AtomVecRHEO : virtual public AtomVec { private: int *status; - double *rho, *drho; + double *pressure, *rho, *drho, *viscosity; }; } // namespace LAMMPS_NS diff --git a/src/RHEO/atom_vec_rheo_thermal.cpp b/src/RHEO/atom_vec_rheo_thermal.cpp new file mode 100644 index 0000000000..de0c7fa5d7 --- /dev/null +++ b/src/RHEO/atom_vec_rheo_thermal.cpp @@ -0,0 +1,200 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + +#include "atom_vec_rheo_thermal.h" + +#include "atom.h" + +#include + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) +{ + molecular = Atom::ATOMIC; + mass_type = PER_TYPE; + forceclearflag = 1; + + atom->status_flag = 1; + atom->conductivity_flag = 1; + atom->temperature_flag = 1; + atom->heatflow_flag = 1; + atom->pressure_flag = 1; + atom->rho_flag = 1; + atom->viscosity_flag = 1; + + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file + + fields_grow = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_copy = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_comm = {"status", "rho", "temperature"}; + fields_comm_vel = {"status", "rho", "temperature"}; + fields_reverse = {"drho", "heatflow"}; + fields_border = {"status", "rho", "temperature"}; + fields_border_vel = {"status", "rho", "temperature"}; + fields_exchange = {"status", "rho", "temperature"}; + fields_restart = {"status", "rho", "temperature"}; + fields_create = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_data_atom = {"id", "type", "status", "rho", "temperature", "x"}; + fields_data_vel = {"id", "v"}; + + setup_fields(); +} + +/* ---------------------------------------------------------------------- + set local copies of all grow ptrs used by this class, except defaults + needed in replicate when 2 atom classes exist and it calls pack_restart() +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::grow_pointers() +{ + status = atom->status; + conductivity = atom->conductivity; + temperature = atom->temperature; + heatflow = atom->heatflow; + pressure = atom->pressure; + rho = atom->rho; + drho = atom->drho; + viscosity = atom->viscosity; +} + +/* ---------------------------------------------------------------------- + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::force_clear(int n, size_t nbytes) +{ + memset(&drho[n], 0, nbytes); + memset(&heatflow[n], 0, nbytes); +} + +/* ---------------------------------------------------------------------- + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::data_atom_post(int ilocal) +{ + drho[ilocal] = 0.0; + heatflow[ilocal] = 0.0; + pressure[ilocal] = 0.0; + viscosity[ilocal] = 0.0; + conductivity[ilocal] = 0.0; +} + +/* ---------------------------------------------------------------------- + assign an index to named atom property and return index + return -1 if name is unknown to this atom style +------------------------------------------------------------------------- */ + +int AtomVecRHEOThermal::property_atom(const std::string &name) +{ + if (name == "status") return 0; + if (name == "rho") return 1; + if (name == "drho") return 2; + if (name == "temperature") return 3; + if (name == "heatflow") return 4; + if (name == "conductivity") return 5; + if (name == "pressure") return 6; + if (name == "viscosity") return 7; + return -1; +} + +/* ---------------------------------------------------------------------- + pack per-atom data into buf for ComputePropertyAtom + index maps to data specific to this atom style +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::pack_property_atom(int index, double *buf, int nvalues, int groupbit) +{ + int *mask = atom->mask; + int nlocal = atom->nlocal; + int n = 0; + + if (index == 0) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = status[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 1) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = rho[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 2) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = drho[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 3) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = temperature[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 4) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = heatflow[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 5) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = conductivity[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 6) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = pressure[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 7) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = viscosity[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } +} diff --git a/src/RHEO/atom_vec_rheo_thermal.h b/src/RHEO/atom_vec_rheo_thermal.h new file mode 100644 index 0000000000..27c6c3c9b5 --- /dev/null +++ b/src/RHEO/atom_vec_rheo_thermal.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef ATOM_CLASS +// clang-format off +AtomStyle(rheo/thermal,AtomVecRHEOThermal); +// clang-format on +#else + +#ifndef LMP_ATOM_VEC_RHEO_THERMAL_H +#define LMP_ATOM_VEC_RHEO_THERMAL_H + +#include "atom_vec.h" + +namespace LAMMPS_NS { + +class AtomVecRHEOThermal : virtual public AtomVec { + public: + AtomVecRHEOThermal(class LAMMPS *); + + void grow_pointers() override; + void force_clear(int, size_t) override; + void data_atom_post(int) override; + int property_atom(const std::string &) override; + void pack_property_atom(int, double *, int, int) override; + + private: + int *status; + double *conductivity, *temperature, *heatflow; + double *pressure, *rho, *drho, *viscosity; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 606cec7dfc..b71fb08d78 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -84,69 +84,34 @@ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : } comm_forward = ncomm_grad; + + nmax_store = 0; + grow_arrays(atom->nmax); + } /* ---------------------------------------------------------------------- */ ComputeRHEOGrad::~ComputeRHEOGrad() { - int dim = domain->dimension; - int tmp1, tmp2, index; - - index = atom->find_custom("rheo_grad_v", tmp1, tmp2); - if (index != 1) atom->remove_custom(index, 1, dim * dim); - index = atom->find_custom("rheo_grad_rho", tmp1, tmp2); - if (index != 1) atom->remove_custom(index, 1, dim); - index = atom->find_custom("rheo_grad_t", tmp1, tmp2); - if (index != 1) atom->remove_custom(index, 1, dim); - index = atom->find_custom("rheo_grad_eta", tmp1, tmp2); - if (index != 1) atom->remove_custom(index, 1, dim); + memory->destroy(gradv); + memory->destroy(gradr); + memory->destroy(gradt); + memory->destroy(gradn); } /* ---------------------------------------------------------------------- */ void ComputeRHEOGrad::init() { - neighbor->add_request(this, NeighConst::REQ_DEFAULT); - cut = fix_rheo->cut; cutsq = cut * cut; rho0 = fix_rheo->rho0; + interface_flag = fix_rheo->interface_flag; compute_kernel = fix_rheo->compute_kernel; compute_interface = fix_rheo->compute_interface; - int tmp1, tmp2; - index_visc = atom->find_custom("rheo_viscosity", tmp1, tmp2); - - // Create coordination array if it doesn't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - - int index; - int dim = domain->dimension; - if (velocity_flag) { - index = atom->add_custom("rheo_grad_v", 1, dim * dim); - gradv = atom->darray[index]; - } - - if (rho_flag) { - index = atom->add_custom("rheo_grad_rho", 1, dim); - gradr = atom->darray[index]; - } - - if (temperature_flag) { - index= atom->add_custom("rheo_grad_temp", 1, dim); - gradt = atom->darray[index]; - } - - if (eta_flag) { - index = atom->add_custom("rheo_grad_eta", 1, dim); - gradn = atom->darray[index]; - } - - nmax_store = 0; - grow_arrays(atom->nmax); + neighbor->add_request(this, NeighConst::REQ_DEFAULT); } /* ---------------------------------------------------------------------- */ @@ -175,7 +140,7 @@ void ComputeRHEOGrad::compute_peratom() double **v = atom->v; double *rho = atom->rho; double *temperature = atom->temperature; - double *viscosity = atom->dvector[index_visc]; + double *viscosity = atom->viscosity; int *status = atom->status; int *type = atom->type; double *mass = atom->mass; @@ -240,15 +205,17 @@ void ComputeRHEOGrad::compute_peratom() vj[2] = v[j][2]; // Add corrections for walls - if ((status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { - compute_interface->correct_v(vi, vj, i, j); - rhoj = compute_interface->correct_rho(j, i); - } else if (!(status[i] & STATUS_FLUID) && (status[j] & STATUS_FLUID)) { - compute_interface->correct_v(vj, vi, j, i); - rhoi = compute_interface->correct_rho(i, j); - } else if (!(status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { - rhoi = rho0; - rhoj = rho0; + if (interface_flag) { + if ((status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { + compute_interface->correct_v(vi, vj, i, j); + rhoj = compute_interface->correct_rho(j, i); + } else if (!(status[i] & STATUS_FLUID) && (status[j] & STATUS_FLUID)) { + compute_interface->correct_v(vj, vi, j, i); + rhoi = compute_interface->correct_rho(i, j); + } else if (!(status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { + rhoi = rho0; + rhoj = rho0; + } } Voli = mass[itype] / rhoi; @@ -481,16 +448,16 @@ void ComputeRHEOGrad::grow_arrays(int nmax) { int dim = domain->dimension; if (velocity_flag) - memory->grow(gradv, nmax, dim * dim, "atom:rheo_grad_v"); + memory->grow(gradv, nmax, dim * dim, "rheo:grad_v"); if (rho_flag) - memory->grow(gradr, nmax, dim, "atom:rheo_grad_rho"); + memory->grow(gradr, nmax, dim, "rheo:grad_rho"); if (temperature_flag) - memory->grow(gradt, nmax, dim, "atom:rheo_grad_temp"); + memory->grow(gradt, nmax, dim, "rheo:grad_temp"); if (eta_flag) - memory->grow(gradn, nmax, dim, "atom:rheo_grad_eta"); + memory->grow(gradn, nmax, dim, "rheo:grad_eta"); nmax_store = nmax; } diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 8c7962a978..af4fecdcfb 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -46,14 +46,14 @@ class ComputeRHEOGrad : public Compute { private: int comm_stage, ncomm_grad, ncomm_field, nmax_store; - int index_visc; double cut, cutsq, rho0; - class NeighList *list; + + int velocity_flag, temperature_flag, rho_flag, eta_flag; + int interface_flag; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; - - int velocity_flag, temperature_flag, rho_flag, eta_flag; + class NeighList *list; void grow_arrays(int); }; diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 72dcdc17d7..a3624f9663 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -46,24 +46,35 @@ ComputeRHEOInterface::ComputeRHEOInterface(LAMMPS *lmp, int narg, char **arg) : { if (narg != 3) error->all(FLERR,"Illegal compute rheo/interface command"); - nmax_store = 0; - comm_forward = 3; comm_reverse = 4; + + nmax_store = atom->nmax; + memory->create(chi, nmax_store, "rheo:chi"); + memory->create(norm, nmax_store, "rheo/interface:norm"); + memory->create(normwf, nmax_store, "rheo/interface:normwf"); + + // For fp_store, create an instance of fix property atom + // Need restarts + exchanging with neighbors since it needs to persist + // between timesteps (fix property atom will handle callbacks) + + int tmp1, tmp2; + int index = atom->find_custom("fp_store", tmp1, tmp2); + if (index == -1) { + id_fix_pa = utils::strdup(id + std::string("_fix_property_atom")); + modify->add_fix(fmt::format("{} all property/atom d2_fp_store 3", id_fix_pa)); + index = atom->find_custom("fp_store", tmp1, tmp2); + } + fp_store = atom->darray[index]; } /* ---------------------------------------------------------------------- */ ComputeRHEOInterface::~ComputeRHEOInterface() { - // Remove custom property if it exists - int tmp1, tmp2, index; - index = atom->find_custom("rheo_chi", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - if (id_fix_pa && modify->nfix) modify->delete_fix(id_fix_pa); delete[] id_fix_pa; - + memory->destroy(chi); memory->destroy(norm); memory->destroy(normwf); } @@ -80,37 +91,6 @@ void ComputeRHEOInterface::init() cutsq = cut * cut; wall_max = sqrt(3.0) / 12.0 * cut; - // Create chi array if it doesn't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - - int tmp1, tmp2; - int nmax = atom->nmax; - int index = atom->find_custom("rheo_chi", tmp1, tmp2); - if (index == -1) { - index = atom->add_custom("rheo_chi", 1, 0); - memory->destroy(norm); - memory->destroy(normwf); - memory->create(norm, nmax, "rheo/interface:norm"); - memory->create(normwf, nmax, "rheo/interface:normwf"); - nmax_store = nmax; - } - chi = atom->dvector[index]; - - // For fp_store, go ahead and create an instance of fix property atom - // Need restarts + exchanging with neighbors since it needs to persist - // between timesteps (fix property atom will handle callbacks) - - index = atom->find_custom("fp_store", tmp1, tmp2); - if (index == -1) { - id_fix_pa = utils::strdup(id + std::string("_fix_property_atom")); - modify->add_fix(fmt::format("{} all property/atom d2_fp_store 3", id_fix_pa)); - index = atom->find_custom("fp_store", tmp1, tmp2); - } - fp_store = atom->darray[index]; - - // need an occasional half neighbor list neighbor->add_request(this, NeighConst::REQ_DEFAULT); } @@ -145,11 +125,9 @@ void ComputeRHEOInterface::compute_peratom() if (atom->nmax > nmax_store) { nmax_store = atom->nmax; - memory->destroy(norm); - memory->destroy(normwf); - memory->create(norm, nmax_store, "rheo/interface:norm"); - memory->create(normwf, nmax_store, "rheo/interface:normwf"); - memory->grow(chi, nmax_store, "rheo/interface:chi"); + memory->grow(norm, nmax_store, "rheo/interface:norm"); + memory->grow(normwf, nmax_store, "rheo/interface:normwf"); + memory->grow(chi, nmax_store, "rheo:chi"); } for (i = 0; i < nall; i++) { diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index b7ad1c9b3f..9cfa86df7e 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -68,7 +68,6 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : correction_order = 2; } - solid_flag = 0; dim = domain->dimension; comm_forward = 1; @@ -93,11 +92,7 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : ComputeRHEOKernel::~ComputeRHEOKernel() { - // Remove custom property if it exists - int tmp1, tmp2, index; - index = atom->find_custom("rheo_coordination", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 0, 0); - + memory->destroy(coordination); memory->destroy(C); memory->destroy(C0); } @@ -112,11 +107,8 @@ void ComputeRHEOKernel::init() if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use compute rheo/kernel"); fix_rheo = dynamic_cast(fixes[0]); - int icompute = modify->find_compute("rheo_interface"); - if (icompute != -1) { - compute_interface = ((ComputeRHEOInterface *) modify->compute[icompute]); - solid_flag = 1; - } + interface_flag = fix_rheo->interface_flag; + compute_interface = fix_rheo->compute_interface; zmin = fix_rheo->zmin_kernel; h = fix_rheo->h; @@ -133,22 +125,8 @@ void ComputeRHEOKernel::init() pre_wp = pre_w * 3.0 * hinv; } - // Create coordination array if it doesn't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - - int tmp1, tmp2; - int nmax = atom->nmax; - int index = atom->find_custom("rheo_coordination", tmp1, tmp2); - if (index == -1) { - index = atom->add_custom("rheo_coordination", 0, 0); - nmax_store = nmax; - } - coordination = atom->ivector[index]; - - // Create local arrays for kernel arrays, I can't foresee a reason to print - + nmax_store = atom->nmax; + memory->create(coordination, nmax_store, "rheo:coordination"); if (kernel_style == CRK0) { memory->create(C0, nmax_store, "rheo/kernel:C0"); } else if (kernel_style == CRK1) { @@ -499,7 +477,7 @@ void ComputeRHEOKernel::compute_peratom() if (kernel_style == QUINTIC) return; int i, j, ii, jj, inum, jnum, itype, g, a, b, gsl_error; - double xtmp, ytmp, ztmp, r, rsq, w, vj; + double xtmp, ytmp, ztmp, r, rsq, w, vj, rhoj; double dx[3]; gsl_matrix_view gM; @@ -549,10 +527,12 @@ void ComputeRHEOKernel::compute_peratom() if (rsq < hsq) { r = sqrt(rsq); w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); - if (!(status[j] & STATUS_FLUID) && solid_flag) { - vj = mass[type[j]] / compute_interface->correct_rho(j,i); - } else vj = mass[type[j]] / rho[j]; + rhoj = rho[j]; + if (interface_flag) + if (!(status[j] & STATUS_FLUID)) + rhoj = compute_interface->correct_rho(j,i); + vj = mass[type[j]] / rhoj; M += w * vj; } } @@ -596,11 +576,12 @@ void ComputeRHEOKernel::compute_peratom() r = sqrt(rsq); w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); - if (solid_flag) + rhoj = rho[j]; + if (interface_flag) if (!(status[j] & STATUS_FLUID)) - vj = mass[type[j]]/compute_interface->correct_rho(j,i); - else - vj = mass[type[j]]/rho[j]; + rhoj = compute_interface->correct_rho(j,i); + + vj = mass[type[j]] / rhoj; //Populate the H-vector of polynomials (2D) if (dim == 2) { @@ -759,7 +740,7 @@ void ComputeRHEOKernel::compute_coordination() void ComputeRHEOKernel::grow_arrays(int nmax) { - memory->grow(coordination, nmax, "atom:rheo_coordination"); + memory->grow(coordination, nmax, "rheo:coordination"); if (kernel_style == CRK0) { memory->grow(C0, nmax, "rheo/kernel:C0"); diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 1842406977..5324199f76 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -49,7 +49,7 @@ class ComputeRHEOKernel : public Compute { private: int comm_stage, comm_forward_save; - int solid_flag; + int interface_flag; int gsl_error_flag; std::unordered_set gsl_error_tags; diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index a23ba5a639..7682552abe 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -21,20 +21,29 @@ #include "atom.h" #include "atom_vec.h" +#include "compute_rheo_interface.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_surface.h" +#include "compute_rheo_vshift.h" #include "error.h" +#include "fix_rheo.h" +#include "fix_rheo_thermal.h" #include "memory.h" +#include "modify.h" #include "update.h" #include #include using namespace LAMMPS_NS; +using namespace RHEO_NS; /* ---------------------------------------------------------------------- */ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), - index(nullptr), colindex(nullptr), pack_choice(nullptr) + Compute(lmp, narg, arg), fix_rheo(nullptr), fix_thermal(nullptr), compute_interface(nullptr), + compute_kernel(nullptr), compute_surface(nullptr), compute_vshift(nullptr), + index(nullptr), pack_choice(nullptr) { if (narg < 4) utils::missing_cmd_args(FLERR, "compute property/atom", error); @@ -43,31 +52,66 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; + thermal_flag, interface_flag, surface_flag, shift_flag = 0; + // parse input values // customize a new keyword by adding to if statement pack_choice = new FnPtrPack[nvalues]; + index = new int[nvalues]; int i; for (int iarg = 3; iarg < narg; iarg++) { i = iarg-3; - if (strcmp(arg[iarg],"id") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_id; - } else if (strcmp(arg[iarg],"mol") == 0) { - if (!atom->molecule_flag) - error->all(FLERR,"Compute property/atom {} is not available", arg[iarg]); - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_molecule; - } else if (strcmp(arg[iarg],"proc") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_proc; - } else if (strcmp(arg[iarg],"type") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_type; - } else if (strcmp(arg[iarg],"mass") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_mass; - - + if (strcmp(arg[iarg],"phase") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_phase; + } else if (strcmp(arg[iarg],"chi") == 0) { + interface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_chi; + } else if (strcmp(arg[iarg],"surface") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface; + } else if (strcmp(arg[iarg],"surface/r") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_r; + } else if (strcmp(arg[iarg],"surface/divr") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_divr; + } else if (strcmp(arg[iarg],"surface/nx") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nx; + } else if (strcmp(arg[iarg],"surface/ny") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_ny; + } else if (strcmp(arg[iarg],"surface/nz") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nz; + } else if (strcmp(arg[iarg],"coordination") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_coordination; + } else if (strcmp(arg[iarg],"cv") == 0) { + thermal_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; + } else if (strcmp(arg[iarg],"shift/vx") == 0) { + shift_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vx; + } else if (strcmp(arg[iarg],"shift/vy") == 0) { + shift_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vy; + } else if (strcmp(arg[iarg],"shift/vz") == 0) { + shift_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vz; } else { - error->all(FLERR,"Invalid keyword {} for compute rheo/property/atom command ", arg[iarg]); + index[i] = atom->avec->property_atom(arg[iarg]); + if (index[i] < 0) + error->all(FLERR, + "Invalid keyword {} for atom style {} in compute rheo/property/atom command ", + atom->get_style(), arg[iarg]); + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; + + if (strcmp(arg[iarg],"temperature") == 0) thermal_flag = 1; + if (strcmp(arg[iarg],"heatflow") == 0) thermal_flag = 1; + if (strcmp(arg[iarg],"conductivity") == 0) thermal_flag = 1; } } @@ -79,12 +123,41 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() { delete[] pack_choice; + delete[] index; memory->destroy(vector_atom); memory->destroy(array_atom); } /* ---------------------------------------------------------------------- */ +void ComputeRHEOPropertyAtom::init() +{ + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); + fix_rheo = dynamic_cast(fixes[0]); + + if (interface_flag && !(fix_rheo->interface_flag)) + error->all(FLERR, "Cannot request interfacial property without corresponding option in fix rheo"); + if (surface_flag && !(fix_rheo->surface_flag)) + error->all(FLERR, "Cannot request surface property without corresponding option in fix rheo"); + if (shift_flag && !(fix_rheo->shift_flag)) + error->all(FLERR, "Cannot request velocity shifting property without corresponding option in fix rheo"); + if (thermal_flag && !(fix_rheo->thermal_flag)) + error->all(FLERR, "Cannot request thermal property without fix rheo/thermal"); + + compute_interface = fix_rheo->compute_interface; + compute_kernel = fix_rheo->compute_kernel; + compute_surface = fix_rheo->compute_surface; + compute_vshift = fix_rheo->compute_vshift; + + if (thermal_flag) { + fixes = modify->get_fix_by_style("rheo/thermal"); + fix_thermal = dynamic_cast(fixes[0]); + } +} + +/* ---------------------------------------------------------------------- */ + void ComputeRHEOPropertyAtom::compute_peratom() { invoked_peratom = update->ntimestep; @@ -133,14 +206,16 @@ double ComputeRHEOPropertyAtom::memory_usage() /* ---------------------------------------------------------------------- */ -void ComputeRHEOPropertyAtom::pack_rho(int n) +void ComputeRHEOPropertyAtom::pack_phase(int n) { - double *rho = atom->rho; + int *status = atom->status; int *mask = atom->mask; int nlocal = atom->nlocal; + int inverse_mask = ~PHASEMASK; + for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = rho[i]; + if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); else buf[n] = 0.0; n += nvalues; } @@ -148,15 +223,189 @@ void ComputeRHEOPropertyAtom::pack_rho(int n) /* ---------------------------------------------------------------------- */ -void ComputeRHEOPropertyAtom::pack_status(int n) +void ComputeRHEOPropertyAtom::pack_chi(int n) +{ + double *chi = compute_interface->chi; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = chi[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface(int n) { int *status = atom->status; int *mask = atom->mask; int nlocal = atom->nlocal; + int inverse_mask = ~SURFACEMASK; + for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = status[i]; + if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); else buf[n] = 0.0; n += nvalues; } } + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_r(int n) +{ + double *rsurface = compute_surface->rsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = rsurface[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_divr(int n) +{ + double *divr = compute_surface->divr; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = divr[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_nx(int n) +{ + double **nsurface = compute_surface->nsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = nsurface[i][0]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_ny(int n) +{ + double **nsurface = compute_surface->nsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = nsurface[i][1]; + else buf[n] = 0.0; + n += nvalues; + } +} + + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_nz(int n) +{ + double **nsurface = compute_surface->nsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = nsurface[i][2]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_coordination(int n) +{ + int *coordination = compute_kernel->coordination; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = coordination[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_cv(int n) +{ + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = fix_thermal->calc_cv(i); + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_shift_vx(int n) +{ + double **vshift = compute_vshift->vshift; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = vshift[i][0]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_shift_vy(int n) +{ + double **vshift = compute_vshift->vshift; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = vshift[i][1]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_shift_vz(int n) +{ + double **vshift = compute_vshift->vshift; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = vshift[i][2]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_atom_style(int n) +{ + atom->avec->pack_property_atom(index[n],&buf[n],nvalues,groupbit); +} diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index 26ca004da0..accb7e9156 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -28,37 +28,40 @@ class ComputeRHEOPropertyAtom : public Compute { public: ComputeRHEOPropertyAtom(class LAMMPS *, int, char **); ~ComputeRHEOPropertyAtom() override; + void init() override; void compute_peratom() override; double memory_usage() override; private: - int nvalues; - int nmax; + int nvalues, nmax; + int thermal_flag, interface_flag, surface_flag, shift_flag; + int *index; double *buf; typedef void (ComputeRHEOPropertyAtom::*FnPtrPack)(int); FnPtrPack *pack_choice; // ptrs to pack functions - void pack_rho(int); - void pack_drho(int); - void pack_temperature(int); - void pack_heatflow(int); - void pack_status(int); void pack_phase(int); + void pack_chi(int); void pack_surface(int); - void pack_r_surface(int); - void pack_divr_surface(int); - void pack_nx_surface(int); - void pack_ny_surface(int); - void pack_nz_surface(int); + void pack_surface_r(int); + void pack_surface_divr(int); + void pack_surface_nx(int); + void pack_surface_ny(int); + void pack_surface_nz(int); void pack_coordination(int); - void pack_viscosity(int); - void pack_pressure(int); - void pack_conductivity(int); void pack_cv(int); - void pack_vx_shift(int); - void pack_vy_shift(int); - void pack_vz_shift(int); + void pack_shift_vx(int); + void pack_shift_vy(int); + void pack_shift_vz(int); + void pack_atom_style(int); + + class FixRHEO *fix_rheo; + class FixRHEOThermal *fix_thermal; + class ComputeRHEOInterface *compute_interface; + class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOSurface *compute_surface; + class ComputeRHEOVShift *compute_vshift; }; diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 58a3e3b9c4..220f8beb6d 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -36,13 +36,13 @@ class ComputeRHEOSurface : public Compute { int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; - double **nsurface, *rsurface; + double **nsurface, *rsurface, *divr; class FixRHEO *fix_rheo; private: double cut, cutsq, rho0, threshold_divr; int surface_style, nmax_store, threshold_z; - double **B, **gradC, *divr; + double **B, **gradC; int threshold_style, comm_stage; class NeighList *list; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 440bfc7fc7..3d3914436e 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -22,6 +22,7 @@ #include "comm.h" #include "compute_rheo_interface.h" #include "compute_rheo_kernel.h" +#include "compute_rheo_surface.h" #include "domain.h" #include "error.h" #include "fix_rheo.h" @@ -38,36 +39,22 @@ using namespace RHEO_NS; ComputeRHEOVShift::ComputeRHEOVShift(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), list(nullptr), vshift(nullptr), fix_rheo(nullptr), - compute_kernel(nullptr), compute_interface(nullptr) + compute_kernel(nullptr), compute_interface(nullptr), compute_surface(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute RHEO/VShift command"); comm_reverse = 3; surface_flag = 0; - // Create vshift array if it doesn't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - - int tmp1, tmp2; - int index = atom->find_custom("rheo_vshift", tmp1, tmp2); - if (index == -1) { - index = atom->add_custom("rheo_vshift", 1, 3); - nmax_store = atom->nmax; - } - vshift = atom->darray[index]; + nmax_store = atom->nmax; + memory->create(vshift, nmax_store, 3, "rheo:vshift"); } /* ---------------------------------------------------------------------- */ ComputeRHEOVShift::~ComputeRHEOVShift() { - // Remove custom property if it exists - int tmp1, tmp2, index; - index = atom->find_custom("rheo_vshift", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 3); - + memory->destroy(vshift); } /* ---------------------------------------------------------------------- */ @@ -76,12 +63,12 @@ void ComputeRHEOVShift::init() { neighbor->add_request(this, NeighConst::REQ_DEFAULT); - surface_flag = 0; - if (fix_rheo->surface_flag) - surface_flag = 1; + surface_flag = fix_rheo->surface_flag; + interface_flag = fix_rheo->interface_flag; compute_kernel = fix_rheo->compute_kernel; compute_interface = fix_rheo->compute_interface; + compute_surface = fix_rheo->compute_surface; cut = fix_rheo->cut; cutsq = cut * cut; @@ -128,7 +115,7 @@ void ComputeRHEOVShift::compute_peratom() firstneigh = list->firstneigh; if (nmax_store < atom->nmax) { - memory->grow(vshift, atom->nmax, 3, "atom:rheo_vshift"); + memory->grow(vshift, atom->nmax, 3, "rheo:vshift"); nmax_store = atom->nmax; } @@ -176,15 +163,17 @@ void ComputeRHEOVShift::compute_peratom() rhoj = rho[j]; // Add corrections for walls - if (fluidi && (!fluidj)) { - compute_interface->correct_v(vi, vj, i, j); - rhoj = compute_interface->correct_rho(j,i); - } else if ((!fluidi) && fluidj) { - compute_interface->correct_v(vj, vi, j, i); - rhoi = compute_interface->correct_rho(i,j); - } else if ((!fluidi) && (!fluidj)) { - rhoi = 1.0; - rhoj = 1.0; + if (interface_flag) { + if (fluidi && (!fluidj)) { + compute_interface->correct_v(vi, vj, i, j); + rhoj = compute_interface->correct_rho(j,i); + } else if ((!fluidi) && fluidj) { + compute_interface->correct_v(vj, vi, j, i); + rhoi = compute_interface->correct_rho(i,j); + } else if ((!fluidi) && (!fluidj)) { + rhoi = 1.0; + rhoj = 1.0; + } } voli = imass / rhoi; @@ -227,30 +216,28 @@ void ComputeRHEOVShift::correct_surfaces() { if (!surface_flag) return; + int i, a, b; + int *status = atom->status; int *mask = atom->mask; - int nlocal = atom->nlocal; - int i, a, b; - int dim = domain->dimension; + double **nsurface = compute_surface->nsurface; - int tmp1, tmp2; - int index_nsurf = atom->find_custom("rheo_nsurf", tmp1, tmp2); - if (index_nsurf == -1) error->all(FLERR, "Cannot find rheo nsurf"); - double **nsurf = atom->darray[index_nsurf]; + int nlocal = atom->nlocal; + int dim = domain->dimension; double nx,ny,nz,vx,vy,vz; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if ((status[i] & STATUS_SURFACE) || (status[i] & STATUS_LAYER)) { - nx = nsurf[i][0]; - ny = nsurf[i][1]; + nx = nsurface[i][0]; + ny = nsurface[i][1]; vx = vshift[i][0]; vy = vshift[i][1]; vz = vshift[i][2]; vshift[i][0] = (1 - nx * nx) * vx - nx * ny * vy; vshift[i][1] = (1 - ny * ny) * vy - nx * ny * vx; if (dim > 2) { - nz = nsurf[i][2]; + nz = nsurface[i][2]; vshift[i][0] -= nx * nz * vz; vshift[i][1] -= ny * nz * vz; vshift[i][2] = (1 - nz * nz) * vz - nz * ny * vy - nx * nz * vx; diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h index 8611e177d1..9d3a0166d6 100644 --- a/src/RHEO/compute_rheo_vshift.h +++ b/src/RHEO/compute_rheo_vshift.h @@ -42,11 +42,12 @@ class ComputeRHEOVShift : public Compute { private: int nmax_store; double dtv, cut, cutsq, cutthird; - int surface_flag; + int surface_flag, interface_flag; class NeighList *list; - class ComputeRHEOInterface *compute_interface ; + class ComputeRHEOInterface *compute_interface; class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOSurface *compute_surface; }; } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index ff804fe007..ac870affd5 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -60,8 +60,12 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : if (igroup != 0) error->all(FLERR,"fix rheo command requires group all"); + if (atom->pressure_flag != 1) + error->all(FLERR,"fix rheo command requires atom_style with pressure"); if (atom->rho_flag != 1) error->all(FLERR,"fix rheo command requires atom_style with density"); + if (atom->viscosity_flag != 1) + error->all(FLERR,"fix rheo command requires atom_style with viscosity"); if (atom->status_flag != 1) error->all(FLERR,"fix rheo command requires atom_style with status"); diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 75edf42572..45557794cd 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -38,7 +38,7 @@ static constexpr double SEVENTH = 1.0 / 7.0; /* ---------------------------------------------------------------------- */ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fix_rheo(nullptr), pressure(nullptr) + Fix(lmp, narg, arg), fix_rheo(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 5df8c1c506..0d8909b908 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -40,7 +40,7 @@ enum {NONE, CONSTANT, TYPE}; FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), compute_vshift(nullptr), - Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), conductivity(nullptr) + Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -48,9 +48,6 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : cv_style = NONE; conductivity_style = NONE; - comm_forward = 1; - nmax_store = 0; - int ntypes = atom->ntypes; int iarg = 3; while (iarg < narg) { @@ -170,9 +167,11 @@ void FixRHEOThermal::init() dtf = 0.5 * update->dt * force->ftm2v; if (atom->temperature_flag != 1) - error->all(FLERR,"fix rheo/thermal command requires atoms store temperature property"); + error->all(FLERR,"fix rheo/thermal command requires atom property temperature"); if (atom->heatflow_flag != 1) - error->all(FLERR,"fix rheo/thermal command requires atoms store heatflow property"); + error->all(FLERR,"fix rheo/thermal command requires atom property heatflow"); + if (atom->conductivity_flag != 1) + error->all(FLERR,"fix rheo/thermal command requires atom property conductivity"); } /* ---------------------------------------------------------------------- */ @@ -181,34 +180,6 @@ void FixRHEOThermal::setup_pre_force(int /*vflag*/) { fix_rheo->thermal_fix_defined = 1; - // Identify whether this is the first/last instance of fix thermal - // First will grow arrays, last will communicate - first_flag = 0; - last_flag = 0; - - int i = 0; - auto fixlist = modify->get_fix_by_style("rheo/thermal"); - for (const auto &fix : fixlist) { - if (strcmp(fix->id, id) == 0) break; - i++; - } - - if (i == 0) first_flag = 1; - if ((i + 1) == fixlist.size()) last_flag = 1; - - // Create conductivity array if it doesn't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - - int tmp1, tmp2; - int index = atom->find_custom("rheo_conductivity", tmp1, tmp2); - if (index== -1) { - index = atom->add_custom("rheo_conductivity", 1, 0); - nmax_store = atom->nmax; - } - conductivity = atom->dvector[index]; - post_neighbor(); pre_force(0); } @@ -294,14 +265,10 @@ void FixRHEOThermal::post_neighbor() int i; int *type = atom->type; int *mask = atom->mask; + double *conductivity = atom->conductivity; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (first_flag && (nmax_store < atom->nmax)) { - memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); - nmax_store = atom->nmax; - } - if (conductivity_style == CONSTANT) { for (i = 0; i < nall; i++) if (mask[i] & groupbit) conductivity[i] = kappa; @@ -312,39 +279,11 @@ void FixRHEOThermal::post_neighbor() } /* ---------------------------------------------------------------------- - Update (and forward) evolving conductivity styles every timestep - Zero heat flow + In the future, update & forward evolving conductivity styles every timestep ------------------------------------------------------------------------- */ void FixRHEOThermal::pre_force(int /*vflag*/) { - // send updated temperatures to ghosts if first instance of fix - // then clear heatflow for next force calculation - double *heatflow = atom->heatflow; - if (first_flag) { - comm->forward_comm(this); - for (int i = 0; i < atom->nmax; i++) heatflow[i] = 0.0; - } - - // Not needed yet, when needed add stage check for (un)pack_forward_comm() methods - //int i; - //double *conductivity = atom->dvector[index_cond]; - //int *mask = atom->mask; - //int nlocal = atom->nlocal; - - //if (first_flag && (nmax_store < atom->nmax)) { - // memory->grow(conductivity, atom->nmax, "atom:rheo_conductivity"); - // nmax_store = atom->nmax; - //} - - //if (conductivity_style == TBD) { - // for (i = 0; i < nlocal; i++) { - // if (mask[i] & groupbit) { - // } - // } - //} - - //if (last_flag && comm_forward) comm->forward_comm(this); } /* ---------------------------------------------------------------------- */ @@ -387,69 +326,3 @@ double FixRHEOThermal::calc_cv(int i) return(cv_type[atom->type[i]]); } } - -/* ---------------------------------------------------------------------- */ - -int FixRHEOThermal::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) -{ - int i, j, m; - - double *temperature = atom->temperature; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = temperature[j]; - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOThermal::unpack_forward_comm(int n, int first, double *buf) -{ - int i, m, last; - - m = 0; - last = first + n; - - double *temperature = atom->temperature; - - for (i = first; i < last; i++) temperature[i] = buf[m++]; -} - -/* ---------------------------------------------------------------------- */ - -int FixRHEOThermal::pack_reverse_comm(int n, int first, double *buf) -{ - int m = 0; - int last = first + n; - double *heatflow = atom->heatflow; - - for (int i = first; i < last; i++) { - buf[m++] = heatflow[i]; - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOThermal::unpack_reverse_comm(int n, int *list, double *buf) -{ - int m = 0; - double *heatflow = atom->heatflow; - - for (int i = 0; i < n; i++) - heatflow[list[i]] += buf[m++]; -} - -/* ---------------------------------------------------------------------- */ - -double FixRHEOThermal::memory_usage() -{ - double bytes = 0.0; - bytes += (size_t) nmax_store * sizeof(double); - return bytes; -} diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index cf64c0b8d1..a27ad98a8c 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -37,29 +37,22 @@ class FixRHEOThermal : public Fix { void pre_force(int) override; void final_integrate() override; void reset_dt() override; - int pack_forward_comm(int, int *, double *, int, int *) override; - void unpack_forward_comm(int, int, double *) override; - int pack_reverse_comm(int, int, double *) override; - void unpack_reverse_comm(int, int *, double *) override; - double memory_usage() override; + double calc_cv(int); private: double *cv_type, cv; double *Tc_type, Tc; double *kappa_type, kappa; double dtf, dtv; - double *conductivity; int Tc_style; int cv_style; int conductivity_style; - int first_flag, last_flag; - int nmax_store; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; class ComputeRHEOVShift *compute_vshift; - double calc_cv(int); + void grow_array(int); }; } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index b15f488370..4d70ffaca3 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -37,14 +37,13 @@ enum {NONE, CONSTANT, TYPE, POWER}; /* ---------------------------------------------------------------------- */ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fix_rheo(nullptr), eta_type(nullptr), viscosity(nullptr), compute_grad(nullptr) + Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), eta_type(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); viscosity_style = NONE; comm_forward = 0; - nmax_store = 0; int ntypes = atom->ntypes; int iarg = 3; @@ -86,11 +85,6 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : FixRHEOViscosity::~FixRHEOViscosity() { - // Remove custom property if it exists - int tmp1, tmp2, index; - index = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - memory->destroy(eta_type); } @@ -121,9 +115,7 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) { fix_rheo->viscosity_fix_defined = 1; - // Identify whether this is the first/last instance of fix viscosity - // First will grow arrays, last will communicate - first_flag = 0; + // Identify whether this is the last instance of fix viscosity last_flag = 0; int i = 0; @@ -133,22 +125,8 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) i++; } - if (i == 0) first_flag = 1; if ((i + 1) == fixlist.size()) last_flag = 1; - // Create viscosity array if it doesn't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - - int tmp1, tmp2; - int index = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index == -1) { - index = atom->add_custom("rheo_viscosity", 1, 0); - nmax_store = atom->nmax; - } - viscosity = atom->dvector[index]; - post_neighbor(); pre_force(0); } @@ -163,14 +141,9 @@ void FixRHEOViscosity::post_neighbor() int *type = atom->type; int *mask = atom->mask; + double *viscosity = atom->viscosity; - int nlocal = atom->nlocal; - int nall = nlocal + atom->nghost; - - if (first_flag && (nmax_store < atom->nmax)) { - memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); - nmax_store = atom->nmax; - } + int nall = atom->nlocal + atom->nghost; if (viscosity_style == CONSTANT) { for (i = 0; i < nall; i++) @@ -191,16 +164,12 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) double tmp, gdot; int *mask = atom->mask; + double *viscosity = atom->viscosity; double **gradv = compute_grad->gradv; int nlocal = atom->nlocal; int dim = domain->dimension; - if (first_flag && (nmax_store < atom->nmax)) { - memory->grow(viscosity, atom->nmax, "atom:rheo_viscosity"); - nmax_store = atom->nmax; - } - if (viscosity_style == POWER) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -231,7 +200,8 @@ void FixRHEOViscosity::pre_force(int /*vflag*/) int FixRHEOViscosity::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { - int i,j,k,m; + int i, j, k, m; + double *viscosity = atom->viscosity; m = 0; for (i = 0; i < n; i++) { @@ -246,6 +216,7 @@ int FixRHEOViscosity::pack_forward_comm(int n, int *list, double *buf, void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; + double *viscosity = atom->viscosity; m = 0; last = first + n; @@ -253,12 +224,3 @@ void FixRHEOViscosity::unpack_forward_comm(int n, int first, double *buf) viscosity[i] = buf[m++]; } } - -/* ---------------------------------------------------------------------- */ - -double FixRHEOViscosity::memory_usage() -{ - double bytes = 0.0; - bytes += (size_t) nmax_store * sizeof(double); - return bytes; -} diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index 66df51601e..c681d18c00 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -35,15 +35,11 @@ class FixRHEOViscosity : public Fix { void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; - double memory_usage() override; private: double *eta_type, eta; double npow, K, gd0, tau0; - double *viscosity; - int viscosity_style; - int first_flag, last_flag; - int nmax_store; + int viscosity_style, last_flag; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index c61d613d82..03e859316f 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -99,6 +99,9 @@ void PairRHEO::compute(int eflag, int vflag) double *rho = atom->rho; double *mass = atom->mass; double *drho = atom->drho; + double *pressure = atom->pressure; + double *viscosity = atom->viscosity; + double *conductivity = atom->conductivity; double *temperature = atom->temperature; double *heatflow = atom->heatflow; double *special_lj = force->special_lj; @@ -112,22 +115,6 @@ void PairRHEO::compute(int eflag, int vflag) chi = compute_interface->chi; } - int tmp1, tmp2; - int index = atom->find_custom("rheo_viscosity", tmp1, tmp2); - if (index == -1) error->all(FLERR, "Cannot find rheo viscosity"); - double *viscosity = atom->dvector[index]; - - index = atom->find_custom("rheo_pressure", tmp1, tmp2); - if (index == -1) error->all(FLERR, "Cannot find rheo pressure"); - double *pressure = atom->dvector[index]; - - double *conductivity; - if (thermal_flag) { - index = atom->find_custom("rheo_conductivity", tmp1, tmp2); - if (index == -1) error->all(FLERR, "Cannot find rheo conductivity"); - conductivity = atom->dvector[index]; - } - inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; diff --git a/src/atom.cpp b/src/atom.cpp index 25023e0d49..cf8cb7468a 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -200,6 +200,9 @@ Atom::Atom(LAMMPS *_lmp) : Pointers(_lmp) // RHEO package status = nullptr; + conductivity = nullptr; + pressure = nullptr; + viscosity = nullptr; // SPH package @@ -533,6 +536,9 @@ void Atom::peratom_create() // RHEO package add_peratom("status",&status,INT,0); + add_peratom("conductivity",&conductivity,DOUBLE,0); + add_peratom("pressure",&pressure,DOUBLE,0); + add_peratom("viscosity",&viscosity,DOUBLE,0); // SPH package @@ -639,7 +645,7 @@ void Atom::set_atomflag_defaults() temperature_flag = heatflow_flag = 0; vfrac_flag = spin_flag = eradius_flag = ervel_flag = erforce_flag = 0; cs_flag = csforce_flag = vforce_flag = ervelforce_flag = etag_flag = 0; - status_flag = 0; + status_flag = conductivity_flag = pressure_flag = viscosity_flag = 0; rho_flag = esph_flag = cv_flag = vest_flag = 0; dpd_flag = edpd_flag = tdpd_flag = 0; sp_flag = 0; @@ -2943,6 +2949,9 @@ void *Atom::extract(const char *name) // RHEO package if (strcmp(name,"status") == 0) return (void *) status; + if (strcmp(name,"conductivity") == 0) return (void *) conductivity; + if (strcmp(name,"pressure") == 0) return (void *) pressure; + if (strcmp(name,"viscosity") == 0) return (void *) viscosity; // SPH package @@ -3069,6 +3078,9 @@ int Atom::extract_datatype(const char *name) // RHEO package if (strcmp(name,"status") == 0) return LAMMPS_INT; + if (strcmp(name,"conductivity") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"pressure") == 0) return LAMMPS_DOUBLE; + if (strcmp(name,"viscosity") == 0) return LAMMPS_DOUBLE; // SPH package diff --git a/src/atom.h b/src/atom.h index 51665cb0bf..a8ced43b4d 100644 --- a/src/atom.h +++ b/src/atom.h @@ -158,6 +158,9 @@ class Atom : protected Pointers { // RHEO package int *status; + double *conductivity; + double *pressure; + double *viscosity; // SPH package @@ -194,7 +197,7 @@ class Atom : protected Pointers { int temperature_flag, heatflow_flag; int vfrac_flag, spin_flag, eradius_flag, ervel_flag, erforce_flag; int cs_flag, csforce_flag, vforce_flag, ervelforce_flag, etag_flag; - int status_flag; + int status_flag, conductivity_flag, pressure_flag, viscosity_flag; int rho_flag, esph_flag, cv_flag, vest_flag; int dpd_flag, edpd_flag, tdpd_flag; int mesont_flag; diff --git a/src/atom_vec_rheo_thermal.cpp b/src/atom_vec_rheo_thermal.cpp new file mode 100644 index 0000000000..de0c7fa5d7 --- /dev/null +++ b/src/atom_vec_rheo_thermal.cpp @@ -0,0 +1,200 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + +#include "atom_vec_rheo_thermal.h" + +#include "atom.h" + +#include + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) +{ + molecular = Atom::ATOMIC; + mass_type = PER_TYPE; + forceclearflag = 1; + + atom->status_flag = 1; + atom->conductivity_flag = 1; + atom->temperature_flag = 1; + atom->heatflow_flag = 1; + atom->pressure_flag = 1; + atom->rho_flag = 1; + atom->viscosity_flag = 1; + + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file + + fields_grow = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_copy = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_comm = {"status", "rho", "temperature"}; + fields_comm_vel = {"status", "rho", "temperature"}; + fields_reverse = {"drho", "heatflow"}; + fields_border = {"status", "rho", "temperature"}; + fields_border_vel = {"status", "rho", "temperature"}; + fields_exchange = {"status", "rho", "temperature"}; + fields_restart = {"status", "rho", "temperature"}; + fields_create = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_data_atom = {"id", "type", "status", "rho", "temperature", "x"}; + fields_data_vel = {"id", "v"}; + + setup_fields(); +} + +/* ---------------------------------------------------------------------- + set local copies of all grow ptrs used by this class, except defaults + needed in replicate when 2 atom classes exist and it calls pack_restart() +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::grow_pointers() +{ + status = atom->status; + conductivity = atom->conductivity; + temperature = atom->temperature; + heatflow = atom->heatflow; + pressure = atom->pressure; + rho = atom->rho; + drho = atom->drho; + viscosity = atom->viscosity; +} + +/* ---------------------------------------------------------------------- + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::force_clear(int n, size_t nbytes) +{ + memset(&drho[n], 0, nbytes); + memset(&heatflow[n], 0, nbytes); +} + +/* ---------------------------------------------------------------------- + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::data_atom_post(int ilocal) +{ + drho[ilocal] = 0.0; + heatflow[ilocal] = 0.0; + pressure[ilocal] = 0.0; + viscosity[ilocal] = 0.0; + conductivity[ilocal] = 0.0; +} + +/* ---------------------------------------------------------------------- + assign an index to named atom property and return index + return -1 if name is unknown to this atom style +------------------------------------------------------------------------- */ + +int AtomVecRHEOThermal::property_atom(const std::string &name) +{ + if (name == "status") return 0; + if (name == "rho") return 1; + if (name == "drho") return 2; + if (name == "temperature") return 3; + if (name == "heatflow") return 4; + if (name == "conductivity") return 5; + if (name == "pressure") return 6; + if (name == "viscosity") return 7; + return -1; +} + +/* ---------------------------------------------------------------------- + pack per-atom data into buf for ComputePropertyAtom + index maps to data specific to this atom style +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::pack_property_atom(int index, double *buf, int nvalues, int groupbit) +{ + int *mask = atom->mask; + int nlocal = atom->nlocal; + int n = 0; + + if (index == 0) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = status[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 1) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = rho[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 2) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = drho[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 3) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = temperature[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 4) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = heatflow[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 5) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = conductivity[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 6) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = pressure[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 7) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = viscosity[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } +} diff --git a/src/atom_vec_rheo_thermal.h b/src/atom_vec_rheo_thermal.h new file mode 100644 index 0000000000..27c6c3c9b5 --- /dev/null +++ b/src/atom_vec_rheo_thermal.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef ATOM_CLASS +// clang-format off +AtomStyle(rheo/thermal,AtomVecRHEOThermal); +// clang-format on +#else + +#ifndef LMP_ATOM_VEC_RHEO_THERMAL_H +#define LMP_ATOM_VEC_RHEO_THERMAL_H + +#include "atom_vec.h" + +namespace LAMMPS_NS { + +class AtomVecRHEOThermal : virtual public AtomVec { + public: + AtomVecRHEOThermal(class LAMMPS *); + + void grow_pointers() override; + void force_clear(int, size_t) override; + void data_atom_post(int) override; + int property_atom(const std::string &) override; + void pack_property_atom(int, double *, int, int) override; + + private: + int *status; + double *conductivity, *temperature, *heatflow; + double *pressure, *rho, *drho, *viscosity; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/compute_rheo_property_atom.cpp b/src/compute_rheo_property_atom.cpp new file mode 100644 index 0000000000..7682552abe --- /dev/null +++ b/src/compute_rheo_property_atom.cpp @@ -0,0 +1,411 @@ +// 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + +#include "compute_rheo_property_atom.h" + +#include "atom.h" +#include "atom_vec.h" +#include "compute_rheo_interface.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_surface.h" +#include "compute_rheo_vshift.h" +#include "error.h" +#include "fix_rheo.h" +#include "fix_rheo_thermal.h" +#include "memory.h" +#include "modify.h" +#include "update.h" + +#include +#include + +using namespace LAMMPS_NS; +using namespace RHEO_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), fix_rheo(nullptr), fix_thermal(nullptr), compute_interface(nullptr), + compute_kernel(nullptr), compute_surface(nullptr), compute_vshift(nullptr), + index(nullptr), pack_choice(nullptr) +{ + if (narg < 4) utils::missing_cmd_args(FLERR, "compute property/atom", error); + + peratom_flag = 1; + nvalues = narg - 3; + if (nvalues == 1) size_peratom_cols = 0; + else size_peratom_cols = nvalues; + + thermal_flag, interface_flag, surface_flag, shift_flag = 0; + + // parse input values + // customize a new keyword by adding to if statement + + pack_choice = new FnPtrPack[nvalues]; + index = new int[nvalues]; + + int i; + for (int iarg = 3; iarg < narg; iarg++) { + i = iarg-3; + + if (strcmp(arg[iarg],"phase") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_phase; + } else if (strcmp(arg[iarg],"chi") == 0) { + interface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_chi; + } else if (strcmp(arg[iarg],"surface") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface; + } else if (strcmp(arg[iarg],"surface/r") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_r; + } else if (strcmp(arg[iarg],"surface/divr") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_divr; + } else if (strcmp(arg[iarg],"surface/nx") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nx; + } else if (strcmp(arg[iarg],"surface/ny") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_ny; + } else if (strcmp(arg[iarg],"surface/nz") == 0) { + surface_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nz; + } else if (strcmp(arg[iarg],"coordination") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_coordination; + } else if (strcmp(arg[iarg],"cv") == 0) { + thermal_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; + } else if (strcmp(arg[iarg],"shift/vx") == 0) { + shift_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vx; + } else if (strcmp(arg[iarg],"shift/vy") == 0) { + shift_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vy; + } else if (strcmp(arg[iarg],"shift/vz") == 0) { + shift_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vz; + } else { + index[i] = atom->avec->property_atom(arg[iarg]); + if (index[i] < 0) + error->all(FLERR, + "Invalid keyword {} for atom style {} in compute rheo/property/atom command ", + atom->get_style(), arg[iarg]); + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; + + if (strcmp(arg[iarg],"temperature") == 0) thermal_flag = 1; + if (strcmp(arg[iarg],"heatflow") == 0) thermal_flag = 1; + if (strcmp(arg[iarg],"conductivity") == 0) thermal_flag = 1; + } + } + + nmax = 0; +} + +/* ---------------------------------------------------------------------- */ + +ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() +{ + delete[] pack_choice; + delete[] index; + memory->destroy(vector_atom); + memory->destroy(array_atom); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::init() +{ + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); + fix_rheo = dynamic_cast(fixes[0]); + + if (interface_flag && !(fix_rheo->interface_flag)) + error->all(FLERR, "Cannot request interfacial property without corresponding option in fix rheo"); + if (surface_flag && !(fix_rheo->surface_flag)) + error->all(FLERR, "Cannot request surface property without corresponding option in fix rheo"); + if (shift_flag && !(fix_rheo->shift_flag)) + error->all(FLERR, "Cannot request velocity shifting property without corresponding option in fix rheo"); + if (thermal_flag && !(fix_rheo->thermal_flag)) + error->all(FLERR, "Cannot request thermal property without fix rheo/thermal"); + + compute_interface = fix_rheo->compute_interface; + compute_kernel = fix_rheo->compute_kernel; + compute_surface = fix_rheo->compute_surface; + compute_vshift = fix_rheo->compute_vshift; + + if (thermal_flag) { + fixes = modify->get_fix_by_style("rheo/thermal"); + fix_thermal = dynamic_cast(fixes[0]); + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow vector or array if necessary + + if (atom->nmax > nmax) { + nmax = atom->nmax; + if (nvalues == 1) { + memory->destroy(vector_atom); + memory->create(vector_atom,nmax,"rheo/property/atom:vector"); + } else { + memory->destroy(array_atom); + memory->create(array_atom,nmax,nvalues,"rheo/property/atom:array"); + } + } + + // fill vector or array with per-atom values + + if (nvalues == 1) { + buf = vector_atom; + (this->*pack_choice[0])(0); + } else { + if (nmax) buf = &array_atom[0][0]; + else buf = nullptr; + for (int n = 0; n < nvalues; n++) + (this->*pack_choice[n])(n); + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputeRHEOPropertyAtom::memory_usage() +{ + double bytes = (double)nmax * nvalues * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- + one method for every keyword compute rheo/property/atom can output + the atom property is packed into buf starting at n with stride nvalues + customize a new keyword by adding a method +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_phase(int n) +{ + int *status = atom->status; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + int inverse_mask = ~PHASEMASK; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_chi(int n) +{ + double *chi = compute_interface->chi; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = chi[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface(int n) +{ + int *status = atom->status; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + int inverse_mask = ~SURFACEMASK; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_r(int n) +{ + double *rsurface = compute_surface->rsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = rsurface[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_divr(int n) +{ + double *divr = compute_surface->divr; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = divr[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_nx(int n) +{ + double **nsurface = compute_surface->nsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = nsurface[i][0]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_ny(int n) +{ + double **nsurface = compute_surface->nsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = nsurface[i][1]; + else buf[n] = 0.0; + n += nvalues; + } +} + + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_surface_nz(int n) +{ + double **nsurface = compute_surface->nsurface; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = nsurface[i][2]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_coordination(int n) +{ + int *coordination = compute_kernel->coordination; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = coordination[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_cv(int n) +{ + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = fix_thermal->calc_cv(i); + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_shift_vx(int n) +{ + double **vshift = compute_vshift->vshift; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = vshift[i][0]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_shift_vy(int n) +{ + double **vshift = compute_vshift->vshift; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = vshift[i][1]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_shift_vz(int n) +{ + double **vshift = compute_vshift->vshift; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = vshift[i][2]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_atom_style(int n) +{ + atom->avec->pack_property_atom(index[n],&buf[n],nvalues,groupbit); +} diff --git a/src/compute_rheo_property_atom.h b/src/compute_rheo_property_atom.h new file mode 100644 index 0000000000..accb7e9156 --- /dev/null +++ b/src/compute_rheo_property_atom.h @@ -0,0 +1,71 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(rheo/property/atom,ComputeRHEOPropertyAtom); +// clang-format on +#else + +#ifndef LMP_COMPUTE_RHEO_PROPERTY_ATOM_H +#define LMP_COMPUTE_RHEO_PROPERTY_ATOM_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeRHEOPropertyAtom : public Compute { + public: + ComputeRHEOPropertyAtom(class LAMMPS *, int, char **); + ~ComputeRHEOPropertyAtom() override; + void init() override; + void compute_peratom() override; + double memory_usage() override; + + private: + int nvalues, nmax; + int thermal_flag, interface_flag, surface_flag, shift_flag; + int *index; + double *buf; + + typedef void (ComputeRHEOPropertyAtom::*FnPtrPack)(int); + FnPtrPack *pack_choice; // ptrs to pack functions + + void pack_phase(int); + void pack_chi(int); + void pack_surface(int); + void pack_surface_r(int); + void pack_surface_divr(int); + void pack_surface_nx(int); + void pack_surface_ny(int); + void pack_surface_nz(int); + void pack_coordination(int); + void pack_cv(int); + void pack_shift_vx(int); + void pack_shift_vy(int); + void pack_shift_vz(int); + void pack_atom_style(int); + + class FixRHEO *fix_rheo; + class FixRHEOThermal *fix_thermal; + class ComputeRHEOInterface *compute_interface; + class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOSurface *compute_surface; + class ComputeRHEOVShift *compute_vshift; + +}; + +} // namespace LAMMPS_NS + +#endif +#endif From 0cd3bd190f9b97507ce953ff6ecdf49283db3c32 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 26 Apr 2023 12:14:40 -0600 Subject: [PATCH 031/385] Fixing various memory issues --- .../rheo/poiseuille/in.rheo.poiseuille | 83 +++++++++++++++++++ src/RHEO/compute_rheo_kernel.cpp | 46 +++++----- src/RHEO/compute_rheo_property_atom.cpp | 4 +- src/RHEO/fix_rheo.cpp | 4 +- src/RHEO/fix_rheo_pressure.cpp | 4 +- src/RHEO/fix_rheo_pressure.h | 1 - src/RHEO/fix_rheo_thermal.cpp | 2 +- src/RHEO/fix_rheo_viscosity.cpp | 2 +- src/RHEO/pair_rheo.cpp | 11 ++- src/compute_rheo_property_atom.cpp | 4 +- 10 files changed, 127 insertions(+), 34 deletions(-) create mode 100644 examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille diff --git a/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille b/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille new file mode 100644 index 0000000000..af5728c1a3 --- /dev/null +++ b/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille @@ -0,0 +1,83 @@ +dimension 2 +units lj +atom_style rheo +boundary p p p +comm_modify vel yes + + +# ------ Particle Lattice/Resolution Parameters ------ # + +variable L equal 10 +variable sf equal 0.2 +variable n equal 1.0/(${sf}^2) +variable cut equal 3.5*${sf} + + +# ------ Create simulation box ------ # + +region box block 0 20 -10 10 -0.01 0.01 units box +create_box 2 box +lattice sq ${n} + +region topwall block INF INF 7 10 INF INF units box +region block block INF INF -6.99 6.99 INF INF units box +region botwall block INF INF -10 -7 INF INF units box + +create_atoms 2 region topwall +create_atoms 2 region botwall +create_atoms 1 region block + +group fluid type 1 +group rig type 2 + +variable dr equal 0.1*${sf} +displace_atoms fluid random $(0.1*v_sf) ${dr} 0 135414 units box + + +# ------ Model parameters ------ # + +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable zeta equal 1.0 +variable kappa equal 1.0*${rho0}/${mp} +variable fext equal 1e-3/${n} +variable eta equal 0.1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable Dr equal 0.05*${cut}*${cs} + +mass 1 ${mp} +mass 2 ${mp} +set group all rheo/rho ${rho0} +set group all rheo/status 0 +set group rig rheo/status 2 +timestep ${dt_max} + +pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} +pair_coeff * * + + +# ------ Fixes & computes ------ # + +fix 1 all rheo ${cut} Quintic 0 shift +fix 2 all rheo/viscosity constant ${eta} +fix 3 all rheo/pressure linear +fix 4 rig setforce 0.0 0.0 0.0 +fix 5 fluid addforce ${fext} 0.0 0.0 + +compute 1 all rheo/property/atom rho phase + + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time temp press + +variable skin equal 0.2*${cut} +neighbor ${skin} bin +neigh_modify one 5000 + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] + +run 20000 + diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 9cfa86df7e..205ae6fb72 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -103,10 +103,6 @@ void ComputeRHEOKernel::init() { neighbor->add_request(this, NeighConst::REQ_FULL); - auto fixes = modify->get_fix_by_style("rheo"); - if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use compute rheo/kernel"); - fix_rheo = dynamic_cast(fixes[0]); - interface_flag = fix_rheo->interface_flag; compute_interface = fix_rheo->compute_interface; @@ -147,17 +143,16 @@ void ComputeRHEOKernel::init_list(int /*id*/, NeighList *ptr) int ComputeRHEOKernel::check_corrections(int i) { - int corrections = 1; - - if (gsl_error_flag) { - // If there were errors, check to see if it occured for this atom + // Skip if there were gsl errors for this atom + if (gsl_error_flag) if (gsl_error_tags.find(atom->tag[i]) != gsl_error_tags.end()) - corrections = 0; - } + return 0; - if (coordination[i] < zmin) corrections = 0; + // Skip if undercoordinated + if (coordination[i] < zmin) + return 0; - return corrections; + return 1; } /* ---------------------------------------------------------------------- */ @@ -165,12 +160,17 @@ int ComputeRHEOKernel::check_corrections(int i) double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double delz, double r) { double w; + int corrections_i, corrections_j, corrections; - int corrections_i = check_corrections(i); - int corrections_j = check_corrections(j); - int corrections = corrections_i & corrections_j; + if (kernel_style != QUINTIC) { + corrections_i = check_corrections(i); + corrections_j = check_corrections(j); + corrections = corrections_i & corrections_j; + } else { + corrections = 0; + } - if (kernel_style == QUINTIC || !corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); + if (!corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); else if (kernel_style == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); else if (kernel_style == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); else if (kernel_style == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); @@ -183,17 +183,21 @@ double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double delz, double r) { double wp; + int corrections_i, corrections_j; - int corrections_i = check_corrections(i); - int corrections_j = check_corrections(j); + if (kernel_style != QUINTIC) { + corrections_i = check_corrections(i); + corrections_j = check_corrections(j); + } // Calc wp and default dW's, a bit inefficient but can redo later wp = calc_dw_quintic(i,j,delx,dely,delz,r,dWij,dWji); - if(kernel_style == CRK1) { - //check if kernel correction calculated successfully. If not, revert to quintic + + // Overwrite if there are corrections + if (kernel_style == CRK1) { if (corrections_i) calc_dw_crk1(i,j,delx,dely,delz,r,dWij); if (corrections_j) calc_dw_crk1(j,i,-delx,-dely,-delz,r,dWji); - } else if(kernel_style == CRK2) { + } else if (kernel_style == CRK2) { if (corrections_i) calc_dw_crk2(i,j,delx,dely,delz,r,dWij); if (corrections_j) calc_dw_crk2(j,i,-delx,-dely,-delz,r,dWji); } diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 7682552abe..3cd5d468b2 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -52,7 +52,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; - thermal_flag, interface_flag, surface_flag, shift_flag = 0; + thermal_flag = interface_flag = surface_flag = shift_flag = 0; // parse input values // customize a new keyword by adding to if statement @@ -132,7 +132,7 @@ ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() void ComputeRHEOPropertyAtom::init() { - auto fixes = modify->get_fix_by_style("rheo"); + auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index ac870affd5..48eece239a 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -195,7 +195,7 @@ void FixRHEO::init() dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; - if (modify->get_fix_by_style("rheo").size() > 1) + if (modify->get_fix_by_style("^rheo$").size() > 1) error->all(FLERR,"Can only specify one instance of fix rheo"); } @@ -258,6 +258,8 @@ void FixRHEO::setup(int /*vflag*/) error->one(FLERR, "Fix rheo/viscosity does not fully cover all atoms"); if (!t_coverage_flag) error->one(FLERR, "Fix rheo/thermal does not fully cover all atoms"); + + pre_force(0); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 45557794cd..63a6995646 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -92,7 +92,7 @@ int FixRHEOPressure::setmask() void FixRHEOPressure::init() { - auto fixes = modify->get_fix_by_style("rheo"); + auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/pressure"); fix_rheo = dynamic_cast(fixes[0]); @@ -161,7 +161,7 @@ void FixRHEOPressure::pre_force(int /*vflag*/) } } - if (last_flag && comm_forward) comm->forward_comm(this); + if (comm_forward) comm->forward_comm(this); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index c257f1dbfb..e8f7f3cb88 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -41,7 +41,6 @@ class FixRHEOPressure : public Fix { double c_cubic, csq, rho0, rho0inv; double *pressure; int pressure_style; - int first_flag, last_flag; int nmax_store; class FixRHEO *fix_rheo; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 0d8909b908..bd7a22ce1e 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -155,7 +155,7 @@ int FixRHEOThermal::setmask() void FixRHEOThermal::init() { - auto fixes = modify->get_fix_by_style("rheo"); + auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 4d70ffaca3..7d915c9b93 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -102,7 +102,7 @@ int FixRHEOViscosity::setmask() void FixRHEOViscosity::init() { - auto fixes = modify->get_fix_by_style("rheo"); + auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 03e859316f..8e76a6d413 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -356,7 +356,9 @@ void PairRHEO::settings(int narg, char **arg) { if (narg < 1) error->all(FLERR,"Illegal pair_style command"); - int iarg = 0; + h = utils::numeric(FLERR,arg[0],false,lmp); +printf("settings\n"); + int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg], "rho/damp") == 0) { if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_style command"); @@ -419,10 +421,13 @@ void PairRHEO::setup() compute_grad = fix_rheo->compute_grad; compute_interface = fix_rheo->compute_interface; thermal_flag = fix_rheo->thermal_flag; - h = fix_rheo->h; csq = fix_rheo->csq; rho0 = fix_rheo->rho0; +printf("setup\n"); + if (h != fix_rheo->h) + error->all(FLERR, "Pair rheo cutoff {} does not agree with fix rheo cutoff {}", h, fix_rheo->h); + hsq = h * h; hinv = 1.0 / h; hinv3 = hinv * 3.0; cs = sqrt(csq); @@ -450,6 +455,6 @@ double PairRHEO::init_one(int i, int j) if (setflag[i][j] == 0) { error->all(FLERR,"All pair rheo coeffs are not set"); } - +printf("init one\n"); return h; } diff --git a/src/compute_rheo_property_atom.cpp b/src/compute_rheo_property_atom.cpp index 7682552abe..3cd5d468b2 100644 --- a/src/compute_rheo_property_atom.cpp +++ b/src/compute_rheo_property_atom.cpp @@ -52,7 +52,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; - thermal_flag, interface_flag, surface_flag, shift_flag = 0; + thermal_flag = interface_flag = surface_flag = shift_flag = 0; // parse input values // customize a new keyword by adding to if statement @@ -132,7 +132,7 @@ ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() void ComputeRHEOPropertyAtom::init() { - auto fixes = modify->get_fix_by_style("rheo"); + auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); From 0cd22dd0d2d6c309e75e99470e5035e78a98d098 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 27 Apr 2023 21:04:04 -0600 Subject: [PATCH 032/385] Creating doc pages and links for rheo --- doc/src/Howto.rst | 1 + doc/src/Howto_rheo.rst | 3 + doc/src/atom_style.rst | 114 +++++++++++++++++---------------- doc/src/compute.rst | 1 + doc/src/fix.rst | 4 ++ doc/src/fix_rheo.rst | 59 +++++++++++++++++ doc/src/fix_rheo_pressure.rst | 59 +++++++++++++++++ doc/src/fix_rheo_thermal.rst | 59 +++++++++++++++++ doc/src/fix_rheo_viscosity.rst | 59 +++++++++++++++++ doc/src/pair_rheo.rst | 86 +++++++++++++++++++++++++ doc/src/read_data.rst | 4 ++ doc/src/set.rst | 6 ++ 12 files changed, 400 insertions(+), 55 deletions(-) create mode 100644 doc/src/Howto_rheo.rst create mode 100644 doc/src/fix_rheo.rst create mode 100644 doc/src/fix_rheo_pressure.rst create mode 100644 doc/src/fix_rheo_thermal.rst create mode 100644 doc/src/fix_rheo_viscosity.rst create mode 100644 doc/src/pair_rheo.rst diff --git a/doc/src/Howto.rst b/doc/src/Howto.rst index 1366ecb839..94a465e6fd 100644 --- a/doc/src/Howto.rst +++ b/doc/src/Howto.rst @@ -89,6 +89,7 @@ Packages howto Howto_drude2 Howto_peri Howto_manifold + Howto_rheo Howto_spins Tutorials howto diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst new file mode 100644 index 0000000000..9dac90549c --- /dev/null +++ b/doc/src/Howto_rheo.rst @@ -0,0 +1,3 @@ +Reproducing hydrodynamics and elastic objects (RHEO) +====================== + diff --git a/doc/src/atom_style.rst b/doc/src/atom_style.rst index b5ee0f07ff..98d465a6f3 100644 --- a/doc/src/atom_style.rst +++ b/doc/src/atom_style.rst @@ -78,61 +78,65 @@ coordinates, velocities, atom IDs and types. See the :doc:`set ` commands for info on how to set these various quantities. -+--------------+-----------------------------------------------------+--------------------------------------+ -| *amoeba* | molecular + charge + 1/5 neighbors | AMOEBA/HIPPO polarized force fields | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *angle* | bonds and angles | bead-spring polymers with stiffness | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *atomic* | only the default values | coarse-grain liquids, solids, metals | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *body* | mass, inertia moments, quaternion, angular momentum | arbitrary bodies | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *bond* | bonds | bead-spring polymers | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *charge* | charge | atomic system with charges | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *dielectric* | normx normy normz area/patch ed em epsilon curv | system with surface polarization | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *dipole* | charge and dipole moment | system with dipolar particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *dpd* | internal temperature and internal energies | DPD particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *edpd* | temperature and heat capacity | eDPD particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *electron* | charge and spin and eradius | electronic force field | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *ellipsoid* | shape, quaternion, angular momentum | aspherical particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *full* | molecular + charge | bio-molecules | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *line* | end points, angular velocity | rigid bodies | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *mdpd* | density | mDPD particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *molecular* | bonds, angles, dihedrals, impropers | uncharged molecules | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *oxdna* | nucleotide polarity | coarse-grained DNA and RNA models | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *peri* | mass, volume | mesoscopic Peridynamic models | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *smd* | volume, kernel diameter, contact radius, mass | solid and fluid SPH particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *sph* | rho, esph, cv | SPH particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *sphere* | diameter, mass, angular velocity | granular models | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *bpm/sphere* | diameter, mass, angular velocity, quaternion | granular bonded particle models (BPM)| -+--------------+-----------------------------------------------------+--------------------------------------+ -| *spin* | magnetic moment | system with magnetic particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *tdpd* | chemical concentration | tDPD particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *template* | template index, template atom | small molecules with fixed topology | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *tri* | corner points, angular momentum | rigid bodies | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *wavepacket* | charge, spin, eradius, etag, cs_re, cs_im | AWPMD | -+--------------+-----------------------------------------------------+--------------------------------------+ ++----------------+-----------------------------------------------------+--------------------------------------+ +| *amoeba* | molecular + charge + 1/5 neighbors | AMOEBA/HIPPO polarized force fields | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *angle* | bonds and angles | bead-spring polymers with stiffness | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *atomic* | only the default values | coarse-grain liquids, solids, metals | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *body* | mass, inertia moments, quaternion, angular momentum | arbitrary bodies | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *bond* | bonds | bead-spring polymers | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *charge* | charge | atomic system with charges | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *dielectric* | normx normy normz area/patch ed em epsilon curv | system with surface polarization | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *dipole* | charge and dipole moment | system with dipolar particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *dpd* | internal temperature and internal energies | DPD particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *edpd* | temperature and heat capacity | eDPD particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *electron* | charge and spin and eradius | electronic force field | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *ellipsoid* | shape, quaternion, angular momentum | aspherical particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *full* | molecular + charge | bio-molecules | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *line* | end points, angular velocity | rigid bodies | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *mdpd* | density | mDPD particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *molecular* | bonds, angles, dihedrals, impropers | uncharged molecules | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *oxdna* | nucleotide polarity | coarse-grained DNA and RNA models | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *peri* | mass, volume | mesoscopic Peridynamic models | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *rheo* | rho, status | solid and fluid RHEO particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *rheo/thermal* | rho, status, temperature | RHEO particles with temperature | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *smd* | volume, kernel diameter, contact radius, mass | solid and fluid SPH particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *sph* | rho, esph, cv | SPH particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *sphere* | diameter, mass, angular velocity | granular models | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *bpm/sphere* | diameter, mass, angular velocity, quaternion | granular bonded particle models (BPM)| ++----------------+-----------------------------------------------------+--------------------------------------+ +| *spin* | magnetic moment | system with magnetic particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *tdpd* | chemical concentration | tDPD particles | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *template* | template index, template atom | small molecules with fixed topology | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *tri* | corner points, angular momentum | rigid bodies | ++----------------+-----------------------------------------------------+--------------------------------------+ +| *wavepacket* | charge, spin, eradius, etag, cs_re, cs_im | AWPMD | ++----------------+-----------------------------------------------------+--------------------------------------+ .. note:: diff --git a/doc/src/compute.rst b/doc/src/compute.rst index 880f60a8a6..5e90d78e83 100644 --- a/doc/src/compute.rst +++ b/doc/src/compute.rst @@ -271,6 +271,7 @@ The individual style names on the :doc:`Commands compute ` pag * :doc:`reduce ` - combine per-atom quantities into a single global value * :doc:`reduce/chunk ` - reduce per-atom quantities within each chunk * :doc:`reduce/region ` - same as compute reduce, within a region +* :doc:`rheo/property/atom ` - convert atom attributes in RHEO package to per-atom vectors/arrays * :doc:`rigid/local ` - extract rigid body attributes * :doc:`saed ` - electron diffraction intensity on a mesh of reciprocal lattice nodes * :doc:`slice ` - extract values from global vector or array diff --git a/doc/src/fix.rst b/doc/src/fix.rst index 56c7cde464..8ab202ab38 100644 --- a/doc/src/fix.rst +++ b/doc/src/fix.rst @@ -353,6 +353,10 @@ accelerated styles exist. * :doc:`reaxff/species ` - write out ReaxFF molecule information * :doc:`recenter ` - constrain the center-of-mass position of a group of atoms * :doc:`restrain ` - constrain a bond, angle, dihedral +* :doc:`rheo ` - integrator for the RHEO package +* :doc:`rheo/thermal ` - thermal integrator for the RHEO package +* :doc:`rheo/pressure ` - pressure derivation for the RHEO package +* :doc:`rheo/viscosity ` - viscosity derivation for the RHEO package * :doc:`rhok ` - add bias potential for long-range ordered systems * :doc:`rigid ` - constrain one or more clusters of atoms to move as a rigid body with NVE integration * :doc:`rigid/meso ` - constrain clusters of mesoscopic SPH/SDPD particles to move as a rigid body diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst new file mode 100644 index 0000000000..7200d456dd --- /dev/null +++ b/doc/src/fix_rheo.rst @@ -0,0 +1,59 @@ +.. index:: fix rheo + +fix rheo command +=============== + +Syntax +"""""" + +.. parsed-literal:: + + fix ID group-ID rheo + +* ID, group-ID are documented in :doc:`fix ` command +* rheo = style name of this fix command + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix 1 all rheo 1.0 CRK1 shift + +Description +""""""""""" + +Perform time integration to update position, velocity, internal energy +and local density for atoms in the group each timestep. This fix is +needed to time-integrate SPH systems where particles carry internal +variables such as internal energy. SPH stands for Smoothed Particle +Hydrodynamics. + +Restart, fix_modify, output, run start/stop, minimize info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +are relevant to this fix. No global or per-atom quantities are stored +by this fix for access by various :doc:`output commands `. +No parameter of this fix can be used with the *start/stop* keywords of +the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. + +Restrictions +"""""""""""" + +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`fix rheo/viscosity `, +:doc:`fix rheo/pressure `, +:doc:`fix rheo/thermal `, +:doc:`pair rheo `, +:doc:`compute rheo/property/atom ` + +Default +""""""" + +none diff --git a/doc/src/fix_rheo_pressure.rst b/doc/src/fix_rheo_pressure.rst new file mode 100644 index 0000000000..7200d456dd --- /dev/null +++ b/doc/src/fix_rheo_pressure.rst @@ -0,0 +1,59 @@ +.. index:: fix rheo + +fix rheo command +=============== + +Syntax +"""""" + +.. parsed-literal:: + + fix ID group-ID rheo + +* ID, group-ID are documented in :doc:`fix ` command +* rheo = style name of this fix command + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix 1 all rheo 1.0 CRK1 shift + +Description +""""""""""" + +Perform time integration to update position, velocity, internal energy +and local density for atoms in the group each timestep. This fix is +needed to time-integrate SPH systems where particles carry internal +variables such as internal energy. SPH stands for Smoothed Particle +Hydrodynamics. + +Restart, fix_modify, output, run start/stop, minimize info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +are relevant to this fix. No global or per-atom quantities are stored +by this fix for access by various :doc:`output commands `. +No parameter of this fix can be used with the *start/stop* keywords of +the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. + +Restrictions +"""""""""""" + +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`fix rheo/viscosity `, +:doc:`fix rheo/pressure `, +:doc:`fix rheo/thermal `, +:doc:`pair rheo `, +:doc:`compute rheo/property/atom ` + +Default +""""""" + +none diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst new file mode 100644 index 0000000000..7200d456dd --- /dev/null +++ b/doc/src/fix_rheo_thermal.rst @@ -0,0 +1,59 @@ +.. index:: fix rheo + +fix rheo command +=============== + +Syntax +"""""" + +.. parsed-literal:: + + fix ID group-ID rheo + +* ID, group-ID are documented in :doc:`fix ` command +* rheo = style name of this fix command + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix 1 all rheo 1.0 CRK1 shift + +Description +""""""""""" + +Perform time integration to update position, velocity, internal energy +and local density for atoms in the group each timestep. This fix is +needed to time-integrate SPH systems where particles carry internal +variables such as internal energy. SPH stands for Smoothed Particle +Hydrodynamics. + +Restart, fix_modify, output, run start/stop, minimize info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +are relevant to this fix. No global or per-atom quantities are stored +by this fix for access by various :doc:`output commands `. +No parameter of this fix can be used with the *start/stop* keywords of +the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. + +Restrictions +"""""""""""" + +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`fix rheo/viscosity `, +:doc:`fix rheo/pressure `, +:doc:`fix rheo/thermal `, +:doc:`pair rheo `, +:doc:`compute rheo/property/atom ` + +Default +""""""" + +none diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst new file mode 100644 index 0000000000..7200d456dd --- /dev/null +++ b/doc/src/fix_rheo_viscosity.rst @@ -0,0 +1,59 @@ +.. index:: fix rheo + +fix rheo command +=============== + +Syntax +"""""" + +.. parsed-literal:: + + fix ID group-ID rheo + +* ID, group-ID are documented in :doc:`fix ` command +* rheo = style name of this fix command + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix 1 all rheo 1.0 CRK1 shift + +Description +""""""""""" + +Perform time integration to update position, velocity, internal energy +and local density for atoms in the group each timestep. This fix is +needed to time-integrate SPH systems where particles carry internal +variables such as internal energy. SPH stands for Smoothed Particle +Hydrodynamics. + +Restart, fix_modify, output, run start/stop, minimize info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +are relevant to this fix. No global or per-atom quantities are stored +by this fix for access by various :doc:`output commands `. +No parameter of this fix can be used with the *start/stop* keywords of +the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. + +Restrictions +"""""""""""" + +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`fix rheo/viscosity `, +:doc:`fix rheo/pressure `, +:doc:`fix rheo/thermal `, +:doc:`pair rheo `, +:doc:`compute rheo/property/atom ` + +Default +""""""" + +none diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst new file mode 100644 index 0000000000..b5c02c41ff --- /dev/null +++ b/doc/src/pair_rheo.rst @@ -0,0 +1,86 @@ +.. index:: pair_style sph/lj + +pair_style sph/lj command +========================= + +Syntax +"""""" + +.. code-block:: LAMMPS + + pair_style sph/lj + +Examples +"""""""" + +.. code-block:: LAMMPS + + pair_style sph/lj + pair_coeff * * 1.0 2.4 + +Description +""""""""""" + +The sph/lj style computes pressure forces between particles according +to the Lennard-Jones equation of state, which is computed according to +Ree's 1980 polynomial fit :ref:`(Ree) `. The Lennard-Jones parameters +epsilon and sigma are set to unity. This pair style also computes +Monaghan's artificial viscosity to prevent particles from +interpenetrating :ref:`(Monaghan) `. + +See `this PDF guide `_ to using SPH in +LAMMPS. + +The following coefficients must be defined for each pair of atoms +types via the :doc:`pair_coeff ` command as in the examples +above. + +* :math:`\nu` artificial viscosity (no units) +* h kernel function cutoff (distance units) + +---------- + +Mixing, shift, table, tail correction, restart, rRESPA info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +This style does not support mixing. Thus, coefficients for all +I,J pairs must be specified explicitly. + +This style does not support the :doc:`pair_modify ` +shift, table, and tail options. + +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. + +This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, +*middle*, *outer* keywords. + +Restrictions +"""""""""""" + +As noted above, the Lennard-Jones parameters epsilon and sigma are set +to unity. + +This pair style is part of the SPH package. It is only enabled +if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`pair_coeff `, pair_sph/rhosum + +Default +""""""" + +none + +---------- + +.. _Ree: + +**(Ree)** Ree, Journal of Chemical Physics, 73, 5401 (1980). + +.. _Monoghan: + +**(Monaghan)** Monaghan and Gingold, Journal of Computational Physics, +52, 374-389 (1983). diff --git a/doc/src/read_data.rst b/doc/src/read_data.rst index 0ecd2b6fa2..4950d8bc25 100644 --- a/doc/src/read_data.rst +++ b/doc/src/read_data.rst @@ -714,6 +714,10 @@ of analysis. - atom-ID molecule-ID atom-type x y z * - peri - atom-ID atom-type volume density x y z + * - rheo + - atom-ID atom-type status rho x y z + * - rheo/thermal + - atom-ID atom-type status rho temperature x y z * - smd - atom-ID atom-type molecule volume mass kradius cradius x0 y0 z0 x y z * - sph diff --git a/doc/src/set.rst b/doc/src/set.rst index 0073e44bf8..96e48a8893 100644 --- a/doc/src/set.rst +++ b/doc/src/set.rst @@ -111,6 +111,8 @@ Syntax *angle* value = angle type for all angles between selected atoms *dihedral* value = dihedral type for all dihedrals between selected atoms *improper* value = improper type for all impropers between selected atoms + *rheo/rho* value = density of RHEO particles (mass/distance\^3) + *rheo/status* value = status or phase of RHEO particles (unitless) *sph/e* value = energy of SPH particles (need units) value can be an atom-style variable (see below) *sph/cv* value = heat capacity of SPH particles (need units) @@ -472,6 +474,10 @@ the *bond types* (\ *angle types*, etc) field in the header of the data file read by the :doc:`read_data ` command. These keywords do not allow use of an atom-style variable. +Keywords *rheo/rho* and *rheo/status* set the density and the status of +rheo particles. In particular, one can only set the phase in the status +as described by the :doc:`RHEO howto page `. + Keywords *sph/e*, *sph/cv*, and *sph/rho* set the energy, heat capacity, and density of smoothed particle hydrodynamics (SPH) particles. See `this PDF guide `_ to using SPH in LAMMPS. From 0b1d393d7817c40d4df9735e96dbdec1093e741b Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 1 May 2023 14:05:47 -0600 Subject: [PATCH 033/385] Adding arguments to doc page --- doc/src/Howto_rheo.rst | 1 + doc/src/fix_rheo.rst | 36 ++++++++++++++----- doc/src/fix_rheo_pressure.rst | 33 +++++++++++------ doc/src/fix_rheo_thermal.rst | 50 ++++++++++++++++++++------ doc/src/fix_rheo_viscosity.rst | 43 ++++++++++++++++------ doc/src/pair_rheo.rst | 66 +++++++++++++--------------------- src/RHEO/fix_rheo.cpp | 6 ++-- src/RHEO/fix_rheo_thermal.cpp | 2 +- src/RHEO/pair_rheo.cpp | 6 ++-- 9 files changed, 154 insertions(+), 89 deletions(-) diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index 9dac90549c..c55631455b 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -1,3 +1,4 @@ Reproducing hydrodynamics and elastic objects (RHEO) ====================== +Text diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 7200d456dd..e9613e4838 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -8,26 +8,38 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo + fix ID group-ID rheo cut kstyle keyword values... * ID, group-ID are documented in :doc:`fix ` command * rheo = style name of this fix command +* cut = *quintic* or *CRK0* or *CRK1* or *CRK2* +* zero or more keyword/value pairs may be appended to args +* keyword = *shift* or *thermal* or *surface/detection* or *interface/reconstruction* or *rho/sum* or *density* or *sound/squared* + + .. parsed-literal:: + + *shift* values = none, turns on velocity shifting + *thermal* values = none, turns on thermal evolution + *surface/detection* values = *sdstyle* *limit* + *sdstyle* = *coordination* or *divergence* + *limit* = threshold for surface particles (unitless) + *interface/reconstruction* values = none, reconstructs interfaces with solid particles + *rho/sum* values = none, uses the kernel to compute the density of particles + *density* values = *rho0* (density) + *sound/squared* values = *csq* (velocity\^2) Examples """""""" .. code-block:: LAMMPS - fix 1 all rheo 1.0 CRK1 shift + fix 1 all rheo 1.0 quintic thermal density 0.1 sound/squared 10.0 + fix 1 all rheo 1.0 CRK1 shift surface/detection coordination 40 Description """"""""""" -Perform time integration to update position, velocity, internal energy -and local density for atoms in the group each timestep. This fix is -needed to time-integrate SPH systems where particles carry internal -variables such as internal energy. SPH stands for Smoothed Particle -Hydrodynamics. +Fix description... Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -41,6 +53,14 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" +This fix must be used with an atom style that includes density +such as atom_style rheo or rheo/thermal. This fix must be used in +conjuction with :doc:`fix rheo/pressure `. and +:doc:`fix rheo/viscosity `, If the *thermal* +setting is used, there must also be an instance of +:doc:`fix rheo/thermal `. The fix group must be +set to all. + This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. @@ -56,4 +76,4 @@ Related commands Default """"""" -none +*rho0* and *csq* are set to 1.0. diff --git a/doc/src/fix_rheo_pressure.rst b/doc/src/fix_rheo_pressure.rst index 7200d456dd..ceb402501a 100644 --- a/doc/src/fix_rheo_pressure.rst +++ b/doc/src/fix_rheo_pressure.rst @@ -1,6 +1,6 @@ -.. index:: fix rheo +.. index:: fix rheo/pressure -fix rheo command +fix rheo/pressure command =============== Syntax @@ -8,26 +8,33 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo + fix ID group-ID rheo/pressure pstyle args * ID, group-ID are documented in :doc:`fix ` command -* rheo = style name of this fix command +* rheo/pressure = style name of this fix command +* pstyle = *linear* or *taitwater* or *cubic* + + .. parsed-literal:: + + *linear* args = none + *taitwater* args = none + *cubic* args = cubic term prefactor :math:`A_3` (pressure/density\^2) Examples """""""" .. code-block:: LAMMPS - fix 1 all rheo 1.0 CRK1 shift + fix 1 all rheo/pressure linear + fix 1 all rheo/pressure cubic 10.0 Description """"""""""" -Perform time integration to update position, velocity, internal energy -and local density for atoms in the group each timestep. This fix is -needed to time-integrate SPH systems where particles carry internal -variables such as internal energy. SPH stands for Smoothed Particle -Hydrodynamics. +This fix... + +Only one instance of fix rheo/pressure can be defined and the fix group must be set to all. + Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -41,6 +48,11 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" +This fix must be used with an atom style that includes density +such as atom_style rheo or rheo/thermal. This fix must be used in +conjuction with :doc:`fix rheo `. The fix group must be +set to all. + This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. @@ -48,7 +60,6 @@ Related commands """""""""""""""" :doc:`fix rheo/viscosity `, -:doc:`fix rheo/pressure `, :doc:`fix rheo/thermal `, :doc:`pair rheo `, :doc:`compute rheo/property/atom ` diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index 7200d456dd..01b4820a39 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -1,6 +1,6 @@ -.. index:: fix rheo +.. index:: fix rheo/thermal -fix rheo command +fix rheo/thermal command =============== Syntax @@ -8,26 +8,49 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo + fix ID group-ID rheo/thermal keyword values ... * ID, group-ID are documented in :doc:`fix ` command -* rheo = style name of this fix command +* rheo/viscosity = style name of this fix command +* one or more attributes may be appended +* attribute = *conductivity* or *specific/heat* or *Tfreeze* + + .. parsed-literal:: + + *conductivity* args = style param + style = *constant* or *type* + *constant* arg = conductivity (power/temperature) + *type* args = list of conductivity values, one per type (power/temperature) + *specific/heat* args = style param + style = *constant* or *type* + *constant* arg = specific heat (energy/(mass*temperature)) + *type* args = list of specific heat values, one per atom type (energy/(mass*temperature)) + *Tfreeze* args = style param + style = *constant* or *type* + *constant* arg = freezing temperature (temperature) + *type* args = list of freezing temperature values, one per type (temperature) Examples """""""" .. code-block:: LAMMPS - fix 1 all rheo 1.0 CRK1 shift + fix 1 all rheo/thermal conductivity constant 1.0 specific/heat constant 1.0 Tfreeze constant 1.0 + fix 1 all rheo/pressure conductivity constant 1.0 specific/heat type 1.0 2.0 Description """"""""""" -Perform time integration to update position, velocity, internal energy -and local density for atoms in the group each timestep. This fix is -needed to time-integrate SPH systems where particles carry internal -variables such as internal energy. SPH stands for Smoothed Particle -Hydrodynamics. +This fix... + +While the *Tfreeze* keyword is optional, the *conducitivity* and +*specific/heat* keywords are mandatory. + +Multiple instances of this fix may be defined to apply different +properties to different groups. However, the union of fix groups +across all instances of fix rheo/thermal must cover all atoms. +If there are multiple instances of this fix, any intersections in +the fix groups will lead to incorrect thermal integration. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -41,15 +64,20 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" +This fix must be used with an atom style that includes temperature, +heatflow, and conductivity such as atom_tyle rheo/thermal This fix +must be used in conjuction with :doc:`fix rheo ` with the +*thermal* setting. + This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. Related commands """""""""""""""" +:doc:`fix rheo `, :doc:`fix rheo/viscosity `, :doc:`fix rheo/pressure `, -:doc:`fix rheo/thermal `, :doc:`pair rheo `, :doc:`compute rheo/property/atom ` diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst index 7200d456dd..278c621216 100644 --- a/doc/src/fix_rheo_viscosity.rst +++ b/doc/src/fix_rheo_viscosity.rst @@ -1,6 +1,6 @@ -.. index:: fix rheo +.. index:: fix rheo/viscosity -fix rheo command +fix rheo/viscosity command =============== Syntax @@ -8,26 +8,43 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo + fix ID group-ID rheo/viscosity vstyle args * ID, group-ID are documented in :doc:`fix ` command -* rheo = style name of this fix command +* rheo/viscosity = style name of this fix command +* vstyle = *constant* or *type* or *power* + + .. parsed-literal:: + + *constant* arg = viscosity (mass/(length*time)) + *type* args = list of viscosity values, one per atom type (mass/(length*time)) + *power* args = *eta* *gd0* *K* *npow* *tau0* + *eta* = (units) + *gd0* = (units) + *K* = (units) + *npow* = (units) + *tau0* = (units) Examples """""""" .. code-block:: LAMMPS - fix 1 all rheo 1.0 CRK1 shift + fix 1 all rheo/viscosity constant 1.0 + fix 1 all rheo/viscosity power 0.1 1e-2 0.5 0.01 Description """"""""""" -Perform time integration to update position, velocity, internal energy -and local density for atoms in the group each timestep. This fix is -needed to time-integrate SPH systems where particles carry internal -variables such as internal energy. SPH stands for Smoothed Particle -Hydrodynamics. +This fix... + +Multiple instances of this fix may be defined to apply different +properties to different groups. However, the union of fix groups +across all instances of fix rheo/viscosity must cover all atoms. +If there are multiple instances of this fix, any intersection +between fix groups will cause the viscosity for the affected atoms +to be calculated multiple times. Any such affected atoms will enabled +up with a viscosity calculated by the latest defined fix. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -41,13 +58,17 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" +This fix must be used with an atom style that includes viscosity +such as atom_style rheo or rheo/thermal. This fix must be used in +conjuction with :doc:`fix rheo `. + This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. Related commands """""""""""""""" -:doc:`fix rheo/viscosity `, +:doc:`fix rheo `, :doc:`fix rheo/pressure `, :doc:`fix rheo/thermal `, :doc:`pair rheo `, diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst index b5c02c41ff..7a26755780 100644 --- a/doc/src/pair_rheo.rst +++ b/doc/src/pair_rheo.rst @@ -1,6 +1,6 @@ .. index:: pair_style sph/lj -pair_style sph/lj command +pair_style rheo command ========================= Syntax @@ -8,79 +8,63 @@ Syntax .. code-block:: LAMMPS - pair_style sph/lj + pair_style rheo cut keyword values + +* cut = *quintic* or *CRK0* or *CRK1* or *CRK2* +* zero or more keyword/value pairs may be appended to args +* keyword = *rho/damp* or *artificial/visc* + +.. parsed-literal:: + + *rho/damp* args = density damping prefactor :math:`\xi` (units?) + *artificial/visc* args = artificial viscosity prefactor :math:`\zeta` (units?) Examples """""""" .. code-block:: LAMMPS - pair_style sph/lj - pair_coeff * * 1.0 2.4 + pair_style rheo 1.0 quintic rho/damp 1.0 artificial/visc 2.0 + pair_coeff * * Description """"""""""" -The sph/lj style computes pressure forces between particles according -to the Lennard-Jones equation of state, which is computed according to -Ree's 1980 polynomial fit :ref:`(Ree) `. The Lennard-Jones parameters -epsilon and sigma are set to unity. This pair style also computes -Monaghan's artificial viscosity to prevent particles from -interpenetrating :ref:`(Monaghan) `. +pair style... -See `this PDF guide `_ to using SPH in -LAMMPS. - -The following coefficients must be defined for each pair of atoms -types via the :doc:`pair_coeff ` command as in the examples +No coefficients are defined for each pair of atoms types via the +:doc:`pair_coeff ` command as in the examples above. -* :math:`\nu` artificial viscosity (no units) -* h kernel function cutoff (distance units) - ---------- Mixing, shift, table, tail correction, restart, rRESPA info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This style does not support mixing. Thus, coefficients for all -I,J pairs must be specified explicitly. - This style does not support the :doc:`pair_modify ` shift, table, and tail options. This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. -This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, -*middle*, *outer* keywords. +This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, *middle*, *outer* keywords. Restrictions """""""""""" -As noted above, the Lennard-Jones parameters epsilon and sigma are set -to unity. - -This pair style is part of the SPH package. It is only enabled -if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. Related commands """""""""""""""" -:doc:`pair_coeff `, pair_sph/rhosum +:doc:`fix rheo `, +:doc:`fix rheo/pressure `, +:doc:`fix rheo/thermal `, +:doc:`fix rheo/viscosity `, +:doc:`compute rheo/property/atom ` Default """"""" -none - ----------- - -.. _Ree: - -**(Ree)** Ree, Journal of Chemical Physics, 73, 5401 (1980). - -.. _Monoghan: - -**(Monaghan)** Monaghan and Gingold, Journal of Computational Physics, -52, 374-389 (1983). +No density damping or artificial viscous forces are calculated. diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 48eece239a..bacaae074d 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -74,7 +74,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : h = utils::numeric(FLERR,arg[3],false,lmp); cut = h; - if (strcmp(arg[4],"Quintic") == 0) { + if (strcmp(arg[4],"quintic") == 0) { kernel_style = QUINTIC; } else if (strcmp(arg[4],"CRK0") == 0) { kernel_style = CRK0; @@ -109,11 +109,11 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : interface_flag = 1; } else if (strcmp(arg[iarg],"rho/sum") == 0) { rhosum_flag = 1; - } else if (strcmp(arg[iarg],"rho0") == 0) { + } else if (strcmp(arg[iarg],"density") == 0) { if(iarg + 1 >= narg) error->all(FLERR,"Illegal rho0 option in fix rheo"); rho0 = utils::numeric(FLERR,arg[iarg + 1],false,lmp); iarg += 1; - } else if (strcmp(arg[iarg],"csq") == 0) { + } else if (strcmp(arg[iarg],"sound/squared") == 0) { if(iarg+1 >= narg) error->all(FLERR,"Illegal csq option in fix rheo"); csq = utils::numeric(FLERR,arg[iarg + 1],false,lmp); iarg += 1; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index bd7a22ce1e..ec39a13311 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -72,7 +72,7 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } - } else if (strcmp(arg[iarg],"cv") == 0) { + } else if (strcmp(arg[iarg],"specific/heat") == 0) { // Cv arguments if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for cv option"); if (strcmp(arg[iarg + 1],"constant") == 0) { diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 8e76a6d413..b8b8e5a809 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -357,7 +357,7 @@ void PairRHEO::settings(int narg, char **arg) if (narg < 1) error->all(FLERR,"Illegal pair_style command"); h = utils::numeric(FLERR,arg[0],false,lmp); -printf("settings\n"); + int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg], "rho/damp") == 0) { @@ -423,7 +423,7 @@ void PairRHEO::setup() thermal_flag = fix_rheo->thermal_flag; csq = fix_rheo->csq; rho0 = fix_rheo->rho0; -printf("setup\n"); + if (h != fix_rheo->h) error->all(FLERR, "Pair rheo cutoff {} does not agree with fix rheo cutoff {}", h, fix_rheo->h); @@ -455,6 +455,6 @@ double PairRHEO::init_one(int i, int j) if (setflag[i][j] == 0) { error->all(FLERR,"All pair rheo coeffs are not set"); } -printf("init one\n"); + return h; } From c81c4cefc07fa0c131a03d497ac58737f7864af8 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 1 May 2023 14:32:14 -0600 Subject: [PATCH 034/385] Fixing pair label --- doc/src/pair_rheo.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst index 7a26755780..d168f79785 100644 --- a/doc/src/pair_rheo.rst +++ b/doc/src/pair_rheo.rst @@ -1,4 +1,4 @@ -.. index:: pair_style sph/lj +.. index:: pair_style rheo pair_style rheo command ========================= From 4a419b2f006acac80c316b4c216134cb31ae5189 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 1 May 2023 14:47:52 -0600 Subject: [PATCH 035/385] Adding rheo property/atom compute odc --- doc/src/compute_rheo_property_atom.rst | 101 +++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 doc/src/compute_rheo_property_atom.rst diff --git a/doc/src/compute_rheo_property_atom.rst b/doc/src/compute_rheo_property_atom.rst new file mode 100644 index 0000000000..5476f7f709 --- /dev/null +++ b/doc/src/compute_rheo_property_atom.rst @@ -0,0 +1,101 @@ +.. index:: compute rheo/property/atom + +compute rheo/property/atom command +============================= + +Syntax +"""""" + +.. code-block:: LAMMPS + + compute ID group-ID rheo/property/atom input1 input2 ... + +* ID, group-ID are documented in :doc:`compute ` command +* rheo/property/atom = style name of this compute command +* input = one or more atom attributes + + .. parsed-literal:: + + possible attributes = phase, chi, surface, surface/r, + surface/divr, surface/nx, surface/ny, + surface/nz, coordination, cv, shift/vx, + shift/vy, shift/vz, temperature, heatflow, + conductivity, viscosity, pressure, status, + rho + + .. parsed-literal:: + + *phase* = atom phase status + *chi* = atom phase neighborhood metric + *surface* = atom surface status + *surface/r* = atom distance from the surface + *surface/divr* = divergence of position at atom position + *surface/nx, surface/ny, surface/nz* = surface normal vector + *coordination* = coordination number + *shift/vx, shift/vy, shift/vz* = atom shifting velocity + *temperature* = atom temperature + *heatflow* = atom heat flow + *conductivity* = atom conductivity + *viscosity* = atom viscosity + *pressure* = atom pressure + *status* = atom full status + *rho* = atom density + +Examples +"""""""" + +.. code-block:: LAMMPS + + compute 1 all rheo/property/atom phase surface/r pressure + +Description +""""""""""" + +Define a computation that simply stores atom attributes specific to the +RHEO package for each atom in the group. This is useful so that the +values can be used by other :doc:`output commands ` that +take computes as inputs. See for example, the :doc:`compute reduce +`, :doc:`fix ave/atom `, :doc:`fix +ave/histo `, :doc:`fix ave/chunk `, +and :doc:`atom-style variable ` commands. + +The possible attributes are described in more detail in other RHEO doc +pages include :doc:`fix rheo `, :doc:`pair rheo `, +and :doc:`the RHEO howto page `. + +The values are stored in a per-atom vector or array as discussed +below. Zeroes are stored for atoms not in the specified group or for +quantities that are not defined for a particular particle in the group + +Output info +""""""""""" + +This compute calculates a per-atom vector or per-atom array depending +on the number of input values. If a single input is specified, a +per-atom vector is produced. If two or more inputs are specified, a +per-atom array is produced where the number of columns = the number of +inputs. The vector or array can be accessed by any command that uses +per-atom values from a compute as input. See the :doc:`Howto output +` page for an overview of LAMMPS output options. + +The vector or array values will be in whatever :doc:`units ` the +corresponding attribute is in (e.g., density units for *rho*). + +Restrictions +"""""""""""" + none + +Related commands +"""""""""""""""" + +:doc:`dump custom `, :doc:`compute reduce `, +:doc:`fix ave/atom `, :doc:`fix ave/chunk `, +:doc:`fix rheo/viscosity `, +:doc:`fix rheo/pressure `, +:doc:`fix rheo/thermal `, +:doc:`pair rheo ` + +Default +""""""" + +none From 35418afd6b186eaa1be26a09ea5740573a8a53b1 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 11 May 2023 14:19:32 -0600 Subject: [PATCH 036/385] Rename CRK -> RK --- doc/src/fix_rheo.rst | 4 +-- src/RHEO/compute_rheo_kernel.cpp | 60 ++++++++++++++++---------------- src/RHEO/compute_rheo_kernel.h | 10 +++--- src/RHEO/fix_rheo.cpp | 12 +++---- src/RHEO/fix_rheo.h | 2 +- src/RHEO/pair_rheo.cpp | 4 +-- 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index e9613e4838..7aaab48f54 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -12,7 +12,7 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * rheo = style name of this fix command -* cut = *quintic* or *CRK0* or *CRK1* or *CRK2* +* cut = *quintic* or *RK0* or *RK1* or *RK2* * zero or more keyword/value pairs may be appended to args * keyword = *shift* or *thermal* or *surface/detection* or *interface/reconstruction* or *rho/sum* or *density* or *sound/squared* @@ -34,7 +34,7 @@ Examples .. code-block:: LAMMPS fix 1 all rheo 1.0 quintic thermal density 0.1 sound/squared 10.0 - fix 1 all rheo 1.0 CRK1 shift surface/detection coordination 40 + fix 1 all rheo 1.0 RK1 shift surface/detection coordination 40 Description """"""""""" diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 205ae6fb72..09d807d50d 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -60,11 +60,11 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : if (kernel_style == QUINTIC) { correction_order = -1; - } else if (kernel_style == CRK0) { + } else if (kernel_style == RK0) { correction_order = 0; - } else if (kernel_style == CRK1) { + } else if (kernel_style == RK1) { correction_order = 1; - } else if (kernel_style == CRK2) { + } else if (kernel_style == RK2) { correction_order = 2; } @@ -73,11 +73,11 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : comm_forward = 1; ncor = 0; Mdim = 0; - if (kernel_style == CRK1) { + if (kernel_style == RK1) { Mdim = 1 + dim; ncor = 1 + dim; comm_forward = ncor * Mdim; - } else if (kernel_style == CRK2) { + } else if (kernel_style == RK2) { //Polynomial basis size (up to quadratic order) Mdim = 1 + dim + dim * (dim + 1) / 2; //Number of sets of correction coefficients (1 x y xx yy) + z zz (3D) @@ -123,11 +123,11 @@ void ComputeRHEOKernel::init() nmax_store = atom->nmax; memory->create(coordination, nmax_store, "rheo:coordination"); - if (kernel_style == CRK0) { + if (kernel_style == RK0) { memory->create(C0, nmax_store, "rheo/kernel:C0"); - } else if (kernel_style == CRK1) { + } else if (kernel_style == RK1) { memory->create(C, nmax_store, ncor, Mdim, "rheo/kernel:C"); - } else if (kernel_style == CRK2) { + } else if (kernel_style == RK2) { memory->create(C, nmax_store, ncor, Mdim, "rheo/kernel:C"); } } @@ -171,9 +171,9 @@ double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double } if (!corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); - else if (kernel_style == CRK0) w = calc_w_crk0(i,j,delx,dely,delz,r); - else if (kernel_style == CRK1) w = calc_w_crk1(i,j,delx,dely,delz,r); - else if (kernel_style == CRK2) w = calc_w_crk2(i,j,delx,dely,delz,r); + else if (kernel_style == RK0) w = calc_w_rk0(i,j,delx,dely,delz,r); + else if (kernel_style == RK1) w = calc_w_rk1(i,j,delx,dely,delz,r); + else if (kernel_style == RK2) w = calc_w_rk2(i,j,delx,dely,delz,r); return w; } @@ -194,12 +194,12 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double wp = calc_dw_quintic(i,j,delx,dely,delz,r,dWij,dWji); // Overwrite if there are corrections - if (kernel_style == CRK1) { - if (corrections_i) calc_dw_crk1(i,j,delx,dely,delz,r,dWij); - if (corrections_j) calc_dw_crk1(j,i,-delx,-dely,-delz,r,dWji); - } else if (kernel_style == CRK2) { - if (corrections_i) calc_dw_crk2(i,j,delx,dely,delz,r,dWij); - if (corrections_j) calc_dw_crk2(j,i,-delx,-dely,-delz,r,dWji); + if (kernel_style == RK1) { + if (corrections_i) calc_dw_rk1(i,j,delx,dely,delz,r,dWij); + if (corrections_j) calc_dw_rk1(j,i,-delx,-dely,-delz,r,dWji); + } else if (kernel_style == RK2) { + if (corrections_i) calc_dw_rk2(i,j,delx,dely,delz,r,dWij); + if (corrections_j) calc_dw_rk2(j,i,-delx,-dely,-delz,r,dWji); } return wp; @@ -285,7 +285,7 @@ double ComputeRHEOKernel::calc_dw_quintic(int i, int j, double delx, double dely /* ---------------------------------------------------------------------- */ -double ComputeRHEOKernel::calc_w_crk0(int i, int j, double delx, double dely, double delz, double r) +double ComputeRHEOKernel::calc_w_rk0(int i, int j, double delx, double dely, double delz, double r) { double w; @@ -299,7 +299,7 @@ double ComputeRHEOKernel::calc_w_crk0(int i, int j, double delx, double dely, do /* ---------------------------------------------------------------------- */ -double ComputeRHEOKernel::calc_w_crk1(int i, int j, double delx, double dely, double delz, double r) +double ComputeRHEOKernel::calc_w_rk1(int i, int j, double delx, double dely, double delz, double r) { int b; double w, wR, dx[3], H[Mdim]; @@ -341,7 +341,7 @@ double ComputeRHEOKernel::calc_w_crk1(int i, int j, double delx, double dely, do /* ---------------------------------------------------------------------- */ -double ComputeRHEOKernel::calc_w_crk2(int i, int j, double delx, double dely, double delz, double r) +double ComputeRHEOKernel::calc_w_rk2(int i, int j, double delx, double dely, double delz, double r) { int b; double w, wR, dx[3], H[Mdim]; @@ -391,7 +391,7 @@ double ComputeRHEOKernel::calc_w_crk2(int i, int j, double delx, double dely, do /* ---------------------------------------------------------------------- */ -void ComputeRHEOKernel::calc_dw_crk1(int i, int j, double delx, double dely, double delz, double r, double *dW) +void ComputeRHEOKernel::calc_dw_rk1(int i, int j, double delx, double dely, double delz, double r, double *dW) { int a, b; double w, dx[3], H[Mdim]; @@ -428,7 +428,7 @@ void ComputeRHEOKernel::calc_dw_crk1(int i, int j, double delx, double dely, dou /* ---------------------------------------------------------------------- */ -void ComputeRHEOKernel::calc_dw_crk2(int i, int j, double delx, double dely, double delz, double r, double *dW) +void ComputeRHEOKernel::calc_dw_rk2(int i, int j, double delx, double dely, double delz, double r, double *dW) { int a, b; double w, dx[3], H[Mdim]; @@ -504,7 +504,7 @@ void ComputeRHEOKernel::compute_peratom() // Grow arrays if necessary if (nmax_store < atom->nmax) grow_arrays(atom->nmax); - if (kernel_style == CRK0) { + if (kernel_style == RK0) { double M; for (ii = 0; ii < inum; ii++) { @@ -592,7 +592,7 @@ void ComputeRHEOKernel::compute_peratom() H[0] = 1.0; H[1] = dx[0] * hinv; H[2] = dx[1] * hinv; - if (kernel_style == CRK2) { + if (kernel_style == RK2) { H[3] = 0.5 * dx[0] * dx[0] * hsqinv; H[4] = 0.5 * dx[1] * dx[1] * hsqinv; H[5] = dx[0] * dx[1] * hsqinv; @@ -602,7 +602,7 @@ void ComputeRHEOKernel::compute_peratom() H[1] = dx[0] * hinv; H[2] = dx[1] * hinv; H[3] = dx[2] * hinv; - if (kernel_style == CRK2) { + if (kernel_style == RK2) { H[4] = 0.5 * dx[0] * dx[0] * hsqinv; H[5] = 0.5 * dx[1] * dx[1] * hsqinv; H[6] = 0.5 * dx[2] * dx[2] * hsqinv; @@ -676,7 +676,7 @@ void ComputeRHEOKernel::compute_peratom() // columns 1-2 (2D) or 1-3 (3D) //Second derivatives - if (kernel_style == CRK2) + if (kernel_style == RK2) C[i][1 + dim + b][a] = M[a * Mdim + b + 1 + dim] * hsqinv; // columns 3-4 (2D) or 4-6 (3D) } @@ -746,7 +746,7 @@ void ComputeRHEOKernel::grow_arrays(int nmax) { memory->grow(coordination, nmax, "rheo:coordination"); - if (kernel_style == CRK0) { + if (kernel_style == RK0) { memory->grow(C0, nmax, "rheo/kernel:C0"); } else if (correction_order > 0) { memory->grow(C, nmax, ncor, Mdim, "rheo/kernel:C"); @@ -768,7 +768,7 @@ int ComputeRHEOKernel::pack_forward_comm(int n, int *list, double *buf, if (comm_stage == 0) { buf[m++] = coordination[j]; } else { - if (kernel_style == CRK0) { + if (kernel_style == RK0) { buf[m++] = C0[j]; } else { for (a = 0; a < ncor; a++) @@ -792,7 +792,7 @@ void ComputeRHEOKernel::unpack_forward_comm(int n, int first, double *buf) if (comm_stage == 0) { coordination[i] = buf[m++]; } else { - if (kernel_style == CRK0) { + if (kernel_style == RK0) { C0[i] = buf[m++]; } else { for (a = 0; a < ncor; a++) @@ -810,7 +810,7 @@ double ComputeRHEOKernel::memory_usage() double bytes = 0.0; bytes = (size_t) nmax_store * sizeof(int); - if (kernel_style == CRK0) { + if (kernel_style == RK0) { bytes += (size_t) nmax_store * sizeof(double); } else if (correction_order > 0) { bytes += (size_t) nmax_store * ncor * Mdim * sizeof(double); diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 5324199f76..2c9f4768e1 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -64,11 +64,11 @@ class ComputeRHEOKernel : public Compute { int check_corrections(int); - double calc_w_crk0(int,int,double,double,double,double); - double calc_w_crk1(int,int,double,double,double,double); - double calc_w_crk2(int,int,double,double,double,double); - void calc_dw_crk1(int,int,double,double,double,double,double *); - void calc_dw_crk2(int,int,double,double,double,double,double *); + double calc_w_rk0(int,int,double,double,double,double); + double calc_w_rk1(int,int,double,double,double,double); + double calc_w_rk2(int,int,double,double,double,double); + void calc_dw_rk1(int,int,double,double,double,double,double *); + void calc_dw_rk2(int,int,double,double,double,double,double *); }; } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index bacaae074d..04e6c08917 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -76,12 +76,12 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : cut = h; if (strcmp(arg[4],"quintic") == 0) { kernel_style = QUINTIC; - } else if (strcmp(arg[4],"CRK0") == 0) { - kernel_style = CRK0; - } else if (strcmp(arg[4],"CRK1") == 0) { - kernel_style = CRK1; - } else if (strcmp(arg[4],"CRK2") == 0) { - kernel_style = CRK2; + } else if (strcmp(arg[4],"RK0") == 0) { + kernel_style = RK0; + } else if (strcmp(arg[4],"RK1") == 0) { + kernel_style = RK1; + } else if (strcmp(arg[4],"RK2") == 0) { + kernel_style = RK2; } else error->all(FLERR,"Unknown kernel style {} in fix rheo", arg[4]); zmin_kernel = utils::numeric(FLERR,arg[5],false,lmp); diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index a74696e68c..743e418f9a 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -68,7 +68,7 @@ class FixRHEO : public Fix { namespace RHEO_NS { - enum {QUINTIC, CRK0, CRK1, CRK2}; + enum {QUINTIC, RK0, RK1, RK2}; enum {COORDINATION, DIVR}; // Status variables diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index b8b8e5a809..0d041b1e30 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -437,9 +437,9 @@ void PairRHEO::setup() error->all(FLERR,"Pair RHEO requires ghost atoms store velocity"); if (laplacian_order == -1) { - if (fix_rheo->kernel_style == CRK2) + if (fix_rheo->kernel_style == RK2) laplacian_order = 2; - else if (fix_rheo->kernel_style == CRK1) + else if (fix_rheo->kernel_style == RK1) laplacian_order = 1; else laplacian_order = 0; From dfc47a55010a896c99c661f3e13b525f52242eef Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 12 May 2023 23:33:02 -0600 Subject: [PATCH 037/385] Fixing various errors, reorganizing status variable --- .../rheo/poiseuille/in.rheo.poiseuille | 2 +- src/.gitignore | 2 + src/RHEO/compute_rheo_grad.cpp | 11 ++-- src/RHEO/compute_rheo_interface.cpp | 10 ++-- src/RHEO/compute_rheo_kernel.cpp | 4 +- src/RHEO/compute_rheo_property_atom.cpp | 8 +-- src/RHEO/compute_rheo_rho_sum.cpp | 1 - src/RHEO/compute_rheo_surface.cpp | 4 +- src/RHEO/compute_rheo_vshift.cpp | 15 ++++-- src/RHEO/fix_rheo.cpp | 34 ++++++------- src/RHEO/fix_rheo.h | 29 ++++++----- src/RHEO/fix_rheo_pressure.cpp | 37 ++------------ src/RHEO/fix_rheo_pressure.h | 3 -- src/RHEO/fix_rheo_thermal.cpp | 22 +++++--- src/RHEO/pair_rheo.cpp | 50 ++++++++++++------- src/RHEO/pair_rheo.h | 1 + 16 files changed, 113 insertions(+), 120 deletions(-) diff --git a/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille b/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille index af5728c1a3..d0f966c2ce 100644 --- a/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille +++ b/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille @@ -59,7 +59,7 @@ pair_coeff * * # ------ Fixes & computes ------ # -fix 1 all rheo ${cut} Quintic 0 shift +fix 1 all rheo ${cut} quintic 0 shift fix 2 all rheo/viscosity constant ${eta} fix 3 all rheo/pressure linear fix 4 rig setforce 0.0 0.0 0.0 diff --git a/src/.gitignore b/src/.gitignore index d0fcaf495c..f9794ddb82 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -205,6 +205,8 @@ /compute_rheo_interface.h /compute_rheo_kernel.cpp /compute_rheo_kernel.h +/compute_rheo_property_atom.cpp +/compute_rheo_property_atom.h /compute_rheo_rho_sum.cpp /compute_rheo_rho_sum.h /compute_rheo_surface.cpp diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index b71fb08d78..92ac108377 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -125,7 +125,7 @@ void ComputeRHEOGrad::init_list(int /*id*/, NeighList *ptr) void ComputeRHEOGrad::compute_peratom() { - int i, j, k, ii, jj, jnum, itype, jtype, a, b; + int i, j, k, ii, jj, jnum, itype, jtype, a, b, fluidi, fluidj; double xtmp, ytmp, ztmp, delx, dely, delz; double rsq, imass, jmass; double rhoi, rhoj, Voli, Volj, drho, dT, deta; @@ -183,6 +183,7 @@ void ComputeRHEOGrad::compute_peratom() vi[1] = v[i][1]; vi[2] = v[i][2]; itype = type[i]; + fluidi = !(status[i] & PHASECHECK); jlist = firstneigh[i]; jnum = numneigh[i]; @@ -197,6 +198,8 @@ void ComputeRHEOGrad::compute_peratom() rsq = delx * delx + dely * dely + delz * delz; if (rsq < cutsq) { + fluidj = !(status[j] & PHASECHECK); + rhoi = rho[i]; rhoj = rho[j]; @@ -206,13 +209,13 @@ void ComputeRHEOGrad::compute_peratom() // Add corrections for walls if (interface_flag) { - if ((status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { + if (fluidi && (!fluidj)) { compute_interface->correct_v(vi, vj, i, j); rhoj = compute_interface->correct_rho(j, i); - } else if (!(status[i] & STATUS_FLUID) && (status[j] & STATUS_FLUID)) { + } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vj, vi, j, i); rhoi = compute_interface->correct_rho(i, j); - } else if (!(status[i] & STATUS_FLUID) && !(status[j] & STATUS_FLUID)) { + } else if ((!fluidi) && (!fluidj)) { rhoi = rho0; rhoj = rho0; } diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index a3624f9663..ea4916087f 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -131,7 +131,7 @@ void ComputeRHEOInterface::compute_peratom() } for (i = 0; i < nall; i++) { - if (!(status[i] & STATUS_FLUID)) rho[i] = 0.0; + if (status[i] & PHASECHECK) rho[i] = 0.0; normwf[i] = 0.0; norm[i] = 0.0; chi[i] = 0.0; @@ -143,7 +143,7 @@ void ComputeRHEOInterface::compute_peratom() ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; - fluidi = status[i] & STATUS_FLUID; + fluidi = !(status[i] & PHASECHECK); jlist = firstneigh[i]; jnum = numneigh[i]; @@ -158,7 +158,7 @@ void ComputeRHEOInterface::compute_peratom() if (rsq < cutsq) { jtype = type[j]; - fluidj = status[j] & STATUS_FLUID; + fluidj = !(status[j] & PHASECHECK); w = compute_kernel->calc_w_quintic(i, j, delx, dely, delz, sqrt(rsq)); status_match = 0; @@ -202,7 +202,7 @@ void ComputeRHEOInterface::compute_peratom() if (norm[i] != 0.0) chi[i] /= norm[i]; // Recalculate rho for non-fluid particles - if (!(status[i] & STATUS_FLUID)) { + if (status[i] & PHASECHECK) { if (normwf[i] != 0.0) { // Stores rho for solid particles 1+Pw in Adami Adams 2012 rho[i] = MAX(EPSILON, rho0 + (rho[i] / normwf[i]) * csq_inv); @@ -289,7 +289,7 @@ void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) j = list[i]; norm[j] += buf[m++]; chi[j] += buf[m++]; - if (!(status[j] & STATUS_FLUID)){ + if (status[j] & PHASECHECK){ normwf[j] += buf[m++]; rho[j] += buf[m++]; } else { diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 09d807d50d..52380a4337 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -533,7 +533,7 @@ void ComputeRHEOKernel::compute_peratom() w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); rhoj = rho[j]; if (interface_flag) - if (!(status[j] & STATUS_FLUID)) + if (status[j] & PHASECHECK) rhoj = compute_interface->correct_rho(j,i); vj = mass[type[j]] / rhoj; @@ -582,7 +582,7 @@ void ComputeRHEOKernel::compute_peratom() rhoj = rho[j]; if (interface_flag) - if (!(status[j] & STATUS_FLUID)) + if (status[j] & PHASECHECK) rhoj = compute_interface->correct_rho(j,i); vj = mass[type[j]] / rhoj; diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 3cd5d468b2..880ae5d64f 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -212,10 +212,8 @@ void ComputeRHEOPropertyAtom::pack_phase(int n) int *mask = atom->mask; int nlocal = atom->nlocal; - int inverse_mask = ~PHASEMASK; - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); + if (mask[i] & groupbit) buf[n] = (status[i] & PHASECHECK); else buf[n] = 0.0; n += nvalues; } @@ -244,10 +242,8 @@ void ComputeRHEOPropertyAtom::pack_surface(int n) int *mask = atom->mask; int nlocal = atom->nlocal; - int inverse_mask = ~SURFACEMASK; - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); + if (mask[i] & groupbit) buf[n] = (status[i] & SURFACECHECK); else buf[n] = 0.0; n += nvalues; } diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp index 726d876ea1..0a2096a2b9 100644 --- a/src/RHEO/compute_rheo_rho_sum.cpp +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -74,7 +74,6 @@ void ComputeRHEORhoSum::compute_peratom() double **x = atom->x; double *rho = atom->rho; int *type = atom->type; - int *status = atom->status; double *mass = atom->mass; int newton = force->newton; diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 180c430dd1..f6b93ee551 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -183,7 +183,7 @@ void ComputeRHEOSurface::compute_peratom() jlist = firstneigh[i]; jnum = numneigh[i]; itype = type[i]; - fluidi = status[i] & STATUS_FLUID; + fluidi = !(status[i] & PHASECHECK); for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -196,7 +196,7 @@ void ComputeRHEOSurface::compute_peratom() rsq = lensq3(dx); if (rsq < cutsq) { jtype = type[j]; - fluidj = status[j] & STATUS_FLUID; + fluidj = !(status[j] & PHASECHECK); rhoi = rho[i]; rhoj = rho[j]; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 3d3914436e..0521ff16c0 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -91,7 +91,7 @@ void ComputeRHEOVShift::compute_peratom() double xtmp, ytmp, ztmp, rsq, r, rinv; double w, wp, dr, w0, w4, vmag, prefactor; double imass, jmass, voli, volj, rhoi, rhoj; - double dx[3], vi[3], vj[3] = {0}; + double dx[3], vi[3], vj[3]; int dim = domain->dimension; int *jlist; @@ -123,6 +123,11 @@ void ComputeRHEOVShift::compute_peratom() for (a = 0; a < dim; a++) vshift[i][a] = 0.0; + for (a = 0; a < 3; a++) { + vi[a] = 0.0; + vj[a] = 0.0; + } + for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; @@ -132,15 +137,15 @@ void ComputeRHEOVShift::compute_peratom() jlist = firstneigh[i]; jnum = numneigh[i]; imass = mass[itype]; - fluidi = status[i] & STATUS_FLUID; + fluidi = !(status[i] & PHASECHECK); for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; - fluidj = status[j] & STATUS_FLUID; + fluidj = !(status[j] & PHASECHECK); if ((!fluidi) && (!fluidj)) continue; - if (!(status[i] & STATUS_SHIFT) && !(status[j] & STATUS_SHIFT)) continue; + if ((status[i] & STATUS_NO_SHIFT) && (status[j] & STATUS_NO_SHIFT)) continue; dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; @@ -154,7 +159,7 @@ void ComputeRHEOVShift::compute_peratom() r = sqrt(rsq); rinv = 1 / r; - for (a = 0; a < dim; a ++) { + for (a = 0; a < dim; a++) { vi[a] = v[i][a]; vj[a] = v[j][a]; } diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 04e6c08917..fd436cab6e 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -210,6 +210,8 @@ void FixRHEO::setup_pre_force(int /*vflag*/) // Calculate surfaces if (surface_flag) compute_surface->compute_peratom(); + + pre_force(0); } /* ---------------------------------------------------------------------- */ @@ -258,8 +260,6 @@ void FixRHEO::setup(int /*vflag*/) error->one(FLERR, "Fix rheo/viscosity does not fully cover all atoms"); if (!t_coverage_flag) error->one(FLERR, "Fix rheo/thermal does not fully cover all atoms"); - - pre_force(0); } /* ---------------------------------------------------------------------- */ @@ -283,7 +283,8 @@ void FixRHEO::initial_integrate(int /*vflag*/) double **gradr = compute_grad->gradr; double **gradv = compute_grad->gradv; double **vshift; - if (shift_flag) compute_vshift->vshift; + if (shift_flag) + vshift = compute_vshift->vshift; int nlocal = atom->nlocal; int rmass_flag = atom->rmass_flag; @@ -294,7 +295,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) //Density Half-step for (i = 0; i < nlocal; i++) { - if (status[i] & STATUS_NO_FORCE) continue; + if (status[i] & STATUS_NO_INTEGRATION) continue; if (mask[i] & groupbit) { if (rmass_flag) { @@ -331,8 +332,8 @@ void FixRHEO::initial_integrate(int /*vflag*/) if (!rhosum_flag) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { - if (status[i] & STATUS_NO_FORCE) continue; - if (!(status[i] & STATUS_FLUID)) continue; + if (status[i] & STATUS_NO_INTEGRATION) continue; + if (status[i] & PHASECHECK) continue; divu = 0; for (a = 0; a < dim; a++) { @@ -348,7 +349,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) compute_vshift->correct_surfaces(); // Could this be moved to preforce after the surface fix runs? for (i = 0; i < nlocal; i++) { - if (!(status[i] & STATUS_SHIFT)) continue; + if (status[i] & STATUS_NO_SHIFT) continue; if (mask[i] & groupbit) { for (a = 0; a < dim; a++) { @@ -387,18 +388,13 @@ void FixRHEO::pre_force(int /*vflag*/) if (shift_flag) compute_vshift->compute_peratom(); - // Remove extra shifting/no force options + // Remove temporary options int *mask = atom->mask; int *status = atom->status; int nall = atom->nlocal + atom->nghost; - for (int i = 0; i < nall; i++) { - if (mask[i] & groupbit) { - status[i] &= ~STATUS_NO_FORCE; - - if (status[i] & STATUS_FLUID) - status[i] &= ~STATUS_SHIFT; - } - } + for (int i = 0; i < nall; i++) + if (mask[i] & groupbit) + status[i] &= OPTIONSMASK; // Calculate surfaces, update status if (surface_flag) compute_surface->compute_peratom(); @@ -433,7 +429,7 @@ void FixRHEO::final_integrate() // Update velocity for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { - if (status[i] & STATUS_NO_FORCE) continue; + if (status[i] & STATUS_NO_INTEGRATION) continue; if (rmass_flag) { dtfm = dtf / rmass[i]; @@ -451,8 +447,8 @@ void FixRHEO::final_integrate() if (!rhosum_flag) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { - if (status[i] & STATUS_NO_FORCE) continue; - if (!(status[i] & STATUS_FLUID)) continue; + if (status[i] & STATUS_NO_INTEGRATION) continue; + if (status[i] & PHASECHECK) continue; divu = 0; for (a = 0; a < dim; a++) { diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 743e418f9a..0dbc8db78b 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -74,22 +74,27 @@ namespace RHEO_NS { // Status variables enum Status{ // Phase status - STATUS_FLUID = 1 << 0, - STATUS_SOLID = 1 << 1, - STATUS_REACTIVE = 1 << 2, - STATUS_FREEZING = 1 << 3, + STATUS_SOLID = 1 << 0, + STATUS_REACTIVE = 1 << 1, + // Surface status - STATUS_BULK = 1 << 4, - STATUS_LAYER = 1 << 5, - STATUS_SURFACE = 1 << 6, - STATUS_SPLASH = 1 << 7, + STATUS_BULK = 1 << 2, + STATUS_LAYER = 1 << 3, + STATUS_SURFACE = 1 << 4, + STATUS_SPLASH = 1 << 5, + // Temporary status options - reset in preforce - STATUS_SHIFT = 1 << 8, - STATUS_NO_FORCE = 1 << 9 + STATUS_NO_SHIFT = 1 << 6, + STATUS_NO_INTEGRATION = 1 << 7, + STATUS_FREEZING = 1 << 8 }; - #define PHASEMASK 0xFFFFFFF0; - #define SURFACEMASK 0xFFFFFF0F; + // Masks and their inverses + #define PHASEMASK 0xFFFFFFFC + #define PHASECHECK 0x00000003 + #define SURFACEMASK 0xFFFFFFC3 + #define SURFACECHECK 0x0000003C + #define OPTIONSMASK 0xFFFFFE3F } // namespace RHEO_NS } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 63a6995646..ff206937f4 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -43,9 +43,7 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : if (narg < 4) error->all(FLERR,"Illegal fix command"); pressure_style = NONE; - comm_forward = 1; - nmax_store = 0; // Currently can only have one instance of fix rheo/pressure if (igroup != 0) @@ -73,10 +71,6 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : FixRHEOPressure::~FixRHEOPressure() { - // Remove custom property if it exists - int tmp1, tmp2, index; - index = atom->find_custom("rheo_pressure", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); } /* ---------------------------------------------------------------------- */ @@ -110,20 +104,6 @@ void FixRHEOPressure::init() void FixRHEOPressure::setup_pre_force(int /*vflag*/) { fix_rheo->pressure_fix_defined = 1; - - // Create pressure array if it doesn't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - - int tmp1, tmp2; - int index = atom->find_custom("rheo_pressure", tmp1, tmp2); - if (index == -1) { - index = atom->add_custom("rheo_pressure", 1, 0); - nmax_store = atom->nmax; - } - pressure = atom->dvector[index]; - pre_force(0); } @@ -138,14 +118,10 @@ void FixRHEOPressure::pre_force(int /*vflag*/) int *mask = atom->mask; double *rho = atom->rho; + double *pressure = atom->pressure; int nlocal = atom->nlocal; - if (nmax_store < atom->nmax) { - memory->grow(pressure, atom->nmax, "atom:rheo_pressure"); - nmax_store = atom->nmax; - } - for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (pressure_style == LINEAR) { @@ -170,6 +146,7 @@ int FixRHEOPressure::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,k,m; + double *pressure = atom->pressure; m = 0; for (i = 0; i < n; i++) { @@ -184,6 +161,7 @@ int FixRHEOPressure::pack_forward_comm(int n, int *list, double *buf, void FixRHEOPressure::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; + double *pressure = atom->pressure; m = 0; last = first + n; @@ -210,12 +188,3 @@ double FixRHEOPressure::calc_pressure(double rho) } return rho; } - -/* ---------------------------------------------------------------------- */ - -double FixRHEOPressure::memory_usage() -{ - double bytes = 0.0; - bytes += (size_t) nmax_store * sizeof(double); - return bytes; -} diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index e8f7f3cb88..cbcb495244 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -34,14 +34,11 @@ class FixRHEOPressure : public Fix { void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; - double memory_usage() override; double calc_pressure(double); private: double c_cubic, csq, rho0, rho0inv; - double *pressure; int pressure_style; - int nmax_store; class FixRHEO *fix_rheo; }; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index ec39a13311..de88b4f8d0 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -205,7 +205,7 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) nlocal = atom->nfirst; for (i = 0; i < nlocal; i++) { - if (!(status[i] & STATUS_SHIFT)) continue; + if (status[i] & STATUS_NO_SHIFT) continue; if (mask[i] & groupbit) { for (a = 0; a < dim; a++) { @@ -231,7 +231,7 @@ void FixRHEOThermal::post_integrate() //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { - if (status[i] & STATUS_NO_FORCE) continue; + if (status[i] & STATUS_NO_INTEGRATION) continue; cvi = calc_cv(i); temperature[i] += dtf * heatflow[i] / cvi; @@ -245,11 +245,17 @@ void FixRHEOThermal::post_integrate() } if (Ti > Tci) { - status[i] &= PHASEMASK; - status[i] |= STATUS_FLUID; - } else if (!(status[i] & STATUS_SOLID)) { - status[i] &= PHASEMASK; - status[i] |= STATUS_FREEZING; + // If solid, melt + if (status[i] & STATUS_SOLID) { + status[i] &= PHASEMASK; + } + } else { + // If fluid, freeze + if (!(status[i] & STATUS_SOLID)) { + status[i] &= PHASEMASK; + status[i] |= STATUS_SOLID; + status[i] |= STATUS_FREEZING; + } } } } @@ -300,7 +306,7 @@ void FixRHEOThermal::final_integrate() //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { - if (status[i] & STATUS_NO_FORCE) continue; + if (status[i] & STATUS_NO_INTEGRATION) continue; cvi = calc_cv(i); temperature[i] += dtf * heatflow[i] / cvi; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 0d041b1e30..0930f28f98 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -120,6 +120,16 @@ void PairRHEO::compute(int eflag, int vflag) numneigh = list->numneigh; firstneigh = list->firstneigh; + for (a = 0; a < 3; a++) { + vi[a] = 0.0; + vj[a] = 0.0; + du[a] = 0.0; + fv[a] = 0.0; + dfp[a] = 0.0; + fsolid[a] = 0.0; + ft[0] = 0.0; + } + // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { @@ -132,7 +142,7 @@ void PairRHEO::compute(int eflag, int vflag) jnum = numneigh[i]; imass = mass[itype]; etai = viscosity[i]; - fluidi = status[i] & STATUS_FLUID; + fluidi = !(status[i] & PHASECHECK); if (thermal_flag) { kappai = conductivity[i]; Ti = temperature[i]; @@ -154,7 +164,7 @@ void PairRHEO::compute(int eflag, int vflag) jmass = mass[jtype]; etaj = viscosity[j]; - fluidj = status[j] & STATUS_FLUID; + fluidj = !(status[j] & PHASECHECK); if (thermal_flag) { Tj = temperature[j]; kappaj = conductivity[j]; @@ -186,25 +196,27 @@ void PairRHEO::compute(int eflag, int vflag) Pi = pressure[i]; Pj = pressure[j]; fmag = 0; - if (fluidi && (!fluidj)) { - compute_interface->correct_v(vi, vj, i, j); - rhoj = compute_interface->correct_rho(j, i); - Pj = fix_pressure->calc_pressure(rhoj); + if (interface_flag) { + if (fluidi && (!fluidj)) { + compute_interface->correct_v(vi, vj, i, j); + rhoj = compute_interface->correct_rho(j, i); + Pj = fix_pressure->calc_pressure(rhoj); - if ((chi[j] > 0.9) && (r < (h * 0.5))) - fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; + if ((chi[j] > 0.9) && (r < (h * 0.5))) + fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; - } else if ((!fluidi) && fluidj) { - compute_interface->correct_v(vj, vi, j, i); - rhoi = compute_interface->correct_rho(i, j); - Pi = fix_pressure->calc_pressure(rhoi); + } else if ((!fluidi) && fluidj) { + compute_interface->correct_v(vj, vi, j, i); + rhoi = compute_interface->correct_rho(i, j); + Pi = fix_pressure->calc_pressure(rhoi); - if (chi[i] > 0.9 && r < (h * 0.5)) - fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; + if (chi[i] > 0.9 && r < (h * 0.5)) + fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; - } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0; - rhoj = rho0; + } else if ((!fluidi) && (!fluidj)) { + rhoi = rho0; + rhoj = rho0; + } } // Repel if close to inner solid particle @@ -234,7 +246,7 @@ void PairRHEO::compute(int eflag, int vflag) sub3(vi, vj, du); //Add artificial viscous pressure if required - if (artificial_visc_flag && pair_avisc_flag){ + if (artificial_visc_flag && pair_avisc_flag) { //Interpolate velocities to midpoint and use this difference for artificial viscosity for (a = 0; a < dim; a++) for (b = 0; b < dim; b++) @@ -328,6 +340,7 @@ void PairRHEO::compute(int eflag, int vflag) } } } + if (vflag_fdotr) virial_fdotr_compute(); } @@ -421,6 +434,7 @@ void PairRHEO::setup() compute_grad = fix_rheo->compute_grad; compute_interface = fix_rheo->compute_interface; thermal_flag = fix_rheo->thermal_flag; + interface_flag = fix_rheo->interface_flag; csq = fix_rheo->csq; rho0 = fix_rheo->rho0; diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index 49aa1ad025..b30b0c3c04 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -42,6 +42,7 @@ class PairRHEO : public Pair { int artificial_visc_flag; int rho_damp_flag; int thermal_flag; + int interface_flag; void allocate(); From 55f7e9271c2049a27909858d61a357ee42ddc484 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 12 May 2023 23:34:26 -0600 Subject: [PATCH 038/385] removing old files --- src/compute_rheo_property_atom.cpp | 411 ----------------------------- src/compute_rheo_property_atom.h | 71 ----- 2 files changed, 482 deletions(-) delete mode 100644 src/compute_rheo_property_atom.cpp delete mode 100644 src/compute_rheo_property_atom.h diff --git a/src/compute_rheo_property_atom.cpp b/src/compute_rheo_property_atom.cpp deleted file mode 100644 index 3cd5d468b2..0000000000 --- a/src/compute_rheo_property_atom.cpp +++ /dev/null @@ -1,411 +0,0 @@ -// 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. -------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) ------------------------------------------------------------------------ */ - -#include "compute_rheo_property_atom.h" - -#include "atom.h" -#include "atom_vec.h" -#include "compute_rheo_interface.h" -#include "compute_rheo_kernel.h" -#include "compute_rheo_surface.h" -#include "compute_rheo_vshift.h" -#include "error.h" -#include "fix_rheo.h" -#include "fix_rheo_thermal.h" -#include "memory.h" -#include "modify.h" -#include "update.h" - -#include -#include - -using namespace LAMMPS_NS; -using namespace RHEO_NS; - -/* ---------------------------------------------------------------------- */ - -ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), fix_rheo(nullptr), fix_thermal(nullptr), compute_interface(nullptr), - compute_kernel(nullptr), compute_surface(nullptr), compute_vshift(nullptr), - index(nullptr), pack_choice(nullptr) -{ - if (narg < 4) utils::missing_cmd_args(FLERR, "compute property/atom", error); - - peratom_flag = 1; - nvalues = narg - 3; - if (nvalues == 1) size_peratom_cols = 0; - else size_peratom_cols = nvalues; - - thermal_flag = interface_flag = surface_flag = shift_flag = 0; - - // parse input values - // customize a new keyword by adding to if statement - - pack_choice = new FnPtrPack[nvalues]; - index = new int[nvalues]; - - int i; - for (int iarg = 3; iarg < narg; iarg++) { - i = iarg-3; - - if (strcmp(arg[iarg],"phase") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_phase; - } else if (strcmp(arg[iarg],"chi") == 0) { - interface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_chi; - } else if (strcmp(arg[iarg],"surface") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface; - } else if (strcmp(arg[iarg],"surface/r") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_r; - } else if (strcmp(arg[iarg],"surface/divr") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_divr; - } else if (strcmp(arg[iarg],"surface/nx") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nx; - } else if (strcmp(arg[iarg],"surface/ny") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_ny; - } else if (strcmp(arg[iarg],"surface/nz") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nz; - } else if (strcmp(arg[iarg],"coordination") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_coordination; - } else if (strcmp(arg[iarg],"cv") == 0) { - thermal_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; - } else if (strcmp(arg[iarg],"shift/vx") == 0) { - shift_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vx; - } else if (strcmp(arg[iarg],"shift/vy") == 0) { - shift_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vy; - } else if (strcmp(arg[iarg],"shift/vz") == 0) { - shift_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vz; - } else { - index[i] = atom->avec->property_atom(arg[iarg]); - if (index[i] < 0) - error->all(FLERR, - "Invalid keyword {} for atom style {} in compute rheo/property/atom command ", - atom->get_style(), arg[iarg]); - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; - - if (strcmp(arg[iarg],"temperature") == 0) thermal_flag = 1; - if (strcmp(arg[iarg],"heatflow") == 0) thermal_flag = 1; - if (strcmp(arg[iarg],"conductivity") == 0) thermal_flag = 1; - } - } - - nmax = 0; -} - -/* ---------------------------------------------------------------------- */ - -ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() -{ - delete[] pack_choice; - delete[] index; - memory->destroy(vector_atom); - memory->destroy(array_atom); -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::init() -{ - auto fixes = modify->get_fix_by_style("^rheo$"); - if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); - fix_rheo = dynamic_cast(fixes[0]); - - if (interface_flag && !(fix_rheo->interface_flag)) - error->all(FLERR, "Cannot request interfacial property without corresponding option in fix rheo"); - if (surface_flag && !(fix_rheo->surface_flag)) - error->all(FLERR, "Cannot request surface property without corresponding option in fix rheo"); - if (shift_flag && !(fix_rheo->shift_flag)) - error->all(FLERR, "Cannot request velocity shifting property without corresponding option in fix rheo"); - if (thermal_flag && !(fix_rheo->thermal_flag)) - error->all(FLERR, "Cannot request thermal property without fix rheo/thermal"); - - compute_interface = fix_rheo->compute_interface; - compute_kernel = fix_rheo->compute_kernel; - compute_surface = fix_rheo->compute_surface; - compute_vshift = fix_rheo->compute_vshift; - - if (thermal_flag) { - fixes = modify->get_fix_by_style("rheo/thermal"); - fix_thermal = dynamic_cast(fixes[0]); - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::compute_peratom() -{ - invoked_peratom = update->ntimestep; - - // grow vector or array if necessary - - if (atom->nmax > nmax) { - nmax = atom->nmax; - if (nvalues == 1) { - memory->destroy(vector_atom); - memory->create(vector_atom,nmax,"rheo/property/atom:vector"); - } else { - memory->destroy(array_atom); - memory->create(array_atom,nmax,nvalues,"rheo/property/atom:array"); - } - } - - // fill vector or array with per-atom values - - if (nvalues == 1) { - buf = vector_atom; - (this->*pack_choice[0])(0); - } else { - if (nmax) buf = &array_atom[0][0]; - else buf = nullptr; - for (int n = 0; n < nvalues; n++) - (this->*pack_choice[n])(n); - } -} - -/* ---------------------------------------------------------------------- - memory usage of local atom-based array -------------------------------------------------------------------------- */ - -double ComputeRHEOPropertyAtom::memory_usage() -{ - double bytes = (double)nmax * nvalues * sizeof(double); - return bytes; -} - -/* ---------------------------------------------------------------------- - one method for every keyword compute rheo/property/atom can output - the atom property is packed into buf starting at n with stride nvalues - customize a new keyword by adding a method -------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_phase(int n) -{ - int *status = atom->status; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - int inverse_mask = ~PHASEMASK; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_chi(int n) -{ - double *chi = compute_interface->chi; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = chi[i]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface(int n) -{ - int *status = atom->status; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - int inverse_mask = ~SURFACEMASK; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = (status[i] & inverse_mask); - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface_r(int n) -{ - double *rsurface = compute_surface->rsurface; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = rsurface[i]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface_divr(int n) -{ - double *divr = compute_surface->divr; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = divr[i]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface_nx(int n) -{ - double **nsurface = compute_surface->nsurface; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = nsurface[i][0]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface_ny(int n) -{ - double **nsurface = compute_surface->nsurface; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = nsurface[i][1]; - else buf[n] = 0.0; - n += nvalues; - } -} - - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface_nz(int n) -{ - double **nsurface = compute_surface->nsurface; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = nsurface[i][2]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_coordination(int n) -{ - int *coordination = compute_kernel->coordination; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = coordination[i]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_cv(int n) -{ - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = fix_thermal->calc_cv(i); - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_shift_vx(int n) -{ - double **vshift = compute_vshift->vshift; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = vshift[i][0]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_shift_vy(int n) -{ - double **vshift = compute_vshift->vshift; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = vshift[i][1]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_shift_vz(int n) -{ - double **vshift = compute_vshift->vshift; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = vshift[i][2]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_atom_style(int n) -{ - atom->avec->pack_property_atom(index[n],&buf[n],nvalues,groupbit); -} diff --git a/src/compute_rheo_property_atom.h b/src/compute_rheo_property_atom.h deleted file mode 100644 index accb7e9156..0000000000 --- a/src/compute_rheo_property_atom.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - 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. -------------------------------------------------------------------------- */ - -#ifdef COMPUTE_CLASS -// clang-format off -ComputeStyle(rheo/property/atom,ComputeRHEOPropertyAtom); -// clang-format on -#else - -#ifndef LMP_COMPUTE_RHEO_PROPERTY_ATOM_H -#define LMP_COMPUTE_RHEO_PROPERTY_ATOM_H - -#include "compute.h" - -namespace LAMMPS_NS { - -class ComputeRHEOPropertyAtom : public Compute { - public: - ComputeRHEOPropertyAtom(class LAMMPS *, int, char **); - ~ComputeRHEOPropertyAtom() override; - void init() override; - void compute_peratom() override; - double memory_usage() override; - - private: - int nvalues, nmax; - int thermal_flag, interface_flag, surface_flag, shift_flag; - int *index; - double *buf; - - typedef void (ComputeRHEOPropertyAtom::*FnPtrPack)(int); - FnPtrPack *pack_choice; // ptrs to pack functions - - void pack_phase(int); - void pack_chi(int); - void pack_surface(int); - void pack_surface_r(int); - void pack_surface_divr(int); - void pack_surface_nx(int); - void pack_surface_ny(int); - void pack_surface_nz(int); - void pack_coordination(int); - void pack_cv(int); - void pack_shift_vx(int); - void pack_shift_vy(int); - void pack_shift_vz(int); - void pack_atom_style(int); - - class FixRHEO *fix_rheo; - class FixRHEOThermal *fix_thermal; - class ComputeRHEOInterface *compute_interface; - class ComputeRHEOKernel *compute_kernel; - class ComputeRHEOSurface *compute_surface; - class ComputeRHEOVShift *compute_vshift; - -}; - -} // namespace LAMMPS_NS - -#endif -#endif From b4e1effe5f6e11b1d8d758991cf92ad52e522a2d Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 19 May 2023 13:10:39 -0600 Subject: [PATCH 039/385] Improving options for outputting gradients --- src/RHEO/compute_rheo_grad.cpp | 6 +- src/RHEO/compute_rheo_property_atom.cpp | 171 +++++++++++++----------- src/RHEO/compute_rheo_property_atom.h | 17 ++- src/RHEO/pair_rheo.cpp | 4 + 4 files changed, 112 insertions(+), 86 deletions(-) diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 92ac108377..d71e7a24ac 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -224,9 +224,9 @@ void ComputeRHEOGrad::compute_peratom() Voli = mass[itype] / rhoi; Volj = mass[jtype] / rhoj; - vij[0] = v[i][0] - v[j][0]; - vij[1] = v[i][1] - v[j][1]; - vij[2] = v[i][2] - v[j][2]; + vij[0] = vi[0] - vj[0]; + vij[1] = vi[1] - vj[1]; + vij[2] = vi[2] - vj[2]; if (rho_flag) drho = rhoi - rhoj; if (temperature_flag) dT = temperature[i] - temperature[j]; diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 880ae5d64f..3afeb03e43 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -25,12 +25,15 @@ #include "compute_rheo_kernel.h" #include "compute_rheo_surface.h" #include "compute_rheo_vshift.h" +#include "compute_rheo_grad.h" +#include "domain.h" #include "error.h" #include "fix_rheo.h" #include "fix_rheo_thermal.h" #include "memory.h" #include "modify.h" #include "update.h" +#include "utils.h" #include #include @@ -42,8 +45,8 @@ using namespace RHEO_NS; ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), fix_rheo(nullptr), fix_thermal(nullptr), compute_interface(nullptr), - compute_kernel(nullptr), compute_surface(nullptr), compute_vshift(nullptr), - index(nullptr), pack_choice(nullptr) + compute_kernel(nullptr), compute_surface(nullptr), compute_vshift(nullptr), compute_grad(nullptr), + avec_index(nullptr), pack_choice(nullptr), col_index(nullptr) { if (narg < 4) utils::missing_cmd_args(FLERR, "compute property/atom", error); @@ -58,7 +61,8 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a // customize a new keyword by adding to if statement pack_choice = new FnPtrPack[nvalues]; - index = new int[nvalues]; + avec_index = new int[nvalues]; + col_index = new int[nvalues]; int i; for (int iarg = 3; iarg < narg; iarg++) { @@ -78,32 +82,25 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a } else if (strcmp(arg[iarg],"surface/divr") == 0) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_divr; - } else if (strcmp(arg[iarg],"surface/nx") == 0) { + } else if (strcmp(arg[iarg],"^surface/n") == 0) { surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nx; - } else if (strcmp(arg[iarg],"surface/ny") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_ny; - } else if (strcmp(arg[iarg],"surface/nz") == 0) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_nz; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_n; + col_index[i] = get_vector_index(arg[iarg]); } else if (strcmp(arg[iarg],"coordination") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_coordination; } else if (strcmp(arg[iarg],"cv") == 0) { thermal_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; - } else if (strcmp(arg[iarg],"shift/vx") == 0) { + } else if (strcmp(arg[iarg],"^shift/v") == 0) { shift_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vx; - } else if (strcmp(arg[iarg],"shift/vy") == 0) { - shift_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vy; - } else if (strcmp(arg[iarg],"shift/vz") == 0) { - shift_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_vz; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_v; + col_index[i] = get_vector_index(arg[iarg]); + } else if (utils::strmatch(arg[iarg],"^gradv")) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_gradv; + col_index[i] = get_tensor_index(arg[iarg]); } else { - index[i] = atom->avec->property_atom(arg[iarg]); - if (index[i] < 0) + avec_index[i] = atom->avec->property_atom(arg[iarg]); + if (avec_index[i] < 0) error->all(FLERR, "Invalid keyword {} for atom style {} in compute rheo/property/atom command ", atom->get_style(), arg[iarg]); @@ -123,7 +120,8 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() { delete[] pack_choice; - delete[] index; + delete[] avec_index; + delete[] col_index; memory->destroy(vector_atom); memory->destroy(array_atom); } @@ -149,6 +147,7 @@ void ComputeRHEOPropertyAtom::init() compute_kernel = fix_rheo->compute_kernel; compute_surface = fix_rheo->compute_surface; compute_vshift = fix_rheo->compute_vshift; + compute_grad = fix_rheo->compute_grad; if (thermal_flag) { fixes = modify->get_fix_by_style("rheo/thermal"); @@ -281,45 +280,15 @@ void ComputeRHEOPropertyAtom::pack_surface_divr(int n) /* ---------------------------------------------------------------------- */ -void ComputeRHEOPropertyAtom::pack_surface_nx(int n) +void ComputeRHEOPropertyAtom::pack_surface_n(int n) { double **nsurface = compute_surface->nsurface; int *mask = atom->mask; int nlocal = atom->nlocal; + int index = col_index[n]; for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = nsurface[i][0]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface_ny(int n) -{ - double **nsurface = compute_surface->nsurface; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = nsurface[i][1]; - else buf[n] = 0.0; - n += nvalues; - } -} - - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_surface_nz(int n) -{ - double **nsurface = compute_surface->nsurface; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = nsurface[i][2]; + if (mask[i] & groupbit) buf[n] = nsurface[i][index]; else buf[n] = 0.0; n += nvalues; } @@ -356,14 +325,15 @@ void ComputeRHEOPropertyAtom::pack_cv(int n) /* ---------------------------------------------------------------------- */ -void ComputeRHEOPropertyAtom::pack_shift_vx(int n) +void ComputeRHEOPropertyAtom::pack_shift_v(int n) { double **vshift = compute_vshift->vshift; int *mask = atom->mask; int nlocal = atom->nlocal; + int index = col_index[n]; for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = vshift[i][0]; + if (mask[i] & groupbit) buf[n] = vshift[i][index]; else buf[n] = 0.0; n += nvalues; } @@ -371,29 +341,15 @@ void ComputeRHEOPropertyAtom::pack_shift_vx(int n) /* ---------------------------------------------------------------------- */ -void ComputeRHEOPropertyAtom::pack_shift_vy(int n) +void ComputeRHEOPropertyAtom::pack_gradv(int n) { - double **vshift = compute_vshift->vshift; + double **gradv = compute_grad->gradv; int *mask = atom->mask; int nlocal = atom->nlocal; + int index = col_index[n]; for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = vshift[i][1]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - -void ComputeRHEOPropertyAtom::pack_shift_vz(int n) -{ - double **vshift = compute_vshift->vshift; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = vshift[i][2]; + if (mask[i] & groupbit) buf[n] = gradv[i][index]; else buf[n] = 0.0; n += nvalues; } @@ -403,5 +359,68 @@ void ComputeRHEOPropertyAtom::pack_shift_vz(int n) void ComputeRHEOPropertyAtom::pack_atom_style(int n) { - atom->avec->pack_property_atom(index[n],&buf[n],nvalues,groupbit); + atom->avec->pack_property_atom(avec_index[n],&buf[n],nvalues,groupbit); +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOPropertyAtom::get_tensor_index(char* option) +{ + int index; + int dim = domain->dimension; + int dim_error = 0; + + if (utils::strmatch(option,"xx$")) { + index = 0; + } else if (utils::strmatch(option,"xy$")) { + index = 1; + } else if (utils::strmatch(option,"xz$")) { + index = 2; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option,"yx$")) { + if (dim == 2) index = 2; + else index = 3; + } else if (utils::strmatch(option,"yy$")) { + if (dim == 2) index = 3; + else index = 4; + } else if (utils::strmatch(option,"yz$")) { + index = 5; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option,"zx$")) { + index = 6; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option,"zy$")) { + index = 7; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option,"zz$")) { + index = 8; + if (dim == 2) dim_error = 1; + } else { + error->all(FLERR, "Invalid compute rheo/property/atom property {}", option); + } + + if (dim_error) + error->all(FLERR, "Invalid compute rheo/property/atom property {} in 2D", option); + + return index; +} + +/* ---------------------------------------------------------------------- */ + +int ComputeRHEOPropertyAtom::get_vector_index(char* option) +{ + int index; + if (utils::strmatch(option,"x$")) { + index = 0; + } else if (utils::strmatch(option,"y$")) { + index = 1; + } else if (utils::strmatch(option,"z$")) { + if (domain->dimension == 2) + error->all(FLERR, "Invalid compute rheo/property/atom property {} in 2D", option); + index = 2; + } else { + error->all(FLERR, "Invalid compute rheo/property/atom property {}", option); + } + + return index; } diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index accb7e9156..344e249d11 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -35,7 +35,8 @@ class ComputeRHEOPropertyAtom : public Compute { private: int nvalues, nmax; int thermal_flag, interface_flag, surface_flag, shift_flag; - int *index; + int *avec_index; + int *col_index; double *buf; typedef void (ComputeRHEOPropertyAtom::*FnPtrPack)(int); @@ -46,22 +47,23 @@ class ComputeRHEOPropertyAtom : public Compute { void pack_surface(int); void pack_surface_r(int); void pack_surface_divr(int); - void pack_surface_nx(int); - void pack_surface_ny(int); - void pack_surface_nz(int); + void pack_surface_n(int); void pack_coordination(int); void pack_cv(int); - void pack_shift_vx(int); - void pack_shift_vy(int); - void pack_shift_vz(int); + void pack_shift_v(int); + void pack_gradv(int); void pack_atom_style(int); + int get_vector_index(char*); + int get_tensor_index(char*); + class FixRHEO *fix_rheo; class FixRHEOThermal *fix_thermal; class ComputeRHEOInterface *compute_interface; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOSurface *compute_surface; class ComputeRHEOVShift *compute_vshift; + class ComputeRHEOGrad *compute_grad; }; @@ -69,3 +71,4 @@ class ComputeRHEOPropertyAtom : public Compute { #endif #endif + diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 0930f28f98..8b0e2c2df6 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -257,6 +257,10 @@ void PairRHEO::compute(int eflag, int vflag) mu = MIN(0.0, mu); q = av * (-2.0 * cs * mu + mu * mu); fp_prefactor += voli * volj * q * (rhoj + rhoi); + + if (fabs(fp_prefactor*dWij[0]) > 1e-9) + if (atom->tag[i] == 643 or atom->tag[j] == 643 or atom->tag[i] == 963 or atom->tag[j] == 963) + printf("%d-%d (%d %d) fp_prefactor %g %g %g\n", atom->tag[i], atom->tag[j], i, j, fp_prefactor, dWij[0], -fp_prefactor*dWij[0]); } // -Grad[P + Q] From 6f59b7c5e081e2750dafed7530dad62a09e99fdc Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 23 May 2023 22:12:34 -0600 Subject: [PATCH 040/385] Fixing misc bugs with interfaces --- doc/src/fix_rheo.rst | 2 +- src/RHEO/compute_rheo_grad.cpp | 7 ++-- src/RHEO/compute_rheo_interface.cpp | 16 ++++---- src/RHEO/fix_rheo.cpp | 8 +++- src/RHEO/fix_rheo_pressure.cpp | 19 ++-------- src/RHEO/pair_rheo.cpp | 58 +++++++++++++++++++++++++---- src/RHEO/pair_rheo.h | 2 + 7 files changed, 77 insertions(+), 35 deletions(-) diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 7aaab48f54..5eae617419 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -23,7 +23,7 @@ Syntax *surface/detection* values = *sdstyle* *limit* *sdstyle* = *coordination* or *divergence* *limit* = threshold for surface particles (unitless) - *interface/reconstruction* values = none, reconstructs interfaces with solid particles + *interface/reconstruct* values = none, reconstructs interfaces with solid particles *rho/sum* values = none, uses the kernel to compute the density of particles *density* values = *rho0* (density) *sound/squared* values = *csq* (velocity\^2) diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index d71e7a24ac..7d0b1d5b14 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -179,9 +179,6 @@ void ComputeRHEOGrad::compute_peratom() xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; - vi[0] = v[i][0]; - vi[1] = v[i][1]; - vi[2] = v[i][2]; itype = type[i]; fluidi = !(status[i] & PHASECHECK); jlist = firstneigh[i]; @@ -203,6 +200,10 @@ void ComputeRHEOGrad::compute_peratom() rhoi = rho[i]; rhoj = rho[j]; + vi[0] = v[i][0]; + vi[1] = v[i][1]; + vi[2] = v[i][2]; + vj[0] = v[j][0]; vj[1] = v[j][1]; vj[2] = v[j][2]; diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index ea4916087f..8cd69b49e3 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -170,9 +170,10 @@ void ComputeRHEOInterface::compute_peratom() chi[i] += w; } else { if (!fluidi) { - dot = (-fp_store[0][j] + fp_store[0][i]) * delx; - dot += (-fp_store[1][j] + fp_store[1][i]) * dely; - dot += (-fp_store[2][j] + fp_store[2][i]) * delz; + dot = (-fp_store[j][0] + fp_store[i][0]) * delx; + dot += (-fp_store[j][1] + fp_store[i][1]) * dely; + dot += (-fp_store[j][2] + fp_store[i][2]) * delz; + rho[i] += w * (csq * (rho[j] - rho0) - rho[j] * dot); normwf[i] += w; } @@ -184,9 +185,10 @@ void ComputeRHEOInterface::compute_peratom() chi[j] += w; } else { if (!fluidj) { - dot = (-fp_store[0][i] + fp_store[0][j]) * delx; - dot += (-fp_store[1][i] + fp_store[1][j]) * dely; - dot += (-fp_store[2][i] + fp_store[2][j]) * delz; + dot = (-fp_store[i][0] + fp_store[j][0]) * delx; + dot += (-fp_store[i][1] + fp_store[j][1]) * dely; + dot += (-fp_store[i][2] + fp_store[j][2]) * delz; + rho[j] += w * (csq * (rho[i] - rho0) + rho[i] * dot); normwf[j] += w; } @@ -342,7 +344,7 @@ void ComputeRHEOInterface::store_forces() // If forces are overwritten by a fix, there are no pressure forces // so just normalize auto fixlist = modify->get_fix_by_style("setforce"); - if (fixlist.size() == 0) { + if (fixlist.size() != 0) { for (const auto &fix : fixlist) { for (int i = 0; i < atom->nlocal; i++) { minv = 1.0 / mass[type[i]]; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index fd436cab6e..cecd3183fd 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -105,7 +105,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : } iarg += 2; - } else if (strcmp(arg[iarg],"interface/reconstruction") == 0) { + } else if (strcmp(arg[iarg],"interface/reconstruct") == 0) { interface_flag = 1; } else if (strcmp(arg[iarg],"rho/sum") == 0) { rhosum_flag = 1; @@ -360,6 +360,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) } if (!rhosum_flag) { + if (status[i] & PHASECHECK) continue; for (a = 0; a < dim; a++) { rho[i] += dtv * vshift[i][a] * gradr[i][a]; } @@ -380,7 +381,10 @@ void FixRHEO::pre_force(int /*vflag*/) compute_grad->forward_fields(); // also forwards v and rho for chi compute_kernel->compute_peratom(); - if (interface_flag) compute_interface->compute_peratom(); + if (interface_flag) { + // Note on first setup, have no forces for pressure to reference + compute_interface->compute_peratom(); + } compute_grad->compute_peratom(); compute_grad->forward_gradients(); diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index ff206937f4..84d21ee872 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -122,20 +122,9 @@ void FixRHEOPressure::pre_force(int /*vflag*/) int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) { - if (pressure_style == LINEAR) { - pressure[i] = csq * (rho[i] - rho0); - } else if (pressure_style == CUBIC) { - dr = rho[i] - rho0; - pressure[i] = csq * (dr + c_cubic * dr * dr * dr); - } else if (pressure_style == TAITWATER) { - rho_ratio = rho[i] / rho0inv; - rr3 = rho_ratio * rho_ratio * rho_ratio; - pressure[i] = csq * rho0 * SEVENTH * (rr3 * rr3 * rho_ratio - 1.0); - } - } - } + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + pressure[i] = calc_pressure(rho[i]); if (comm_forward) comm->forward_comm(this); } @@ -186,5 +175,5 @@ double FixRHEOPressure::calc_pressure(double rho) rr3 = rho_ratio * rho_ratio * rho_ratio; p = csq * rho0 * SEVENTH * (rr3 * rr3 * rho_ratio - 1.0); } - return rho; + return p; } diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 8b0e2c2df6..0feb6af445 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -56,6 +56,8 @@ PairRHEO::PairRHEO(LAMMPS *lmp) : artificial_visc_flag = 0; rho_damp_flag = 0; thermal_flag = 0; + + comm_reverse = 3; } /* ---------------------------------------------------------------------- */ @@ -79,7 +81,7 @@ void PairRHEO::compute(int eflag, int vflag) double rhoi, rhoj, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj; double mu, q, fp_prefactor, drho_damp, fmag, psi_ij, Fij; double *dWij, *dWji, *dW1ij, *dW1ji; - double dx[3], du[3], fv[3], dfp[3], fsolid[3], ft[3], vi[3], vj[3]; + double dx[3], du[3], dv[3], fv[3], dfp[3], fsolid[3], ft[3], vi[3], vj[3]; int *ilist, *jlist, *numneigh, **firstneigh; double imass, jmass, rsq, r, rinv; @@ -113,6 +115,12 @@ void PairRHEO::compute(int eflag, int vflag) if (compute_interface) { fp_store = compute_interface->fp_store; chi = compute_interface->chi; + + for (i = 0; i < atom->nmax; i++) { + fp_store[i][0] = 0.0; + fp_store[i][1] = 0.0; + fp_store[i][2] = 0.0; + } } inum = list->inum; @@ -243,11 +251,12 @@ void PairRHEO::compute(int eflag, int vflag) //Hydrostatic pressure forces fp_prefactor = voli * volj * (Pj + Pi); - sub3(vi, vj, du); + sub3(vi, vj, dv); //Add artificial viscous pressure if required if (artificial_visc_flag && pair_avisc_flag) { //Interpolate velocities to midpoint and use this difference for artificial viscosity + copy3(dv, du); for (a = 0; a < dim; a++) for (b = 0; b < dim; b++) du[a] -= 0.5 * (gradv[i][a * dim + b] + gradv[j][a * dim + b]) * dx[b]; @@ -257,10 +266,6 @@ void PairRHEO::compute(int eflag, int vflag) mu = MIN(0.0, mu); q = av * (-2.0 * cs * mu + mu * mu); fp_prefactor += voli * volj * q * (rhoj + rhoi); - - if (fabs(fp_prefactor*dWij[0]) > 1e-9) - if (atom->tag[i] == 643 or atom->tag[j] == 643 or atom->tag[i] == 963 or atom->tag[j] == 963) - printf("%d-%d (%d %d) fp_prefactor %g %g %g\n", atom->tag[i], atom->tag[j], i, j, fp_prefactor, dWij[0], -fp_prefactor*dWij[0]); } // -Grad[P + Q] @@ -270,7 +275,7 @@ void PairRHEO::compute(int eflag, int vflag) for (a = 0; a < dim; a++) { fv[a] = 0.0; for (b = 0; b < dim; b++) - fv[a] += du[a] * dx[b] * dWij[b]; + fv[a] += dv[a] * dx[b] * dWij[b]; fv[a] *= (etai + etaj) * voli * volj * rinv * rinv; } @@ -346,6 +351,11 @@ void PairRHEO::compute(int eflag, int vflag) } if (vflag_fdotr) virial_fdotr_compute(); + + if (compute_interface) { + comm->reverse_comm(this); + comm->forward_comm(this); + } } /* ---------------------------------------------------------------------- @@ -476,3 +486,37 @@ double PairRHEO::init_one(int i, int j) return h; } + +/* ---------------------------------------------------------------------- */ + +int PairRHEO::pack_reverse_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double **fp_store = compute_interface->fp_store; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = fp_store[i][0]; + buf[m++] = fp_store[i][1]; + buf[m++] = fp_store[i][2]; + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEO::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i, j, k, m; + double **fp_store = compute_interface->fp_store; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + fp_store[j][0] += buf[m++]; + fp_store[j][1] += buf[m++]; + fp_store[j][2] += buf[m++]; + } +} diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index b30b0c3c04..cb2227c8d6 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -33,6 +33,8 @@ class PairRHEO : public Pair { void coeff(int, char **) override; void setup() override; double init_one(int, int) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; protected: double h, csq, rho0; // From fix RHEO From 4ae41edee791755613786a91b4058084af5b4332 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 23 Jun 2023 14:12:59 -0600 Subject: [PATCH 041/385] Fixing order of correct_v --- .../PACKAGES/rheo/dam-break/in.rheo.dam.break | 87 +++++++++++++++++++ .../rheo/poiseuille/in.rheo.poiseuille | 16 ++-- .../rheo/taylor-green/in.rheo.taylor.green | 74 ++++++++++++++++ src/RHEO/compute_rheo_grad.cpp | 2 + src/RHEO/compute_rheo_surface.cpp | 4 +- src/RHEO/compute_rheo_vshift.cpp | 2 + src/RHEO/fix_rheo.cpp | 2 +- src/RHEO/pair_rheo.cpp | 2 + 8 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 examples/PACKAGES/rheo/dam-break/in.rheo.dam.break create mode 100644 examples/PACKAGES/rheo/taylor-green/in.rheo.taylor.green diff --git a/examples/PACKAGES/rheo/dam-break/in.rheo.dam.break b/examples/PACKAGES/rheo/dam-break/in.rheo.dam.break new file mode 100644 index 0000000000..207fd6885e --- /dev/null +++ b/examples/PACKAGES/rheo/dam-break/in.rheo.dam.break @@ -0,0 +1,87 @@ +# ------ 2D dam break ------ # + +dimension 2 +units lj +atom_style rheo +boundary f s p +comm_modify vel yes +newton off +comm_style tiled + + +# ------ Create simulation box ------ # + +variable sf equal 0.05 +variable n equal 1.0/(${sf}^2) +variable cut equal 3.0*${sf} + +region box block -1 55 -1 20 -0.01 0.01 units box +create_box 2 box +lattice sq ${n} + +region left_wall block -1 0 EDGE EDGE -0.01 0.01 units box +region right_wall block 53.66 EDGE EDGE EDGE -0.01 0.01 units box +region bot_wall block 0.01 53.65 -1 0 -0.01 0.01 units box +region interior block 0.01 10 0.01 20 -0.01 0.01 units box + +create_atoms 1 region interior +create_atoms 2 region left_wall +create_atoms 2 region right_wall +create_atoms 2 region bot_wall + +group fluid type 1 +group static_wall type 2 +group dyn_wall type 3 +group rig union static_wall dyn_wall + + +# ------ Model parameters ------ # + +variable rho0 equal 1.0 +variable mp equal ${rho0}/${n} +variable cs equal 10 +variable zeta equal 1 +variable Dr equal 0.1*${cut}*${cs} +variable dt_max equal 0.1*${cut}/${cs}/3 +variable g equal 0.0245 +variable fext equal ${g}/${n} +variable eta equal 0.05 + +mass * ${mp} +variable d0 atom (${rho0}*${g}*(20-y)/${cs}/${cs})+${rho0} +set group all rheo/rho ${rho0} +set group fluid rheo/rho v_d0 + +set group all rheo/status 0 +set group rig rheo/status 2 + +timestep ${dt_max} + +pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} +pair_coeff * * + + +# ------ Fixes & computes ------ # + +fix 1 all rheo ${cut} RK1 32 shift surface/detection coordination 26 +fix 2 all rheo/viscosity constant ${eta} +fix 3 all rheo/pressure linear +fix 4 rig setforce 0.0 0.0 0.0 +fix 5 fluid addforce 0.0 -${fext} 0.0 +fix 6 all balance 1000 1.1 rcb + +compute 1 all rheo/property/atom rho phase surface + + +# ------ Output & Run ------ # + +thermo 10 +thermo_style custom step time ke press + +variable skin equal 0.2*${cut} +neighbor ${skin} bin +neigh_modify one 5000 + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] + +run 400000 diff --git a/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille b/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille index d0f966c2ce..6f5ad91e73 100644 --- a/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille +++ b/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille @@ -1,3 +1,5 @@ +# ------ 2D Poiseuille flow ------ # + dimension 2 units lj atom_style rheo @@ -5,16 +7,12 @@ boundary p p p comm_modify vel yes -# ------ Particle Lattice/Resolution Parameters ------ # +# ------ Create simulation box ------ # -variable L equal 10 variable sf equal 0.2 variable n equal 1.0/(${sf}^2) variable cut equal 3.5*${sf} - -# ------ Create simulation box ------ # - region box block 0 20 -10 10 -0.01 0.01 units box create_box 2 box lattice sq ${n} @@ -46,11 +44,11 @@ variable eta equal 0.1 variable dt_max equal 0.1*${cut}/${cs}/3 variable Dr equal 0.05*${cut}*${cs} -mass 1 ${mp} -mass 2 ${mp} +mass * ${mp} set group all rheo/rho ${rho0} set group all rheo/status 0 set group rig rheo/status 2 + timestep ${dt_max} pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} @@ -71,13 +69,13 @@ compute 1 all rheo/property/atom rho phase # ------ Output & Run ------ # thermo 200 -thermo_style custom step time temp press +thermo_style custom step time ke press variable skin equal 0.2*${cut} neighbor ${skin} bin neigh_modify one 5000 -dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] run 20000 diff --git a/examples/PACKAGES/rheo/taylor-green/in.rheo.taylor.green b/examples/PACKAGES/rheo/taylor-green/in.rheo.taylor.green new file mode 100644 index 0000000000..5367ceef13 --- /dev/null +++ b/examples/PACKAGES/rheo/taylor-green/in.rheo.taylor.green @@ -0,0 +1,74 @@ +# ------ 2D Taylor Green vortex ------ # + +dimension 2 +units lj +atom_style rheo +boundary p p p +comm_modify vel yes +newton off + + +# ------ Create simulation box ------ # + +variable sf equal 0.1 +variable n equal 1.0/(${sf}^2) +variable cut equal 3.5*${sf} + +region box block 0 10 0 10 -0.01 0.01 units box +create_box 1 box +lattice sq ${n} + +create_atoms 1 region box + +variable dr equal 0.1*${sf} +displace_atoms all random ${dr} ${dr} 0 135414 units box + + +# ------ Model parameters ------ # + +variable rho0 equal 1.0 +variable mp equal ${rho0}/${n} +variable cs equal 1.0 +variable eta equal 0.05 +variable zeta equal 1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable Dr equal 0.1*${cut}*${cs} + +mass * ${mp} +set group all rheo/rho ${rho0} +set group all rheo/status 0 + +variable u0 equal 0.05 +variable uy atom ${u0}*sin(2*PI*x/lx)*cos(2*PI*y/ly) +variable ux atom -${u0}*sin(2*PI*y/ly)*cos(2*PI*x/ly) +variable d0 atom ${rho0}-${u0}*${u0}*${rho0}*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/${cs}/${cs} + +velocity all set v_ux v_uy 0.0 units box + +timestep ${dt_max} + +pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} +pair_coeff * * + + +# ------ Fixes & computes ------ # + +fix 1 all rheo ${cut} quintic 0 shift +fix 2 all rheo/viscosity constant ${eta} +fix 3 all rheo/pressure linear + +compute 1 all rheo/property/atom rho phase + + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press + +variable skin equal 0.2*${cut} +neighbor ${skin} bin +neigh_modify one 10000 #increase number of allowed neighbors + +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] + +run 10000 \ No newline at end of file diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 7d0b1d5b14..369bf11e0d 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -212,9 +212,11 @@ void ComputeRHEOGrad::compute_peratom() if (interface_flag) { if (fluidi && (!fluidj)) { compute_interface->correct_v(vi, vj, i, j); + //compute_interface->correct_v(vj, vi, j, i); rhoj = compute_interface->correct_rho(j, i); } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vj, vi, j, i); + //compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { rhoi = rho0; diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index f6b93ee551..4b0745abd3 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -126,7 +126,7 @@ void ComputeRHEOSurface::compute_peratom() { int i, j, ii, jj, inum, jnum, a, b, itype, jtype, fluidi, fluidj; double xtmp, ytmp, ztmp, rsq, Voli, Volj, rhoi, rhoj, wp; - double *dWij, *dWji, dx[3]; + double dWij[3], dWji[3], dx[3]; int *ilist, *jlist, *numneigh, **firstneigh; int nlocal = atom->nlocal; @@ -214,7 +214,7 @@ void ComputeRHEOSurface::compute_peratom() Voli = mass[itype] / rhoi; Volj = mass[jtype] / rhoj; - wp = compute_kernel->calc_dw_quintic(i, j, dx[0], dx[1], dx[2], sqrt(rsq),dWij, dWji); + wp = compute_kernel->calc_dw_quintic(i, j, dx[0], dx[1], dx[2], sqrt(rsq), dWij, dWji); for (a = 0; a < dim; a++){ divr[i] -= dWij[a] * dx[a] * Volj; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 0521ff16c0..9741026324 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -171,9 +171,11 @@ void ComputeRHEOVShift::compute_peratom() if (interface_flag) { if (fluidi && (!fluidj)) { compute_interface->correct_v(vi, vj, i, j); + //compute_interface->correct_v(vj, vi, j, i); rhoj = compute_interface->correct_rho(j,i); } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vj, vi, j, i); + //compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i,j); } else if ((!fluidi) && (!fluidj)) { rhoi = 1.0; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index cecd3183fd..0420a0f23f 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -154,7 +154,7 @@ void FixRHEO::post_constructor() if (rhosum_flag) { compute_rhosum = dynamic_cast(modify->add_compute( - "rheo_rho_sum all RHEO/RHO/SUM")); + "rheo_rhosum all RHEO/RHO/SUM")); compute_rhosum->fix_rheo = this; } diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 0feb6af445..e22715eab1 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -207,6 +207,7 @@ void PairRHEO::compute(int eflag, int vflag) if (interface_flag) { if (fluidi && (!fluidj)) { compute_interface->correct_v(vi, vj, i, j); + //compute_interface->correct_v(vj, vi, j, i); rhoj = compute_interface->correct_rho(j, i); Pj = fix_pressure->calc_pressure(rhoj); @@ -215,6 +216,7 @@ void PairRHEO::compute(int eflag, int vflag) } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vj, vi, j, i); + //compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i, j); Pi = fix_pressure->calc_pressure(rhoi); From 71abebb1d7173a5fe0b1c38903f65a3ebc4b7905 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 16 Jul 2023 16:26:57 -0600 Subject: [PATCH 042/385] debugging surface compute --- doc/src/fix_rheo.rst | 3 ++- src/RHEO/compute_rheo_surface.cpp | 24 ++++++++++++++---------- src/RHEO/compute_rheo_surface.h | 2 +- src/RHEO/fix_rheo.cpp | 4 +++- src/RHEO/fix_rheo.h | 2 +- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 5eae617419..25e171a1b9 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -20,9 +20,10 @@ Syntax *shift* values = none, turns on velocity shifting *thermal* values = none, turns on thermal evolution - *surface/detection* values = *sdstyle* *limit* + *surface/detection* values = *sdstyle* *limit* *limit/splash* *sdstyle* = *coordination* or *divergence* *limit* = threshold for surface particles (unitless) + *limit/splash* = threshold for splash particles (unitless) *interface/reconstruct* values = none, reconstructs interfaces with solid particles *rho/sum* values = none, uses the kernel to compute the density of particles *density* values = *rho0* (density) diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 4b0745abd3..230bca8219 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -82,6 +82,8 @@ void ComputeRHEOSurface::init() threshold_style = fix_rheo->surface_style; threshold_divr = fix_rheo->divr_surface; threshold_z = fix_rheo->zmin_surface; + threshold_splash = fix_rheo->zmin_splash; + interface_flag = fix_rheo->interface_flag; cutsq = cut * cut; @@ -202,13 +204,15 @@ void ComputeRHEOSurface::compute_peratom() rhoj = rho[j]; // Add corrections for walls - if (fluidi && (!fluidj)) { - rhoj = compute_interface->correct_rho(j, i); - } else if ((!fluidi) && fluidj) { - rhoi = compute_interface->correct_rho(i, j); - } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0; - rhoj = rho0; + if (interface_flag) { + if (fluidi && (!fluidj)) { + rhoj = compute_interface->correct_rho(j, i); + } else if ((!fluidi) && fluidj) { + rhoi = compute_interface->correct_rho(i, j); + } else if ((!fluidi) && (!fluidj)) { + rhoi = rho0; + rhoj = rho0; + } } Voli = mass[itype] / rhoi; @@ -262,7 +266,7 @@ void ComputeRHEOSurface::compute_peratom() if (divr[i] < threshold_divr) { status[i] |= STATUS_SURFACE; rsurface[i] = 0.0; - if (coordination[i] < threshold_z) + if (coordination[i] < threshold_splash) status[i] |= STATUS_SPLASH; } } @@ -272,10 +276,10 @@ void ComputeRHEOSurface::compute_peratom() if (mask[i] & groupbit) { status[i] |= STATUS_BULK; rsurface[i] = cut; - if (coordination[i] < threshold_divr) { + if (coordination[i] < threshold_z) { status[i] |= STATUS_SURFACE; rsurface[i] = 0.0; - if (coordination[i] < threshold_z) + if (coordination[i] < threshold_splash) status[i] |= STATUS_SPLASH; } } diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 220f8beb6d..1d1cdba3fa 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -41,7 +41,7 @@ class ComputeRHEOSurface : public Compute { private: double cut, cutsq, rho0, threshold_divr; - int surface_style, nmax_store, threshold_z; + int surface_style, nmax_store, threshold_z, threshold_splash, interface_flag; double **B, **gradC; int threshold_style, comm_stage; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 0420a0f23f..339d7f5ac8 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -97,14 +97,16 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg + 1], "coordination")) { surface_style = COORDINATION; zmin_surface = utils::inumeric(FLERR,arg[iarg + 2],false,lmp); + zmin_splash = utils::inumeric(FLERR,arg[iarg + 3],false,lmp); } else if (strcmp(arg[iarg + 1], "divergence")) { surface_style = DIVR; divr_surface = utils::numeric(FLERR,arg[iarg + 2],false,lmp); + zmin_splash = utils::inumeric(FLERR,arg[iarg + 3],false,lmp); } else { error->all(FLERR,"Illegal surface/detection option in fix rheo, {}", arg[iarg + 1]); } - iarg += 2; + iarg += 3; } else if (strcmp(arg[iarg],"interface/reconstruct") == 0) { interface_flag = 1; } else if (strcmp(arg[iarg],"rho/sum") == 0) { diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 0dbc8db78b..96f4b6f502 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -40,7 +40,7 @@ class FixRHEO : public Fix { // Model parameters double h, cut, rho0, csq; - int zmin_kernel, zmin_surface; + int zmin_kernel, zmin_surface, zmin_splash; int kernel_style, surface_style; double divr_surface; From 583917b194a50effe37047db10de2346be9b0562 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 25 Sep 2023 09:39:29 -0600 Subject: [PATCH 043/385] Drafting structure of solidification bond creation --- src/RHEO/fix_rheo.h | 3 +- src/RHEO/fix_rheo_thermal.cpp | 118 +++++++++++++++++++++++++++++++++- src/RHEO/fix_rheo_thermal.h | 10 +++ 3 files changed, 128 insertions(+), 3 deletions(-) diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 0dbc8db78b..9acf30e4fc 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -86,7 +86,8 @@ namespace RHEO_NS { // Temporary status options - reset in preforce STATUS_NO_SHIFT = 1 << 6, STATUS_NO_INTEGRATION = 1 << 7, - STATUS_FREEZING = 1 << 8 + STATUS_FREEZING = 1 << 8, + STATUS_MELTING = 1 << 9 }; // Masks and their inverses diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index de88b4f8d0..837cea6de4 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -29,6 +29,8 @@ #include "math_extra.h" #include "memory.h" #include "modify.h" +#include "neigh_list.h" +#include "pair.h" #include "update.h" using namespace LAMMPS_NS; @@ -47,6 +49,8 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : Tc_style = NONE; cv_style = NONE; conductivity_style = NONE; + cut_bond = 0; + comm_forward = 0; int ntypes = atom->ntypes; int iarg = 3; @@ -95,7 +99,7 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : } } else if (strcmp(arg[iarg],"Tfreeze") == 0) { // T freeze arguments - if (iarg+1 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); + if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); if (strcmp(arg[iarg + 1],"constant") == 0) { if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); Tc_style = CONSTANT; @@ -105,7 +109,7 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg + 1],"type") == 0) { if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); Tc_style = TYPE; - memory->create(Tc_type,ntypes + 1,"rheo_thermal:Tc_type"); + memory->create(Tc_type, ntypes + 1, "rheo_thermal:Tc_type"); for (int i = 1; i <= ntypes; i++) { Tc_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i],false,lmp); if (Tc_type[i] < 0.0) error->all(FLERR,"The melting temperature must be positive"); @@ -114,6 +118,12 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } + } else if (strcmp(arg[iarg],"react") == 0) { + if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for react option"); + cut_bond = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + comm_forward = 1; + if (cut_bond <= 0.0) error->all(FLERR, "Illegal value for bond lengths"); + iarg += 1; } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg]); } @@ -172,6 +182,31 @@ void FixRHEOThermal::init() error->all(FLERR,"fix rheo/thermal command requires atom property heatflow"); if (atom->conductivity_flag != 1) error->all(FLERR,"fix rheo/thermal command requires atom property conductivity"); + + + if (cut_bond > 0.0) { + if (!force->bond) error->all(FLERR,"Must define a bond style to use reactive bond generation with fix rheo/thermal"); + if (!atom->avec->bonds_allow) error->all(FLERR, "Reactive bond generation in fix rheo/thermal requires atom bonds"); + + // all special weights must be 1.0, RHEO pair styles filter by status + if (force->special_lj[0] != 1.0 || force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) + error->all(FLERR, "Reactive bond generation in fix rheo/thermal requires special weights of 1.0"); + + // need a half neighbor list, built only when particles freeze + auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL); + req->set_cutoff(cut_bond); + + // find instances of bond history to delete data + histories = modify->get_fix_by_style("BOND_HISTORY"); + n_histories = histories.size(); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; } /* ---------------------------------------------------------------------- */ @@ -180,6 +215,9 @@ void FixRHEOThermal::setup_pre_force(int /*vflag*/) { fix_rheo->thermal_fix_defined = 1; + if (modify->get_fix_by_style("rheo/thermal").size() > 1) + error->all(FLERR, "More than one fix rheo/thermal defined"); + post_neighbor(); pre_force(0); } @@ -228,6 +266,8 @@ void FixRHEOThermal::post_integrate() double cvi, Tci, Ti; + int phase_changes = 0; + //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { if (mask[i] & groupbit) { @@ -248,6 +288,8 @@ void FixRHEOThermal::post_integrate() // If solid, melt if (status[i] & STATUS_SOLID) { status[i] &= PHASEMASK; + status[i] |= STATUS_MELTING; + phase_changes += 1; } } else { // If fluid, freeze @@ -255,11 +297,22 @@ void FixRHEOThermal::post_integrate() status[i] &= PHASEMASK; status[i] |= STATUS_SOLID; status[i] |= STATUS_FREEZING; + phase_changes += 1; } } } } } + + if (cut_bond > 0 && phase_changes != 0) { + // Forward status then delete/create bonds + comm->forward_comm(this); + + for (int i = 0; i < atom->nlocal; i++) { + if (status[i] & STATUS_MELTING) delete_bonds(i); + if (status[i] & STATUS_FREEZING) create_bonds(i); + } + } } /* ---------------------------------------------------------------------- @@ -324,6 +377,36 @@ void FixRHEOThermal::reset_dt() /* ---------------------------------------------------------------------- */ +void FixRHEOThermal::break_bonds(int i) +{ + int m, k, j; + + int *status = atom->status; + int **bond_type = atom->bond_type; + tagint **bond_atom = atom->bond_atom; + int *num_bond = atom->num_bond; + + for (m = 0; m < num_bond[i]; m++) { + j = bond_atom[i][k]; + if (n_histories > 0) + for (auto &ihistory: histories) + dynamic_cast(ihistory)->delete_history(i,num_bond[i]-1); + + Search for bond in js list and delete + } + + num_bond[i] = 0; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::create_bonds(int i) +{ + +} + +/* ---------------------------------------------------------------------- */ + double FixRHEOThermal::calc_cv(int i) { if (cv_style == CONSTANT) { @@ -332,3 +415,34 @@ double FixRHEOThermal::calc_cv(int i) return(cv_type[atom->type[i]]); } } + + +/* ---------------------------------------------------------------------- */ + +int FixRHEOThermal::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i, j, k, m; + int *status = atom->status; + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(status[j]).d; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + int *status = atom->status; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + status[i] = (int) ubuf(buf[m++]).i + } +} diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index a27ad98a8c..f732a2d728 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -30,12 +30,15 @@ class FixRHEOThermal : public Fix { ~FixRHEOThermal() override; int setmask() override; void init() override; + void init_list(int, class NeighList *) override; void setup_pre_force(int) override; void initial_integrate(int) override; void post_integrate() override; void post_neighbor() override; void pre_force(int) override; void final_integrate() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; void reset_dt() override; double calc_cv(int); @@ -44,15 +47,22 @@ class FixRHEOThermal : public Fix { double *Tc_type, Tc; double *kappa_type, kappa; double dtf, dtv; + double cut_bond; int Tc_style; int cv_style; int conductivity_style; + class NeighList *list; + + int n_histories; + const std::vector histories; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; class ComputeRHEOVShift *compute_vshift; void grow_array(int); + void break_bonds(int); + void create_bonds(int); }; } // namespace LAMMPS_NS From 3cae238eb5bdc26ade047a4789c7e157fbf33cfa Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 26 Sep 2023 09:07:44 -0600 Subject: [PATCH 044/385] Finish drafting bond creation/deletion --- src/RHEO/fix_rheo_thermal.cpp | 82 ++++++++++++++++++++++++++++++++--- src/RHEO/fix_rheo_thermal.h | 1 + 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 837cea6de4..f6fa95b3b7 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -25,6 +25,8 @@ #include "domain.h" #include "error.h" #include "fix_rheo.h" +#include "fix_bond_history.h" +#include "fix_update_special_bonds.h" #include "force.h" #include "math_extra.h" #include "memory.h" @@ -42,7 +44,7 @@ enum {NONE, CONSTANT, TYPE}; FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), compute_vshift(nullptr), - Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr) + Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), fix_update_special_bonds(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -188,9 +190,12 @@ void FixRHEOThermal::init() if (!force->bond) error->all(FLERR,"Must define a bond style to use reactive bond generation with fix rheo/thermal"); if (!atom->avec->bonds_allow) error->all(FLERR, "Reactive bond generation in fix rheo/thermal requires atom bonds"); - // all special weights must be 1.0, RHEO pair styles filter by status - if (force->special_lj[0] != 1.0 || force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) - error->all(FLERR, "Reactive bond generation in fix rheo/thermal requires special weights of 1.0"); + // all special weights must be 1.0 (no special neighbors) or there must be an instance of fix update/special/bonds + if (force->special_lj[0] != 1.0 || force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) { + auto fixes = modify->get_fix_by_style("UPDATE_SPECIAL_BONDS"); + if (fixes.size == 0) error->all(FLERR, "Without fix update/special/bonds, reactive bond generation in fix rheo/thermal requires special weights of 1.0"); + fix_update_special_bonds = dynamic_cast(fixes[0]); + } // need a half neighbor list, built only when particles freeze auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL); @@ -379,20 +384,40 @@ void FixRHEOThermal::reset_dt() void FixRHEOThermal::break_bonds(int i) { - int m, k, j; + int m, n, nmax, j; + tagint *tag = atom->tag; int *status = atom->status; int **bond_type = atom->bond_type; tagint **bond_atom = atom->bond_atom; int *num_bond = atom->num_bond; for (m = 0; m < num_bond[i]; m++) { - j = bond_atom[i][k]; + j = bond_atom[i][m]; if (n_histories > 0) for (auto &ihistory: histories) dynamic_cast(ihistory)->delete_history(i,num_bond[i]-1); - Search for bond in js list and delete + if (fix_update_special_bonds) fix_update_special_bonds->add_broken_bond(i,j); + + if (j >= atom->nlocal) continue; + + for (n = 0; n < num_bond[j]; n++) { + if (bond_atom[j][n] == tag[i]) { + bond_type[j][n] = 0; + nmax = num_bond[j] - 1; + bond_type[j][n] = bond_type[j][nmax]; + bond_atom[j][n] = bond_atom[j][nmax]; + if (n_histories > 0) { + for (auto &ihistory: histories) { + dynamic_cast(ihistory)->shift_history(j, n, nmax); + dynamic_cast(ihistory)->delete_history(j, nmax); + } + } + num_bond[j]--; + break; + } + } } num_bond[i] = 0; @@ -402,7 +427,50 @@ void FixRHEOThermal::break_bonds(int i) void FixRHEOThermal::create_bonds(int i) { + int i1, i2, j, jj, jnum; + int *jlist, *numneigh, **firstneigh; + double rsq; + int nlocal = atom->nlocal; + + tagint *tag = atom->tag; + double *x = atom->x; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + int *status = atom->status; + int **bond_type = atom->bond_type; + tagint **bond_atom = atom->bond_atom; + int *num_bond = atom->num_bond; + + double xtmp = x[i][0]; + double ytmp = x[i][1]; + double ztmp = x[i][2]; + double delx, dely, delz; + + // Loop through atoms of owned atoms + jlist = firstneigh[i]; + jnum = numneigh[i]; + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= SPECIALMASK; + if (status[j] & STATUS_SOLID) { + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + if (rsq > cut_bond) continue; + + if (!newton_bond || tag[i] < tag[j]) { + if (num_bond[i] == atom->bond_per_atom) + error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); + if (fix_update_special_bonds) fix_update_special_bonds->add_created_bond(i,j); + bond_type[i][num_bond[i]] = btype; + bond_atom[i][num_bond[i]] = tag[j]; + num_bond[i]++; + } + } + } } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index f732a2d728..13b743b939 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -59,6 +59,7 @@ class FixRHEOThermal : public Fix { class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; class ComputeRHEOVShift *compute_vshift; + class FixUpdateSpecialBonds *fix_update_special_bonds; void grow_array(int); void break_bonds(int); From 1cbe59c254989631df6bffde3a767c98896e3b2a Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 5 Oct 2023 21:19:50 -0600 Subject: [PATCH 045/385] Fixing compile errors --- src/RHEO/fix_rheo_thermal.cpp | 20 +++++++++++++------- src/RHEO/fix_rheo_thermal.h | 8 +++++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index f6fa95b3b7..48a22a5419 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -19,6 +19,7 @@ #include "fix_rheo_thermal.h" #include "atom.h" +#include "atom_vec.h" #include "comm.h" #include "compute_rheo_grad.h" #include "compute_rheo_vshift.h" @@ -31,7 +32,9 @@ #include "math_extra.h" #include "memory.h" #include "modify.h" +#include "neighbor.h" #include "neigh_list.h" +#include "neigh_request.h" #include "pair.h" #include "update.h" @@ -121,11 +124,13 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } } else if (strcmp(arg[iarg],"react") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for react option"); + if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for react option"); cut_bond = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + btype = utils::numeric(FLERR, arg[iarg + 2], false, lmp); comm_forward = 1; - if (cut_bond <= 0.0) error->all(FLERR, "Illegal value for bond lengths"); - iarg += 1; + if (cut_bond <= 0.0) error->all(FLERR, "Illegal value for bond lengths");\ + if (btype < 1 || btype > atom->nbondtypes) error->all(FLERR, "Illegal value for bond type"); + iarg += 2; } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg]); } @@ -193,7 +198,7 @@ void FixRHEOThermal::init() // all special weights must be 1.0 (no special neighbors) or there must be an instance of fix update/special/bonds if (force->special_lj[0] != 1.0 || force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) { auto fixes = modify->get_fix_by_style("UPDATE_SPECIAL_BONDS"); - if (fixes.size == 0) error->all(FLERR, "Without fix update/special/bonds, reactive bond generation in fix rheo/thermal requires special weights of 1.0"); + if (fixes.size() == 0) error->all(FLERR, "Without fix update/special/bonds, reactive bond generation in fix rheo/thermal requires special weights of 1.0"); fix_update_special_bonds = dynamic_cast(fixes[0]); } @@ -314,7 +319,7 @@ void FixRHEOThermal::post_integrate() comm->forward_comm(this); for (int i = 0; i < atom->nlocal; i++) { - if (status[i] & STATUS_MELTING) delete_bonds(i); + if (status[i] & STATUS_MELTING) break_bonds(i); if (status[i] & STATUS_FREEZING) create_bonds(i); } } @@ -434,7 +439,7 @@ void FixRHEOThermal::create_bonds(int i) int nlocal = atom->nlocal; tagint *tag = atom->tag; - double *x = atom->x; + double **x = atom->x; numneigh = list->numneigh; firstneigh = list->firstneigh; @@ -442,6 +447,7 @@ void FixRHEOThermal::create_bonds(int i) int **bond_type = atom->bond_type; tagint **bond_atom = atom->bond_atom; int *num_bond = atom->num_bond; + int newton_bond = force->newton_bond; double xtmp = x[i][0]; double ytmp = x[i][1]; @@ -511,6 +517,6 @@ void FixRHEOThermal::unpack_forward_comm(int n, int first, double *buf) m = 0; last = first + n; for (i = first; i < last; i++) { - status[i] = (int) ubuf(buf[m++]).i + status[i] = (int) ubuf(buf[m++]).i; } } diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index 13b743b939..75d32b7bc1 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -22,6 +22,8 @@ FixStyle(rheo/thermal,FixRHEOThermal) #include "fix.h" +#include + namespace LAMMPS_NS { class FixRHEOThermal : public Fix { @@ -48,13 +50,13 @@ class FixRHEOThermal : public Fix { double *kappa_type, kappa; double dtf, dtv; double cut_bond; - int Tc_style; - int cv_style; + int Tc_style, cv_style; + int btype; int conductivity_style; class NeighList *list; int n_histories; - const std::vector histories; + std::vector histories; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; From 63eed5e2301f53848a52557ebb6864cb68e19c3a Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 6 Oct 2023 17:43:54 -0600 Subject: [PATCH 046/385] Drafting tension model --- src/.gitignore | 2 + src/RHEO/pair_rheo_tension.cpp | 369 +++++++++++++++++++++++++++++++++ src/RHEO/pair_rheo_tension.h | 56 +++++ 3 files changed, 427 insertions(+) create mode 100644 src/RHEO/pair_rheo_tension.cpp create mode 100644 src/RHEO/pair_rheo_tension.h diff --git a/src/.gitignore b/src/.gitignore index f9794ddb82..7b645ee347 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -223,6 +223,8 @@ /fix_rheo_viscosity.h /pair_rheo.cpp /pair_rheo.h +/pair_rheo_tension.cpp +/pair_rheo_tension.h /compute_grid.cpp /compute_grid.h diff --git a/src/RHEO/pair_rheo_tension.cpp b/src/RHEO/pair_rheo_tension.cpp new file mode 100644 index 0000000000..5899c87e3e --- /dev/null +++ b/src/RHEO/pair_rheo_tension.cpp @@ -0,0 +1,369 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL) +----------------------------------------------------------------------- */ + +#include "pair_rheo_tension.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_kernel.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "math_extra.h" +#include "memory.h" +#include "modify.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "update.h" +#include "utils.h" + +#include + +using namespace LAMMPS_NS; +using namespace RHEO_NS; +using namespace MathExtra; + +static constexpr double EPSILON = 1e-2; + +/* ---------------------------------------------------------------------- */ + +PairRHEOTension::PairRHEOTension(LAMMPS *lmp) : + Pair(lmp), compute_kernel(nullptr), fix_rheo(nullptr) +{ + restartinfo = 0; + single_enable = 0; + + comm_forward = 3; + comm_reverse = 3; +} + +/* ---------------------------------------------------------------------- */ + +PairRHEOTension::~PairRHEOTension() +{ + // Remove custom property if it exists + int tmp1, tmp2, index; + + index = atom->find_custom("rheo_c_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 0); + + index = atom->find_custom("rheo_n_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 3); + + if (allocated) { + memory->destroy(alpha); + memory->destroy(setflag); + memory->destroy(cutsq); + } +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEOTension::compute(int eflag, int vflag) +{ + int i, j, a, b, ii, jj, inum, jnum, itype, jtype; + int fluidi, fluidj; + double xtmp, ytmp, ztmp, w, wp; + double rhoi, rhoj, voli, volj; + double *dWij, *dWji; + double dx[3], ft[3]; + + int *ilist, *jlist, *numneigh, **firstneigh; + double imass, jmass, rsq, r, rinv; + + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + int dim = domain->dimension; + + ev_init(eflag, vflag); + + double **x = atom->x; + double **f = atom->f; + double *rho = atom->rho; + double *mass = atom->mass; + double *special_lj = force->special_lj; + int *type = atom->type; + int *status = atom->status; + tagint *tag = atom->tag; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + int nmax = atom->nmax; + if (nmax_store <= nmax) { + memory->grow(c_tension, nmax, "atom:rheo_c_tension"); + memory->grow(n_tension, nmax, 3, "atom:rheo_n_tension"); + nmax_store = atom->nmax; + } + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + imass = mass[itype]; + rhoi = rho[i]; + voli = imass / rhoi; + fluidi = !(status[i] & PHASECHECK); + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = lensq3(dx); + jtype = type[j]; + + if (rsq > hsq) continue; + + r = sqrt(rsq); + rinv = 1 / r; + + jmass = mass[jtype]; + rhoj = rho[j]; + volj = jmass / rhoj; + fluidj = !(status[j] & PHASECHECK); + + wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2],r); + dWij = compute_kernel->dWij; + dWji = compute_kernel->dWji; + + + + f[i][0] += ft[0]; + f[i][1] += ft[1]; + f[i][2] += ft[2]; + + if (evflag) // Does not account for unbalanced forces + ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); + + if (newton_pair || j < nlocal) { + + f[j][0] -= ft[0]; + f[j][1] -= ft[1]; + f[j][2] -= ft[2]; + } + } + } + + if (vflag_fdotr) virial_fdotr_compute(); + + if (compute_interface) { + comm->reverse_comm(this); + comm->forward_comm(this); + } +} + +/* ---------------------------------------------------------------------- + allocate all arrays + ------------------------------------------------------------------------- */ + +void PairRHEOTension::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag, n + 1, n + 1, "pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(alpha, n + 1, n + 1, "pair:alpha"); + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs + ------------------------------------------------------------------------- */ + +void PairRHEOTension::coeff(int narg, char **arg) +{ + if (narg != 3) + error->all(FLERR,"Incorrect number of args for pair_style rheo coefficients"); + if (!allocated) + allocate(); + + int ilo, ihi, jlo, jhi; + utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); + utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); + + alpha_one = utils::numeric(FLERR, arg[2], false, lmp); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = 0; j <= atom->ntypes; j++) { + alpha[i][j] = alpha_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) + error->all(FLERR,"Incorrect args for pair rheo/tension coefficients"); +} + +/* ---------------------------------------------------------------------- + setup specific to this pair style + ------------------------------------------------------------------------- */ + +void PairRHEOTension::setup() +{ + auto fixes = modify->get_fix_by_style("rheo"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use pair rheo"); + fix_rheo = dynamic_cast(fixes[0]); + + compute_kernel = fix_rheo->compute_kernel; + compute_grad = fix_rheo->compute_grad; + compute_interface = fix_rheo->compute_interface; + h = fix_rheo->h; + csq = fix_rheo->csq; + rho0 = fix_rheo->rho0; + + hsq = h * h; + hinv = 1.0 / h; + hinv3 = hinv * 3.0; +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairRHEOTension::init_style() +{ + neighbor->add_request(this); + + + // Create c_tension arrays n_tension arrays if they don't already exist + // Create a custom atom property so it works with compute property/atom + // Do not create grow callback as there's no reason to copy/exchange data + // Manually grow if nmax_store exceeded + // For B and gradC, create a local array since they are unlikely to be printed + + int tmp1, tmp2; + int index = atom->find_custom("rheo_c_tension", tmp1, tmp2); + if (index == -1) index = atom->add_custom("rheo_c_tension", 1, 0); + ct = atom->dvector[index]; + + index = atom->find_custom("rheo_n_tension", tmp1, tmp2); + if (index == -1) index = atom->add_custom("rheo_n_tension", 1, 3); + nt = atom->darray[index]; + + nmax_store = atom->nmax; +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i + ------------------------------------------------------------------------- */ + +double PairRHEOTension::init_one(int i, int j) +{ + if (setflag[i][j] == 0) + error->all(FLERR,"All pair rheo/tension coeffs are not set"); + + alpha[j][i] = alpha[i][j]; + + return h; +} + + +/* ---------------------------------------------------------------------- */ + +int PairRHEOTension::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) +{ + int i,j,k,m; + m = 0; + double *rho = atom->rho; + + for (i = 0; i < n; i++) { + j = list[i]; + if (comm_stage == 0) { + buf[m++] = fp_store[j][0]; + buf[m++] = fp_store[j][1]; + buf[m++] = fp_store[j][2]; + } else { + buf[m++] = chi[j]; + buf[m++] = rho[j]; + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEOTension::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double *rho = atom->rho; + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (comm_stage == 0) { + fp_store[i][0] = buf[m++]; + fp_store[i][1] = buf[m++]; + fp_store[i][2] = buf[m++]; + } else { + chi[i] = buf[m++]; + rho[i] = buf[m++]; + } + } +} + + +/* ---------------------------------------------------------------------- */ + +int PairRHEOTension::pack_reverse_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double **fp_store = compute_interface->fp_store; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = fp_store[i][0]; + buf[m++] = fp_store[i][1]; + buf[m++] = fp_store[i][2]; + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i, j, k, m; + double **fp_store = compute_interface->fp_store; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + fp_store[j][0] += buf[m++]; + fp_store[j][1] += buf[m++]; + fp_store[j][2] += buf[m++]; + } +} diff --git a/src/RHEO/pair_rheo_tension.h b/src/RHEO/pair_rheo_tension.h new file mode 100644 index 0000000000..9b75b05ebd --- /dev/null +++ b/src/RHEO/pair_rheo_tension.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS +// clang-format off +PairStyle(rheo/tension,PairRHEOTension) +// clang-format on +#else + +#ifndef LMP_PAIR_RHEO_TENSION_H +#define LMP_PAIR_RHEO_TENSION_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairRHEOTension : public Pair { + public: + PairRHEOTension(class LAMMPS *); + ~PairRHEOTension() override; + void compute(int, int) override; + void coeff(int, char **) override; + void setup() override; + void init_style() override; + double init_one(int, int) override; + void unpack_forward_comm(int, int, double *) override; + int pack_reverse_comm(int, int, double *) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; + + protected: + int nmax_store; + double **nt, *ct; + double *alpha; + double hsq, hinv, hinv3; + + void allocate(); + + class ComputeRHEOKernel *compute_kernel; + class FixRHEO *fix_rheo; +}; + +} // namespace LAMMPS_NS + +#endif +#endif From f28e46d40e5ad5e883849a7412faccd2d58b1d6f Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 19 Oct 2023 11:57:07 -0600 Subject: [PATCH 047/385] Adding support for remap v --- src/RHEO/compute_rheo_grad.cpp | 28 ++++++++++++++++++++++++---- src/RHEO/compute_rheo_grad.h | 2 +- src/RHEO/fix_rheo.cpp | 2 +- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 369bf11e0d..7fdff41403 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -111,6 +111,8 @@ void ComputeRHEOGrad::init() compute_kernel = fix_rheo->compute_kernel; compute_interface = fix_rheo->compute_interface; + remap_v_flag = domain->deform_vremap; + neighbor->add_request(this, NeighConst::REQ_DEFAULT); } @@ -301,13 +303,23 @@ void ComputeRHEOGrad::forward_fields() /* ---------------------------------------------------------------------- */ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, - int /*pbc_flag*/, int * /*pbc*/) + int pbc_flag, int *pbc) { int i,j,k,m; + int *mask = atom->mask; double *rho = atom->rho; double *temperature = atom->temperature; double **v = atom->v; int dim = domain->dimension; + double *h_rate = domain->h_rate; + int deform_groupbit = domain->deform_groupbit; + double dv[3]; + + if (remap_v_flag) { + dv[0] = pbc[0] * h_rate[0] + pbc[5] * h_rate[5] + pbc[4] * h_rate[4]; + dv[1] = pbc[1] * h_rate[1] + pbc[3] * h_rate[3]; + dv[2] = pbc[2] * h_rate[2]; + } m = 0; @@ -333,9 +345,17 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, } else if (comm_stage == COMMFIELD) { - if (velocity_flag) - for (k = 0; k < dim; k++) - buf[m++] = v[j][k]; + if (velocity_flag) { + if (remap_v_flag & pbc_flag & (mask[j] & deform_groupbit)) { + for (k = 0; k < dim; k++) + buf[m++] = v[j][k] + dv[k]; + } else { + for (k = 0; k < dim; k++) + buf[m++] = v[j][k]; + } + } + + if (rho_flag) buf[m++] = rho[j]; diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index af4fecdcfb..db5e84d32a 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -49,7 +49,7 @@ class ComputeRHEOGrad : public Compute { double cut, cutsq, rho0; int velocity_flag, temperature_flag, rho_flag, eta_flag; - int interface_flag; + int interface_flag, remap_v_flag; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 339d7f5ac8..e26ce8744b 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -381,13 +381,13 @@ void FixRHEO::pre_force(int /*vflag*/) if (rhosum_flag) compute_rhosum->compute_peratom(); - compute_grad->forward_fields(); // also forwards v and rho for chi compute_kernel->compute_peratom(); if (interface_flag) { // Note on first setup, have no forces for pressure to reference compute_interface->compute_peratom(); } + // No need to forward v, rho, or T for compute_grad since already done compute_grad->compute_peratom(); compute_grad->forward_gradients(); From 5986fb90b93c00b11318ec69e96bdeafe83ce55a Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 19 Oct 2023 12:37:59 -0600 Subject: [PATCH 048/385] Few updates to surface tension, add stress fix --- src/.gitignore | 2 + src/RHEO/fix_rheo_stress.cpp | 137 +++++++++++++++++++++++++++++++++ src/RHEO/fix_rheo_stress.h | 48 ++++++++++++ src/RHEO/pair_rheo_tension.cpp | 12 +-- src/RHEO/pair_rheo_tension.h | 2 +- 5 files changed, 192 insertions(+), 9 deletions(-) create mode 100644 src/RHEO/fix_rheo_stress.cpp create mode 100644 src/RHEO/fix_rheo_stress.h diff --git a/src/.gitignore b/src/.gitignore index 7b645ee347..cc792388a6 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -217,6 +217,8 @@ /fix_rheo.h /fix_rheo_pressure.cpp /fix_rheo_pressure.h +/fix_rheo_stress.cpp +/fix_rheo_stress.h /fix_rheo_thermal.cpp /fix_rheo_thermal.h /fix_rheo_viscosity.cpp diff --git a/src/RHEO/fix_rheo_stress.cpp b/src/RHEO/fix_rheo_stress.cpp new file mode 100644 index 0000000000..b391527f1c --- /dev/null +++ b/src/RHEO/fix_rheo_stress.cpp @@ -0,0 +1,137 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Joel Clemmer (SNL) +----------------------------------------------------------------------- */ + +#include "fix_rheo_stress.h" + +#include "atom.h" +#include "comm.h" +#include "compute.h" +#include "domain.h" +#include "fix_store_atom.h" +#include "group.h" +#include "error.h" +#include "modify.h" +#include "update.h" + +#include +#include + +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixRHEOStress::FixRHEOStress(LAMMPS *lmp, int narg, char **arg) : + id_compute(nullptr), id_fix(nullptr), stress_compute(nullptr), store_fix(nullptr), Fix(lmp, narg, arg) +{ + if (narg != 3) error->all(FLERR,"Illegal fix rheo/stress command"); + comm_forward = 6; +} + +/* ---------------------------------------------------------------------- */ + +FixRHEOStress::~FixRHEOStress() +{ + modify->delete_compute(id_compute); + modify->delete_fix(id_fix); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOStress::post_constructor() +{ + id_fix = utils::strdup(std::string(id) + "_store"); + store_fix = dynamic_cast(modify->add_fix(fmt::format("{} {} STORE/ATOM d_pxx d_pyy d_pzz d_pxy d_pxz d_pyz", id_fix, group->names[igroup]))); + array_atom = store_fix->astore; + + id_compute = utils::strdup(std::string(id) + "_compute"); + stress_compute = modify->add_compute(fmt::format("{} {} stress/atom NULL ke pair bond", id_compute, group->names[igroup])); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOStress::setmask() +{ + int mask = 0; + mask |= PRE_FORCE; + mask |= END_OF_STEP; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOStress::init() +{ + stress_compute->addstep(update->ntimestep+1); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOStress::pre_force(int vflag) +{ + // add pre-force and forward to ghosts (not done in store/atom) + comm->forward_comm(this); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOStress::end_of_step() +{ + stress_compute->compute_peratom(); + + // copy compute to fix property atom + double **saved_stress = store_fix->astore; + double **stress = stress_compute->array_atom; + + int ntotal = atom->nlocal+atom->nghost; + for (int i = 0; i < ntotal; i++) + for (int a = 0; a < 6; a++) + saved_stress[i][a] = stress[i][a]; + + stress_compute->addstep(update->ntimestep + 1); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOStress::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i, j, a, m; + double **saved_stress = store_fix->astore; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + for (a = 0; a < 6; a++) + buf[m++] = saved_stress[j][a]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOStress::unpack_forward_comm(int n, int first, double *buf) +{ + int i, a, m, last; + double **saved_stress = store_fix->astore; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + for (a = 0; a < 6; a++) + saved_stress[i][a] = buf[m++]; +} diff --git a/src/RHEO/fix_rheo_stress.h b/src/RHEO/fix_rheo_stress.h new file mode 100644 index 0000000000..4bf522793f --- /dev/null +++ b/src/RHEO/fix_rheo_stress.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS +// clang-format off +FixStyle(rheo/stress,FixRHEOStress); +// clang-format on +#else + +#ifndef LMP_FIX_RHEO_STRESS_H +#define LMP_FIX_RHEO_STRESS_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixRHEOStress : public Fix { + public: + FixRHEOStress(class LAMMPS *, int, char **); + ~FixRHEOStress() override; + void post_constructor() override; + int setmask() override; + void init() override; + void pre_force(int) override; + void end_of_step() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; + + private: + char *id_compute, *id_fix; + class Compute *stress_compute; + class FixStoreAtom *store_fix; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/pair_rheo_tension.cpp b/src/RHEO/pair_rheo_tension.cpp index 5899c87e3e..824f496161 100644 --- a/src/RHEO/pair_rheo_tension.cpp +++ b/src/RHEO/pair_rheo_tension.cpp @@ -109,8 +109,8 @@ void PairRHEOTension::compute(int eflag, int vflag) int nmax = atom->nmax; if (nmax_store <= nmax) { - memory->grow(c_tension, nmax, "atom:rheo_c_tension"); - memory->grow(n_tension, nmax, 3, "atom:rheo_n_tension"); + memory->grow(ct, nmax, "atom:rheo_c_tension"); + memory->grow(nnt_tension, nmax, 3, "atom:rheo_n_tension"); nmax_store = atom->nmax; } @@ -153,8 +153,6 @@ void PairRHEOTension::compute(int eflag, int vflag) dWij = compute_kernel->dWij; dWji = compute_kernel->dWji; - - f[i][0] += ft[0]; f[i][1] += ft[1]; f[i][2] += ft[2]; @@ -173,10 +171,8 @@ void PairRHEOTension::compute(int eflag, int vflag) if (vflag_fdotr) virial_fdotr_compute(); - if (compute_interface) { - comm->reverse_comm(this); - comm->forward_comm(this); - } + comm->reverse_comm(this); + comm->forward_comm(this); } /* ---------------------------------------------------------------------- diff --git a/src/RHEO/pair_rheo_tension.h b/src/RHEO/pair_rheo_tension.h index 9b75b05ebd..d1799b65e7 100644 --- a/src/RHEO/pair_rheo_tension.h +++ b/src/RHEO/pair_rheo_tension.h @@ -33,9 +33,9 @@ class PairRHEOTension : public Pair { void setup() override; void init_style() override; double init_one(int, int) override; + int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; int pack_reverse_comm(int, int, double *) override; - int pack_reverse_comm(int, int, double *) override; void unpack_reverse_comm(int, int *, double *) override; protected: From 0d2b3dc51e1bc4c478723a29bb653f0036a92205 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 22 Oct 2023 14:54:27 -0600 Subject: [PATCH 049/385] Drafting oxide model --- src/.gitignore | 2 + src/RHEO/pair_rheo_react.cpp | 587 +++++++++++++++++++++++++++++++++++ src/RHEO/pair_rheo_react.h | 60 ++++ 3 files changed, 649 insertions(+) create mode 100644 src/RHEO/pair_rheo_react.cpp create mode 100644 src/RHEO/pair_rheo_react.h diff --git a/src/.gitignore b/src/.gitignore index f9794ddb82..099b905eb2 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -223,6 +223,8 @@ /fix_rheo_viscosity.h /pair_rheo.cpp /pair_rheo.h +/pair_rheo_react.cpp +/pair_rheo_react.h /compute_grid.cpp /compute_grid.h diff --git a/src/RHEO/pair_rheo_react.cpp b/src/RHEO/pair_rheo_react.cpp new file mode 100644 index 0000000000..49c24cf501 --- /dev/null +++ b/src/RHEO/pair_rheo_react.cpp @@ -0,0 +1,587 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL) +----------------------------------------------------------------------- */ + +#include "pair_rheo_react.h" + +#include "atom.h" +#include "comm.h" +#include "error.h" +#include "fix.h" +#include "fix_dummy.h" +#include "fix_neigh_history.h" +#include "fix_rheo.h" +#include "force.h" +#include "memory.h" +#include "modify.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "update.h" +#include "utils.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +PairRHEOReact::PairRHEOReact(LAMMPS *lmp) : Pair(lmp), + dbond(NULL) +{ + single_enable = 0; + size_history = 2; + beyond_contact = 1; + comm_reverse = 1; + + // create dummy fix as placeholder for FixNeighHistory + // this is so final order of Modify:fix will conform to input script + + fix_history = nullptr; + fix_dummy = dynamic_cast( + modify->add_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY" + std::to_string(instance_me) + " all DUMMY")); + + // For nbond, create an instance of fix property atom + // Need restarts + exchanging with neighbors since it needs to persist + // between timesteps (fix property atom will handle callbacks) + + int tmp1, tmp2; + int index = atom->find_custom("react_nbond", tmp1, tmp2); + if (index == -1) { + id_fix_pa = utils::strdup("pair_rheo_react_fix_property_atom"); + modify->add_fix(fmt::format("{} all property/atom i_react_nbond", id_fix_pa)); + index = atom->find_custom("nbond", tmp1, tmp2); + } + nbond = atom->ivector[index]; + + //Store non-persistent per atom quantities, intermediate + + nmax_store = atom->nmax; + memory->create(dbond, nmax_store, "rheo/react:dbond"); +} + +/* ---------------------------------------------------------------------- */ + +PairRHEOReact::~PairRHEOReact() +{ + if (modify->nfix && fix_history) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT"); + if (modify->nfix && fix_dummy) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY"); + if (modify->nfix) modify->delete_fix("PROPERTY_ATOM_RHEO_REACT"); + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(cutbsq); + + memory->destroy(cut); + memory->destroy(cutbond); + memory->destroy(k); + memory->destroy(eps); + memory->destroy(gamma); + memory->destroy(t_form); + memory->destroy(rlimit); + memory->destroy(sigma); + memory->destroy(krepel); + } + + memory->destroy(dbond); +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEOReact::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum; + double xtmp,ytmp,ztmp,delx,dely,delz; + double rsq,r,rinv,r0; + double vxtmp,vytmp,vztmp,delvx,delvy,delvz; + double fpair,dot,evdwl,smooth; + int itype, jtype; + + int *ilist,*jlist,*numneigh,**firstneigh; + int *saved,**firstsaved; + double *data,*alldata,**firstdata; + + ev_init(eflag,vflag); + + int bondupdate = 1; + if (update->setupflag) bondupdate = 0; + + dt = update->dt; + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + int *type = atom->type; + int *phase = atom->phase; + int *mask = atom->mask; + int *nbond = atom->ivector[index_nb]; + int *surface = atom->surface; + double *rsurf = atom->dvector[index_rsurf]; + + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + firstsaved = fix_history->firstflag; + firstdata = fix_history->firstvalue; + + if (atom->nmax > nmax){ + nmax = atom->nmax; + memory->destroy(dbond); + memory->create(dbond, nmax, "rheo/react:dbond"); + } + + // Switch to no shift if it has bonds (could have just been changed from reactive) + for(i = 0; i < nmax; i++) { + dbond[i] = 0; + } + + // loop over neighbors of my atoms + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + vxtmp = v[i][0]; + vytmp = v[i][1]; + vztmp = v[i][2]; + saved = firstsaved[i]; + alldata = firstdata[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + jtype = type[j]; + data = &alldata[2*jj]; + + // If not bonded and there's an internal fluid particle, unsave any data and skip + if (!(saved[jj] == 1 && data[0] > 0)) { + if ((phase[i] <= FixRHEO::FLUID_MAX && rsurf[i] > rlimit[itype][jtype]) || (phase[j] <= FixRHEO::FLUID_MAX && rsurf[j] > rlimit[itype][jtype])) { + saved[jj] = 0; + continue; + } + } + + // If both are solid, unbond and skip + if ((phase[i] == FixRHEO::SOLID || phase[i] == FixRHEO::FREEZING) && + (phase[j] == FixRHEO::SOLID || phase[j] == FixRHEO::FREEZING)) { + //If bonded, deincrement + if (saved[jj] == 1 && data[0] > 0) { + dbond[i] --; + dbond[j] --; + } + saved[jj] = 0; + continue; + } + + // Remaining options are react+sold, react+react, react+surf/fluid, or surf/fluid+surf/fluid + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + + // If unbonded and beyond bond distance, unsave and skip + if (data[0] == -1 && rsq > cutbsq[itype][jtype]) { + saved[jj] = 0; + continue; + } + + r = sqrt(rsq); + // Initialize data if not currently saved since all could bond if they are on the surface + if (saved[jj] == 0) { + data[0] = -1; + data[1] = 0; + saved[jj] = 1; + } + + // Check for bond formation (unbonded) or breakage (bonded) + if (data[0] == -1) { + // If unbonded, check if we count down to bonding if both on surface (not given for r or s) + if (bondupdate && rsurf[i] <= rlimit[itype][jtype] && rsurf[j] <= rlimit[itype][jtype]) { + data[1] += dt; + if (data[1] >= t_form[itype][jtype]) { + data[0] = r; + dbond[i] ++; + dbond[j] ++; + data[1] = 0; + } + } + } else { + // If bonded, check if breaks in tension + r0 = data[0]; + if (r > ((1.0+eps[itype][jtype])*r0)) { + saved[jj] = 0; + dbond[i] --; + dbond[j] --; + data[0] = -1; + } + } + + // Apply forces + delvx = vxtmp - v[j][0]; + delvy = vytmp - v[j][1]; + delvz = vztmp - v[j][2]; + rinv = 1.0/r; + + if (data[0] <= 0) { + // Skip if either is fluid (only include r+s or r+r since already skipped s+s) + if (phase[i] <= FixRHEO::FLUID_MAX || phase[j] <= FixRHEO::FLUID_MAX) continue; + + // Skip if out of contact + if (rsq > sigma[itype][jtype]*sigma[itype][jtype]) continue; + + fpair = krepel[itype][jtype]*(sigma[itype][jtype]-r); + if (eflag) + evdwl = -0.5*krepel[itype][jtype]*(sigma[itype][jtype]-r)*(sigma[itype][jtype]-r); + + smooth = rsq/(sigma[itype][jtype]*sigma[itype][jtype]); + smooth *= smooth; + smooth = 1.0 - smooth; + dot = delx*delvx + dely*delvy + delz*delvz; + fpair -= gamma[itype][jtype]*dot*smooth*rinv; + + fpair *= rinv; + + f[i][0] += delx*fpair; + f[i][1] += dely*fpair; + f[i][2] += delz*fpair; + if (newton_pair || j < nlocal) { + f[j][0] -= delx*fpair; + f[j][1] -= dely*fpair; + f[j][2] -= delz*fpair; + } + + if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz); + } else { + // Bonded + r0 = data[0]; + + fpair = k[itype][jtype]*(r0-r); + if (evflag) evdwl = -0.5*fpair*(r0-r); + + dot = delx*delvx + dely*delvy + delz*delvz; + fpair -= gamma[itype][jtype]*dot*rinv; + + smooth = 1.0; + if (r > r0) { + smooth = (r-r0)/(r0*eps[itype][jtype]); + smooth *= smooth; + smooth *= smooth; + smooth = 1 - smooth; + } + + fpair *= rinv*smooth; + + f[i][0] += delx*fpair; + f[i][1] += dely*fpair; + f[i][2] += delz*fpair; + if (newton_pair || j < nlocal) { + f[j][0] -= delx*fpair; + f[j][1] -= dely*fpair; + f[j][2] -= delz*fpair; + } + + if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz); + } + } + } + + // Communicate changes in nbond + if(newton_pair) comm->reverse_comm_pair(this); + + for(i = 0; i < nlocal; i++) { + nbond[i] += dbond[i]; + + // If it has bonds it is reactive (no shifting) + // If a reactive particle breaks all bonds, return to fluid + // Keep it non-shifting for this timestep to be safe + if (nbond[i] != 0 && phase[i] <= FixRHEO::FLUID_MAX) phase[i] = FixRHEO::FLUID_NO_SHIFT; + } + + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairRHEOReact::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cut,n+1,n+1,"pair:cut"); + memory->create(cutbond,n+1,n+1,"pair:cutbond"); + memory->create(cutsq,n+1,n+1,"pair:cutsq"); + memory->create(cutbsq,n+1,n+1,"pair:cutbsq"); + memory->create(k,n+1,n+1,"pair:k"); + memory->create(eps,n+1,n+1,"pair:eps"); + memory->create(gamma,n+1,n+1,"pair:gamma"); + memory->create(t_form,n+1,n+1,"pair:t_form"); + memory->create(rlimit,n+1,n+1,"pair:rlimit"); + memory->create(sigma,n+1,n+1,"pair:sigma"); + memory->create(krepel,n+1,n+1,"pair:krepel"); +} + +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairRHEOReact::settings(int narg, char **arg) +{ +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairRHEOReact::coeff(int narg, char **arg) +{ + if (narg != 11) error->all(FLERR,"Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + utils::bounds(FLERR,arg[0],1, atom->ntypes, ilo, ihi,error); + utils::bounds(FLERR,arg[1],1, atom->ntypes, jlo, jhi,error); + + double cut_one = utils::numeric(FLERR,arg[2],false,lmp); + double cutb_one = utils::numeric(FLERR,arg[3],false,lmp); + double k_one = utils::numeric(FLERR,arg[4],false,lmp); + double eps_one = utils::numeric(FLERR,arg[5],false,lmp); + double gamma_one = utils::numeric(FLERR,arg[6],false,lmp); + double t_form_one = utils::numeric(FLERR,arg[7],false,lmp); + double rlimit_one = utils::numeric(FLERR,arg[8],false,lmp); + double sigma_one = utils::numeric(FLERR,arg[9],false,lmp); + double krepel_one = utils::numeric(FLERR,arg[10],false,lmp); + + if (k_one < 0.0 || eps_one < 0.0 || + t_form_one < 0.0 || (1.0+eps_one)*cutb_one > cut_one) + error->all(FLERR,"Illegal pair_style command"); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + cut[i][j] = cut_one; + cutbond[i][j] = cutb_one; + k[i][j] = k_one; + eps[i][j] = eps_one; + gamma[i][j] = gamma_one; + t_form[i][j] = t_form_one; + rlimit[i][j] = rlimit_one; + sigma[i][j] = sigma_one; + krepel[i][j] = krepel_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairRHEOReact::init_style() +{ + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->history = 1; + + if (fix_history == nullptr) { + + // Don't want history[i][j] = -history[j][i] + nondefault_history_transfer = 1; + + char dnumstr[16]; + sprintf(dnumstr,"%d",size_history); + char **fixarg = new char*[4]; + fixarg[0] = (char *) "NEIGH_HISTORY_RHEO_REACT"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "NEIGH_HISTORY"; + fixarg[3] = dnumstr; + modify->replace_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY",4,fixarg,1); + delete [] fixarg; + int ifix = modify->find_fix("NEIGH_HISTORY_RHEO_REACT"); + fix_history = (FixNeighHistory *) modify->fix[ifix]; + fix_history->pair = this; + fix_dummy = nullptr; + } + + int temp_flag; + index_rsurf = atom->find_custom("rsurf", temp_flag); + if ((index_rsurf < 0) || (temp_flag != 1)) + error->all(FLERR, "Pair rheo/react can't find fix property/atom rsurf"); +} + +/* ---------------------------------------------------------------------- + setup specific to this pair style + ------------------------------------------------------------------------- */ + +void PairRHEOReact::setup() { + int ifix = modify->find_fix_by_style("rheo"); + if (ifix == -1) error->all(FLERR, "Using pair rheo/react without fix rheo"); + fix_rheo = ((FixRHEO *) modify->fix[ifix]); + + ifix = modify->find_fix_by_style("rheo/surface"); + if (ifix == -1) error->all(FLERR, "Using pair rheo/react without fix rheo/surface"); + + if (force->newton_pair == 0) error->all(FLERR, + "Pair rheo/react needs newton pair on for bond changes to be consistent"); +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairRHEOReact::init_one(int i, int j) +{ + if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); + + double einv = 1/eps[i][j]; + + cutbsq[i][j] = cutbond[i][j]*cutbond[i][j]; + + cutbsq[j][i] = cutbsq[i][j]; + cut[j][i] = cut[i][j]; + cutbond[j][i] = cutbond[i][j]; + k[j][i] = k[i][j]; + eps[j][i] = eps[i][j]; + gamma[j][i] = gamma[i][j]; + t_form[j][i] = t_form[i][j]; + rlimit[j][i] = rlimit[i][j]; + sigma[j][i] = sigma[i][j]; + krepel[j][i] = krepel[i][j]; + + return cut[i][j]; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairRHEOReact::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&cut[i][j],sizeof(double),1,fp); + fwrite(&cutbond[i][j],sizeof(double),1,fp); + fwrite(&k[i][j],sizeof(double),1,fp); + fwrite(&eps[i][j],sizeof(double),1,fp); + fwrite(&gamma[i][j],sizeof(double),1,fp); + fwrite(&t_form[i][j],sizeof(double),1,fp); + fwrite(&rlimit[i][j],sizeof(double),1,fp); + fwrite(&sigma[i][j],sizeof(double),1,fp); + fwrite(&krepel[i][j],sizeof(double),1,fp); + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairRHEOReact::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&cut[i][j],sizeof(double),1,fp); + fread(&cutbond[i][j],sizeof(double),1,fp); + fread(&k[i][j],sizeof(double),1,fp); + fread(&eps[i][j],sizeof(double),1,fp); + fread(&gamma[i][j],sizeof(double),1,fp); + fread(&t_form[i][j],sizeof(double),1,fp); + fread(&rlimit[i][j],sizeof(double),1,fp); + fread(&sigma[i][j],sizeof(double),1,fp); + fread(&krepel[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cutbond[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&k[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&eps[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&gamma[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&t_form[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&rlimit[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&krepel[i][j],1,MPI_DOUBLE,0,world); + } + } +} + + + + +/* ---------------------------------------------------------------------- + transfer history during fix/neigh/history exchange - transfer same sign +------------------------------------------------------------------------- */ + +void PairRHEOReact::transfer_history(double* source, double* target) +{ + for (int i = 0; i < size_history; i++) + target[i] = source[i]; +} + +/* ---------------------------------------------------------------------- */ + +int PairRHEOReact::pack_reverse_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + + for (i = first; i < last; i++) { + buf[m++] = dbond[i]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEOReact::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + dbond[j] += buf[m++]; + } +} diff --git a/src/RHEO/pair_rheo_react.h b/src/RHEO/pair_rheo_react.h new file mode 100644 index 0000000000..c2a7f26f03 --- /dev/null +++ b/src/RHEO/pair_rheo_react.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS +// clang-format off +PairStyle(rheo/react,PairRHEOReact) +// clang-format on +#else + +#ifndef LMP_PAIR_RHEO_REACT_H +#define LMP_PAIR_RHEO_REACT_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairRHEOReact : public Pair { + public: + PairRHEOReact(class LAMMPS *); + virtual ~PairRHEOReact() override; + virtual void compute(int, int) override; + void settings(int, char **) override; + void coeff(int, char **) override; + void init_style() override; + void setup() override; + double init_one(int, int) override; + void write_restart(FILE *) override; + void read_restart(FILE *) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; + + protected: + double **cut,**cutbond,**cutbsq, **k, **eps, **gamma, **t_form, **rlimit, **sigma, **krepel; + + void allocate(); + void transfer_history(double*, double*); + + int size_history, nmax_store; + int *dbond, *nbond; + double dt; + + class FixDummy *fix_dummy; + class FixNeighHistory *fix_history; + class FixRHEO *fix_rheo; +}; + +} // namespace LAMMPS_NS + +#endif +#endif From 0945c3dda850aa6635be7f5aa7124c24ce992a23 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 30 Oct 2023 20:22:14 -0600 Subject: [PATCH 050/385] Bug in rheo, cleaning up old files --- src/RHEO/fix_rheo.cpp | 4 +- src/atom_vec_rheo_thermal.cpp | 200 ---------------------------------- src/atom_vec_rheo_thermal.h | 46 -------- 3 files changed, 2 insertions(+), 248 deletions(-) delete mode 100644 src/atom_vec_rheo_thermal.cpp delete mode 100644 src/atom_vec_rheo_thermal.h diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index e26ce8744b..c8dca74d32 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -94,11 +94,11 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg],"surface/detection") == 0) { surface_flag = 1; if(iarg + 2 >= narg) error->all(FLERR,"Illegal surface/detection option in fix rheo"); - if (strcmp(arg[iarg + 1], "coordination")) { + if (strcmp(arg[iarg + 1], "coordination") == 0) { surface_style = COORDINATION; zmin_surface = utils::inumeric(FLERR,arg[iarg + 2],false,lmp); zmin_splash = utils::inumeric(FLERR,arg[iarg + 3],false,lmp); - } else if (strcmp(arg[iarg + 1], "divergence")) { + } else if (strcmp(arg[iarg + 1], "divergence") == 0) { surface_style = DIVR; divr_surface = utils::numeric(FLERR,arg[iarg + 2],false,lmp); zmin_splash = utils::inumeric(FLERR,arg[iarg + 3],false,lmp); diff --git a/src/atom_vec_rheo_thermal.cpp b/src/atom_vec_rheo_thermal.cpp deleted file mode 100644 index de0c7fa5d7..0000000000 --- a/src/atom_vec_rheo_thermal.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* ---------------------------------------------------------------------- - 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. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) ------------------------------------------------------------------------ */ - -#include "atom_vec_rheo_thermal.h" - -#include "atom.h" - -#include - -using namespace LAMMPS_NS; - -/* ---------------------------------------------------------------------- */ - -AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) -{ - molecular = Atom::ATOMIC; - mass_type = PER_TYPE; - forceclearflag = 1; - - atom->status_flag = 1; - atom->conductivity_flag = 1; - atom->temperature_flag = 1; - atom->heatflow_flag = 1; - atom->pressure_flag = 1; - atom->rho_flag = 1; - atom->viscosity_flag = 1; - - // strings with peratom variables to include in each AtomVec method - // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in a string does not matter - // except: fields_data_atom & fields_data_vel must match data file - - fields_grow = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_copy = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_comm = {"status", "rho", "temperature"}; - fields_comm_vel = {"status", "rho", "temperature"}; - fields_reverse = {"drho", "heatflow"}; - fields_border = {"status", "rho", "temperature"}; - fields_border_vel = {"status", "rho", "temperature"}; - fields_exchange = {"status", "rho", "temperature"}; - fields_restart = {"status", "rho", "temperature"}; - fields_create = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_data_atom = {"id", "type", "status", "rho", "temperature", "x"}; - fields_data_vel = {"id", "v"}; - - setup_fields(); -} - -/* ---------------------------------------------------------------------- - set local copies of all grow ptrs used by this class, except defaults - needed in replicate when 2 atom classes exist and it calls pack_restart() -------------------------------------------------------------------------- */ - -void AtomVecRHEOThermal::grow_pointers() -{ - status = atom->status; - conductivity = atom->conductivity; - temperature = atom->temperature; - heatflow = atom->heatflow; - pressure = atom->pressure; - rho = atom->rho; - drho = atom->drho; - viscosity = atom->viscosity; -} - -/* ---------------------------------------------------------------------- - clear extra forces starting at atom N - nbytes = # of bytes to clear for a per-atom vector -------------------------------------------------------------------------- */ - -void AtomVecRHEOThermal::force_clear(int n, size_t nbytes) -{ - memset(&drho[n], 0, nbytes); - memset(&heatflow[n], 0, nbytes); -} - -/* ---------------------------------------------------------------------- - modify what AtomVec::data_atom() just unpacked - or initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecRHEOThermal::data_atom_post(int ilocal) -{ - drho[ilocal] = 0.0; - heatflow[ilocal] = 0.0; - pressure[ilocal] = 0.0; - viscosity[ilocal] = 0.0; - conductivity[ilocal] = 0.0; -} - -/* ---------------------------------------------------------------------- - assign an index to named atom property and return index - return -1 if name is unknown to this atom style -------------------------------------------------------------------------- */ - -int AtomVecRHEOThermal::property_atom(const std::string &name) -{ - if (name == "status") return 0; - if (name == "rho") return 1; - if (name == "drho") return 2; - if (name == "temperature") return 3; - if (name == "heatflow") return 4; - if (name == "conductivity") return 5; - if (name == "pressure") return 6; - if (name == "viscosity") return 7; - return -1; -} - -/* ---------------------------------------------------------------------- - pack per-atom data into buf for ComputePropertyAtom - index maps to data specific to this atom style -------------------------------------------------------------------------- */ - -void AtomVecRHEOThermal::pack_property_atom(int index, double *buf, int nvalues, int groupbit) -{ - int *mask = atom->mask; - int nlocal = atom->nlocal; - int n = 0; - - if (index == 0) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = status[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } else if (index == 1) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = rho[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } else if (index == 2) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = drho[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } else if (index == 3) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = temperature[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } else if (index == 4) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = heatflow[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } else if (index == 5) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = conductivity[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } else if (index == 6) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = pressure[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } else if (index == 7) { - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) - buf[n] = viscosity[i]; - else - buf[n] = 0.0; - n += nvalues; - } - } -} diff --git a/src/atom_vec_rheo_thermal.h b/src/atom_vec_rheo_thermal.h deleted file mode 100644 index 27c6c3c9b5..0000000000 --- a/src/atom_vec_rheo_thermal.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - 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. -------------------------------------------------------------------------- */ - -#ifdef ATOM_CLASS -// clang-format off -AtomStyle(rheo/thermal,AtomVecRHEOThermal); -// clang-format on -#else - -#ifndef LMP_ATOM_VEC_RHEO_THERMAL_H -#define LMP_ATOM_VEC_RHEO_THERMAL_H - -#include "atom_vec.h" - -namespace LAMMPS_NS { - -class AtomVecRHEOThermal : virtual public AtomVec { - public: - AtomVecRHEOThermal(class LAMMPS *); - - void grow_pointers() override; - void force_clear(int, size_t) override; - void data_atom_post(int) override; - int property_atom(const std::string &) override; - void pack_property_atom(int, double *, int, int) override; - - private: - int *status; - double *conductivity, *temperature, *heatflow; - double *pressure, *rho, *drho, *viscosity; -}; - -} // namespace LAMMPS_NS - -#endif -#endif From 89150877a22976808cbd9eeb8ffcddf61aafb44f Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 30 Oct 2023 20:48:20 -0600 Subject: [PATCH 051/385] Hiding compile bugs in temporary files --- src/RHEO/pair_rheo_react.cpp | 35 ++++++++++++++++++---------------- src/RHEO/pair_rheo_react.h | 7 +++++-- src/RHEO/pair_rheo_tension.cpp | 24 ++++++++++++++++++++--- src/RHEO/pair_rheo_tension.h | 5 +++-- 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/RHEO/pair_rheo_react.cpp b/src/RHEO/pair_rheo_react.cpp index 49c24cf501..7ec63bb2a9 100644 --- a/src/RHEO/pair_rheo_react.cpp +++ b/src/RHEO/pair_rheo_react.cpp @@ -60,8 +60,8 @@ PairRHEOReact::PairRHEOReact(LAMMPS *lmp) : Pair(lmp), int tmp1, tmp2; int index = atom->find_custom("react_nbond", tmp1, tmp2); if (index == -1) { - id_fix_pa = utils::strdup("pair_rheo_react_fix_property_atom"); - modify->add_fix(fmt::format("{} all property/atom i_react_nbond", id_fix_pa)); + id_fix = utils::strdup("pair_rheo_react_fix_property_atom"); + modify->add_fix(fmt::format("{} all property/atom i_react_nbond", id_fix)); index = atom->find_custom("nbond", tmp1, tmp2); } nbond = atom->ivector[index]; @@ -125,11 +125,9 @@ void PairRHEOReact::compute(int eflag, int vflag) double **v = atom->v; double **f = atom->f; int *type = atom->type; - int *phase = atom->phase; + int *status = atom->status; int *mask = atom->mask; int *nbond = atom->ivector[index_nb]; - int *surface = atom->surface; - double *rsurf = atom->dvector[index_rsurf]; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; @@ -151,7 +149,7 @@ void PairRHEOReact::compute(int eflag, int vflag) for(i = 0; i < nmax; i++) { dbond[i] = 0; } - +/* // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; @@ -167,23 +165,25 @@ void PairRHEOReact::compute(int eflag, int vflag) jlist = firstneigh[i]; jnum = numneigh[i]; + for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; jtype = type[j]; data = &alldata[2*jj]; + // If not bonded and there's an internal fluid particle, unsave any data and skip if (!(saved[jj] == 1 && data[0] > 0)) { - if ((phase[i] <= FixRHEO::FLUID_MAX && rsurf[i] > rlimit[itype][jtype]) || (phase[j] <= FixRHEO::FLUID_MAX && rsurf[j] > rlimit[itype][jtype])) { + if ((status[i] <= FixRHEO::FLUID_MAX && rsurf[i] > rlimit[itype][jtype]) || (status[j] <= FixRHEO::FLUID_MAX && rsurf[j] > rlimit[itype][jtype])) { saved[jj] = 0; continue; } } // If both are solid, unbond and skip - if ((phase[i] == FixRHEO::SOLID || phase[i] == FixRHEO::FREEZING) && - (phase[j] == FixRHEO::SOLID || phase[j] == FixRHEO::FREEZING)) { + if ((status[i] == FixRHEO::SOLID || status[i] == FixRHEO::FREEZING) && + (status[j] == FixRHEO::SOLID || status[j] == FixRHEO::FREEZING)) { //If bonded, deincrement if (saved[jj] == 1 && data[0] > 0) { dbond[i] --; @@ -245,7 +245,7 @@ void PairRHEOReact::compute(int eflag, int vflag) if (data[0] <= 0) { // Skip if either is fluid (only include r+s or r+r since already skipped s+s) - if (phase[i] <= FixRHEO::FLUID_MAX || phase[j] <= FixRHEO::FLUID_MAX) continue; + if (status[i] <= FixRHEO::FLUID_MAX || status[j] <= FixRHEO::FLUID_MAX) continue; // Skip if out of contact if (rsq > sigma[itype][jtype]*sigma[itype][jtype]) continue; @@ -315,10 +315,11 @@ void PairRHEOReact::compute(int eflag, int vflag) // If it has bonds it is reactive (no shifting) // If a reactive particle breaks all bonds, return to fluid // Keep it non-shifting for this timestep to be safe - if (nbond[i] != 0 && phase[i] <= FixRHEO::FLUID_MAX) phase[i] = FixRHEO::FLUID_NO_SHIFT; + if (nbond[i] != 0 && status[i] <= FixRHEO::FLUID_MAX) status[i] = FixRHEO::FLUID_NO_SHIFT; } if (vflag_fdotr) virial_fdotr_compute(); + */ } /* ---------------------------------------------------------------------- @@ -410,7 +411,7 @@ void PairRHEOReact::coeff(int narg, char **arg) void PairRHEOReact::init_style() { int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->history = 1; + //neighbor->requests[irequest]->history = 1; if (fix_history == nullptr) { @@ -432,10 +433,10 @@ void PairRHEOReact::init_style() fix_dummy = nullptr; } - int temp_flag; - index_rsurf = atom->find_custom("rsurf", temp_flag); - if ((index_rsurf < 0) || (temp_flag != 1)) - error->all(FLERR, "Pair rheo/react can't find fix property/atom rsurf"); + //int temp_flag; + //index_rsurf = atom->find_custom("rsurf", temp_flag); + //if ((index_rsurf < 0) || (temp_flag != 1)) + // error->all(FLERR, "Pair rheo/react can't find fix property/atom rsurf"); } /* ---------------------------------------------------------------------- @@ -443,6 +444,7 @@ void PairRHEOReact::init_style() ------------------------------------------------------------------------- */ void PairRHEOReact::setup() { + /* int ifix = modify->find_fix_by_style("rheo"); if (ifix == -1) error->all(FLERR, "Using pair rheo/react without fix rheo"); fix_rheo = ((FixRHEO *) modify->fix[ifix]); @@ -452,6 +454,7 @@ void PairRHEOReact::setup() { if (force->newton_pair == 0) error->all(FLERR, "Pair rheo/react needs newton pair on for bond changes to be consistent"); + */ } /* ---------------------------------------------------------------------- diff --git a/src/RHEO/pair_rheo_react.h b/src/RHEO/pair_rheo_react.h index c2a7f26f03..b349300f27 100644 --- a/src/RHEO/pair_rheo_react.h +++ b/src/RHEO/pair_rheo_react.h @@ -27,8 +27,8 @@ namespace LAMMPS_NS { class PairRHEOReact : public Pair { public: PairRHEOReact(class LAMMPS *); - virtual ~PairRHEOReact() override; - virtual void compute(int, int) override; + ~PairRHEOReact() override; + void compute(int, int) override; void settings(int, char **) override; void coeff(int, char **) override; void init_style() override; @@ -49,6 +49,9 @@ class PairRHEOReact : public Pair { int *dbond, *nbond; double dt; + int index_nb, nmax; + char *id_fix; + class FixDummy *fix_dummy; class FixNeighHistory *fix_history; class FixRHEO *fix_rheo; diff --git a/src/RHEO/pair_rheo_tension.cpp b/src/RHEO/pair_rheo_tension.cpp index 824f496161..ef0d0b60b4 100644 --- a/src/RHEO/pair_rheo_tension.cpp +++ b/src/RHEO/pair_rheo_tension.cpp @@ -106,7 +106,7 @@ void PairRHEOTension::compute(int eflag, int vflag) ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; - +/* int nmax = atom->nmax; if (nmax_store <= nmax) { memory->grow(ct, nmax, "atom:rheo_c_tension"); @@ -173,6 +173,7 @@ void PairRHEOTension::compute(int eflag, int vflag) comm->reverse_comm(this); comm->forward_comm(this); +*/ } /* ---------------------------------------------------------------------- @@ -193,6 +194,14 @@ void PairRHEOTension::allocate() memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); } +/* ---------------------------------------------------------------------- + global settings + ------------------------------------------------------------------------- */ + +void PairRHEOTension::settings(int narg, char **arg) +{ +} + /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ @@ -208,7 +217,7 @@ void PairRHEOTension::coeff(int narg, char **arg) utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); - alpha_one = utils::numeric(FLERR, arg[2], false, lmp); + double alpha_one = utils::numeric(FLERR, arg[2], false, lmp); int count = 0; for (int i = ilo; i <= ihi; i++) { @@ -232,7 +241,7 @@ void PairRHEOTension::setup() auto fixes = modify->get_fix_by_style("rheo"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use pair rheo"); fix_rheo = dynamic_cast(fixes[0]); - + /* compute_kernel = fix_rheo->compute_kernel; compute_grad = fix_rheo->compute_grad; compute_interface = fix_rheo->compute_interface; @@ -243,6 +252,7 @@ void PairRHEOTension::setup() hsq = h * h; hinv = 1.0 / h; hinv3 = hinv * 3.0; + */ } /* ---------------------------------------------------------------------- @@ -291,6 +301,7 @@ double PairRHEOTension::init_one(int i, int j) int PairRHEOTension::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { + /* int i,j,k,m; m = 0; double *rho = atom->rho; @@ -307,12 +318,14 @@ int PairRHEOTension::pack_forward_comm(int n, int *list, double *buf, int /*pbc_ } } return m; + */ } /* ---------------------------------------------------------------------- */ void PairRHEOTension::unpack_forward_comm(int n, int first, double *buf) { + /* int i, k, m, last; double *rho = atom->rho; m = 0; @@ -327,6 +340,7 @@ void PairRHEOTension::unpack_forward_comm(int n, int first, double *buf) rho[i] = buf[m++]; } } + */ } @@ -334,6 +348,7 @@ void PairRHEOTension::unpack_forward_comm(int n, int first, double *buf) int PairRHEOTension::pack_reverse_comm(int n, int first, double *buf) { + /* int i, k, m, last; double **fp_store = compute_interface->fp_store; @@ -346,12 +361,14 @@ int PairRHEOTension::pack_reverse_comm(int n, int first, double *buf) } return m; + */ } /* ---------------------------------------------------------------------- */ void PairRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) { + /* int i, j, k, m; double **fp_store = compute_interface->fp_store; @@ -362,4 +379,5 @@ void PairRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) fp_store[j][1] += buf[m++]; fp_store[j][2] += buf[m++]; } + */ } diff --git a/src/RHEO/pair_rheo_tension.h b/src/RHEO/pair_rheo_tension.h index d1799b65e7..2a046ff324 100644 --- a/src/RHEO/pair_rheo_tension.h +++ b/src/RHEO/pair_rheo_tension.h @@ -29,6 +29,7 @@ class PairRHEOTension : public Pair { PairRHEOTension(class LAMMPS *); ~PairRHEOTension() override; void compute(int, int) override; + void settings(int, char **) override; void coeff(int, char **) override; void setup() override; void init_style() override; @@ -41,8 +42,8 @@ class PairRHEOTension : public Pair { protected: int nmax_store; double **nt, *ct; - double *alpha; - double hsq, hinv, hinv3; + double **alpha; + double h, hsq, hinv, hinv3; void allocate(); From bf115e5df4718d8e8bb45d639a10c03aa5f3e3ba Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 1 Nov 2023 11:55:07 -0600 Subject: [PATCH 052/385] Fix compiler/memory errors in tension, update properties in surface --- src/.gitignore | 4 +- src/RHEO/compute_rheo_grad.cpp | 2 - src/RHEO/compute_rheo_surface.cpp | 82 ++-- src/RHEO/compute_rheo_surface.h | 8 +- src/RHEO/fix_rheo_tension.cpp | 452 ++++++++++++++++++ ...pair_rheo_tension.h => fix_rheo_tension.h} | 41 +- src/RHEO/pair_rheo_tension.cpp | 383 --------------- 7 files changed, 527 insertions(+), 445 deletions(-) create mode 100644 src/RHEO/fix_rheo_tension.cpp rename src/RHEO/{pair_rheo_tension.h => fix_rheo_tension.h} (60%) delete mode 100644 src/RHEO/pair_rheo_tension.cpp diff --git a/src/.gitignore b/src/.gitignore index ef74318fc7..c7e022797f 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -219,6 +219,8 @@ /fix_rheo_pressure.h /fix_rheo_stress.cpp /fix_rheo_stress.h +/fix_rheo_tension.cpp +/fix_rheo_tension.h /fix_rheo_thermal.cpp /fix_rheo_thermal.h /fix_rheo_viscosity.cpp @@ -227,8 +229,6 @@ /pair_rheo.h /pair_rheo_react.cpp /pair_rheo_react.h -/pair_rheo_tension.cpp -/pair_rheo_tension.h /compute_grid.cpp /compute_grid.h diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 7fdff41403..46c1500556 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -355,8 +355,6 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, } } - - if (rho_flag) buf[m++] = rho[j]; diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 230bca8219..88b33c09af 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -87,27 +87,26 @@ void ComputeRHEOSurface::init() cutsq = cut * cut; - // Create rsurface, divr, nsurface arrays if they don't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded + // Create rsurface, divr, nsurface arrays as custom atom properties, + // can print with compute property/atom + // no grow callback as there's no reason to copy/exchange data, manually grow // For B and gradC, create a local array since they are unlikely to be printed + int dim = domain->dimension; int tmp1, tmp2; - int index = atom->find_custom("rheo_divr", tmp1, tmp2); - if (index == -1) index = atom->add_custom("rheo_divr", 1, 0); - divr = atom->dvector[index]; + index_divr = atom->find_custom("rheo_divr", tmp1, tmp2); + if (index_divr == -1) index_divr = atom->add_custom("rheo_divr", 1, 0); + divr = atom->dvector[index_divr]; - index = atom->find_custom("rheo_rsurface", tmp1, tmp2); - if (index == -1) index = atom->add_custom("rheo_rsurface", 1, 0); - rsurface = atom->dvector[index]; + index_rsurf = atom->find_custom("rheo_rsurface", tmp1, tmp2); + if (index_rsurf == -1) index_rsurf = atom->add_custom("rheo_rsurface", 1, 0); + rsurface = atom->dvector[index_rsurf]; - index = atom->find_custom("rheo_nsurface", tmp1, tmp2); - if (index == -1) index = atom->add_custom("rheo_nsurface", 1, 3); - nsurface = atom->darray[index]; + index_nsurf = atom->find_custom("rheo_nsurface", tmp1, tmp2); + if (index_nsurf == -1) index_nsurf = atom->add_custom("rheo_nsurface", 1, dim); + nsurface = atom->darray[index_nsurf]; nmax_store = atom->nmax; - int dim = domain->dimension; memory->create(B, nmax_store, dim * dim, "rheo/surface:B"); memory->create(gradC, nmax_store, dim * dim, "rheo/surface:gradC"); @@ -148,32 +147,21 @@ void ComputeRHEOSurface::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - int nmax = atom->nmax; - if (nmax_store <= nmax) { - memory->grow(divr, nmax, "atom:rheo_divr"); - memory->grow(rsurface, nmax, "atom:rheo_rsurface"); - memory->grow(nsurface, nmax, 3, "atom:rheo_nsurface"); + // Grow and zero arrays + if (nmax_store <= atom->nmax) + grow_arrays(atom->nmax); - memory->grow(B, nmax, dim * dim, "rheo/surface:B"); - memory->grow(gradC, nmax, dim * dim, "rheo/surface:gradC"); - - nmax_store = atom->nmax; - } + size_t nbytes = nmax_store * sizeof(double); + memset(&divr, 0, nbytes); + memset(&rsurface, 0, nbytes); + memset(&nsurface, 0, 3 * nbytes); + memset(&gradC, 0, 3 * 3 * nbytes); + memset(&B, 0, 3 * 3 * nbytes); + // Remove surface settings int nall = nlocal + atom->nghost; - for (i = 0; i < nall; i++) { - for (a = 0; a < dim; a++) { - for (b = 0; b < dim; b++) { - B[i][a * dim + b] = 0.0; - gradC[i][a * dim + b] = 0.0; - } - nsurface[i][a] = 0.0; - } - divr[i] = 0.0; - - // Remove surface settings + for (i = 0; i < nall; i++) status[i] &= SURFACEMASK; - } // loop over neighbors to calculate the average orientation of neighbors for (ii = 0; ii < inum; ii++) { @@ -424,3 +412,25 @@ void ComputeRHEOSurface::unpack_forward_comm(int n, int first, double *buf) } } } + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOSurface::grow_arrays(int nmax) +{ + int dim = domain->dimension; + + // Grow atom variables and reassign pointers + memory->grow(atom->dvector[index_divr], nmax, "atom:rheo_divr"); + memory->grow(atom->dvector[index_rsurf], nmax, "atom:rheo_rsurface"); + memory->grow(atom->darray[index_nsurf], nmax, dim, "atom:rheo_nsurface"); + + divr = atom->dvector[index_divr]; + rsurface = atom->dvector[index_rsurf]; + nsurface = atom->darray[index_nsurf]; + + // Grow local variables + memory->grow(B, nmax, dim * dim, "rheo/surface:B"); + memory->grow(gradC, nmax, dim * dim, "rheo/surface:gradC"); + + nmax_store = atom->nmax; +} diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 1d1cdba3fa..f1b1af7742 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -40,14 +40,18 @@ class ComputeRHEOSurface : public Compute { class FixRHEO *fix_rheo; private: - double cut, cutsq, rho0, threshold_divr; int surface_style, nmax_store, threshold_z, threshold_splash, interface_flag; - double **B, **gradC; int threshold_style, comm_stage; + int index_divr, index_rsurf, index_nsurf; + + double cut, cutsq, rho0, threshold_divr; + double **B, **gradC; class NeighList *list; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; + + void grow_arrays(int); }; } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo_tension.cpp b/src/RHEO/fix_rheo_tension.cpp new file mode 100644 index 0000000000..44bc3bf580 --- /dev/null +++ b/src/RHEO/fix_rheo_tension.cpp @@ -0,0 +1,452 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) +----------------------------------------------------------------------- */ + +#include "fix_rheo_tension.h" + +#include "atom.h" +#include "comm.h" +#include "compute_rheo_kernel.h" +#include "compute_rheo_interface.h" +#include "domain.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "math_extra.h" +#include "memory.h" +#include "modify.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "update.h" +#include "utils.h" + +#include + +using namespace LAMMPS_NS; +using namespace RHEO_NS; +using namespace MathExtra; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg), compute_kernel(nullptr), compute_interface(nullptr), fix_rheo(nullptr) +{ + if (narg != 4) error->all(FLERR,"Illegal fix command"); + alpha = utils::numeric(FLERR,arg[3],false,lmp); + + comm_forward = 3; + comm_reverse = 3; + + // Create cgrad, n, and divr arrays as custom atom properties, + // can print with compute property/atom + // no grow callback as there's no reason to copy/exchange data, manually grow + // For norm, create a local array since they are unlikely to be printed + + int tmp1, tmp2; + index_cgradt = atom->find_custom("cgrad_rheo_tension", tmp1, tmp2); + if (index_cgradt == -1) index_cgradt = atom->add_custom("cgrad_rheo_tension", 1, 3); + cgradt = atom->darray[index_cgradt]; + + index_nt = atom->find_custom("n_rheo_tension", tmp1, tmp2); + if (index_nt == -1) index_nt = atom->add_custom("n_rheo_tension", 1, 3); + nt = atom->darray[index_nt]; + + index_divnt = atom->find_custom("divn_rheo_tension", tmp1, tmp2); + if (index_divnt == -1) index_divnt = atom->add_custom("divn_rheo_tension", 1, 0); + divnt = atom->dvector[index_divnt]; + + norm = nullptr; + nmax_store = 0; +} + +/* ---------------------------------------------------------------------- */ + +FixRHEOTension::~FixRHEOTension() +{ + // Remove custom property if it exists + int tmp1, tmp2, index; + + index = atom->find_custom("cgrad_rheo_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 3); + + index = atom->find_custom("n_rheo_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 3); + + index = atom->find_custom("divn_rheo_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 0); + + memory->destroy(norm); +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOTension::setmask() +{ + int mask = 0; + mask |= POST_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOTension::init() +{ + auto fixes = modify->get_fix_by_style("^rheo$"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/tension"); + fix_rheo = dynamic_cast(fixes[0]); + + compute_kernel = fix_rheo->compute_kernel; + compute_interface = fix_rheo->compute_interface; + interface_flag = fix_rheo->interface_flag; + h = fix_rheo->h; + rho0 = fix_rheo->rho0; + + hsq = h * h; + + neighbor->add_request(this, NeighConst::REQ_DEFAULT); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOTension::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + + +/* ---------------------------------------------------------------------- */ + +void FixRHEOTension::setup(int vflag) +{ + // Grow and populate arrays + post_force(vflag); +} + +/* ---------------------------------------------------------------------- + Calculate and apply tension forces +------------------------------------------------------------------------- */ + +void FixRHEOTension::post_force(int vflag) +{ + int i, j, a, ii, jj, inum, jnum, itype, jtype; + int fluidi, fluidj; + double xtmp, ytmp, ztmp, w, wp, c; + double rhoi, rhoj, Voli, Volj; + double *dWij, *dWji; + double dx[3], ft[3]; + + int *ilist, *jlist, *numneigh, **firstneigh; + double imass, jmass, rsq, r, rinv; + + int nlocal = atom->nlocal; + int newton = force->newton; + int dim = domain->dimension; + + v_init(vflag); + + double **x = atom->x; + double **f = atom->f; + double *rho = atom->rho; + double *mass = atom->mass; + imageint *image = atom->image; + int *type = atom->type; + int *status = atom->status; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + if (nmax_store <= atom->nmax) + grow_arrays(atom->nmax); + + for (i = 0; i < nlocal+atom->nghost; i++) { + cgradt[i][0] = 0.0; + cgradt[i][1] = 0.0; + cgradt[i][2] = 0.0; + norm[i] = 0.0; + divnt[i] = 0.0; + } + + // Calculate color gradient + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + fluidi = !(status[i] & PHASECHECK); + jlist = firstneigh[i]; + jnum = numneigh[i]; + imass = mass[itype]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = lensq3(dx); + + if (rsq > hsq) continue; + + fluidj = !(status[j] & PHASECHECK); + jtype = type[j]; + r = sqrt(rsq); + rinv = 1 / r; + + rhoi = rho[i]; + rhoj = rho[j]; + + // Add corrections for walls + if (interface_flag) { + if (fluidi && (!fluidj)) { + rhoj = compute_interface->correct_rho(j, i); + } else if ((!fluidi) && fluidj) { + rhoi = compute_interface->correct_rho(i, j); + } else if ((!fluidi) && (!fluidj)) { + rhoi = rho0; + rhoj = rho0; + } + } + + Voli = mass[itype] / rhoi; + Volj = mass[jtype] / rhoj; + + wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2],r); + dWij = compute_kernel->dWij; + dWji = compute_kernel->dWji; + + c = 0; + if (itype == jtype) c += rhoi; + c /= (rhoi + rhoj); + + for (a = 0; a < 3; a++) { + cgradt[i][a] -= c * Volj * dWij[a]; + if (newton || j < nlocal) + cgradt[j][a] -= c * Voli * dWji[a]; + } + } + } + + comm_stage = 0; + comm_reverse = 3; + if (newton) comm->reverse_comm(this); + + // Calculate normal direction + double minv; + for (i = 0; i < nlocal; i++) { + minv = 1.0 / sqrt(cgradt[i][0] * cgradt[i][0] + cgradt[i][1] * cgradt[i][1] + cgradt[i][2] * cgradt[i][2]); + + for (a = 0; a < 3; a++) + nt[i][a] = cgradt[i][a] * minv; + } + + comm->forward_comm(this); + + // Calculate divergence + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + fluidi = !(status[i] & PHASECHECK); + jlist = firstneigh[i]; + jnum = numneigh[i]; + imass = mass[itype]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = lensq3(dx); + + if (rsq > hsq) continue; + + fluidj = !(status[j] & PHASECHECK); + jtype = type[j]; + r = sqrt(rsq); + rinv = 1 / r; + + rhoi = rho[i]; + rhoj = rho[j]; + + // Add corrections for walls + if (interface_flag) { + if (fluidi && (!fluidj)) { + rhoj = compute_interface->correct_rho(j, i); + } else if ((!fluidi) && fluidj) { + rhoi = compute_interface->correct_rho(i, j); + } else if ((!fluidi) && (!fluidj)) { + rhoi = rho0; + rhoj = rho0; + } + } + + Voli = mass[itype] / rhoi; + Volj = mass[jtype] / rhoj; + + wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2],r); + dWij = compute_kernel->dWij; + dWji = compute_kernel->dWji; + + for (a = 0; a < 3; a++) { + divnt[i] -= nt[i][a] * Volj * dWij[a]; + norm[i] -= dx[a] * Volj * dWij[a]; + if (newton || j < nlocal) { + divnt[j] -= nt[j][a] * Voli * dWji[a]; + norm[j] += dx[a] * Voli * dWji[a]; + } + } + } + } + + comm_stage = 1; + comm_reverse = 2; + if (newton) comm->reverse_comm(this); + + // Skip forces if it's setup + if (update->setupflag) return; + + // apply force + int prefactor; + double unwrap[3]; + double v[6]; + for (i = 0; i < nlocal; i++) { + itype = type[i]; + divnt[i] /= norm[i]; + + prefactor *= -alpha * divnt[i] / mass[itype]; + + for (a = 0; a < 3; a++) + f[i][a] += prefactor * cgradt[i][a]; + + if (evflag) { + domain->unmap(x[i], image[i], unwrap); + v[0] = prefactor * cgradt[i][0] * unwrap[0]; + v[1] = prefactor * cgradt[i][1] * unwrap[1]; + v[2] = prefactor * cgradt[i][2] * unwrap[2]; + v[3] = prefactor * cgradt[i][0] * unwrap[1]; + v[4] = prefactor * cgradt[i][0] * unwrap[2]; + v[5] = prefactor * cgradt[i][1] * unwrap[2]; + v_tally(i, v); + } + } + + + + if (evflag) { + + } + +} + + +/* ---------------------------------------------------------------------- */ + +int FixRHEOTension::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) +{ + int i, j, a, m; + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + for (a = 0; a < 3; a++) + buf[m++] = nt[j][a]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOTension::unpack_forward_comm(int n, int first, double *buf) +{ + int i, a, m, last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) + for (a = 0; a < 3; a++) + nt[i][a] = buf[m++]; +} + + +/* ---------------------------------------------------------------------- */ + +int FixRHEOTension::pack_reverse_comm(int n, int first, double *buf) +{ + int i, a, m, last; + + m = 0; + last = first + n; + if (comm_stage == 0) + for (i = first; i < last; i++) + for (a = 0; a < 3; a++) + buf[m++] = cgradt[i][a]; + else + for (i = first; i < last; i++) { + buf[m++] = norm[i]; + buf[m++] = divnt[i]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i, j, a, m; + + m = 0; + if (comm_stage == 0) + for (i = 0; i < n; i++) { + j = list[i]; + for (a = 0; a < 3; a++) + cgradt[j][a] += buf[m++]; + } + else + for (i = 0; i < n; i++) { + j = list[i]; + norm[j] += buf[m++]; + divnt[j] += buf[m++]; + } +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOTension::grow_arrays(int nmax) +{ + // Grow atom variables and reassign pointers + memory->grow(atom->darray[index_cgradt], nmax, 3, "atom:rheo_cgradt"); + memory->grow(atom->darray[index_nt], nmax, 3, "atom:rheo_nt"); + memory->grow(atom->dvector[index_divnt], nmax, "atom:rheo_divnt"); + + cgradt = atom->darray[index_cgradt]; + nt = atom->darray[index_nt]; + divnt = atom->dvector[index_divnt]; + + // Grow local variables + memory->grow(norm, nmax, "rheo/tension:norm"); + + nmax_store = atom->nmax; +} \ No newline at end of file diff --git a/src/RHEO/pair_rheo_tension.h b/src/RHEO/fix_rheo_tension.h similarity index 60% rename from src/RHEO/pair_rheo_tension.h rename to src/RHEO/fix_rheo_tension.h index 2a046ff324..74b8b71436 100644 --- a/src/RHEO/pair_rheo_tension.h +++ b/src/RHEO/fix_rheo_tension.h @@ -11,44 +11,45 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -#ifdef PAIR_CLASS +#ifdef FIX_CLASS // clang-format off -PairStyle(rheo/tension,PairRHEOTension) +FixStyle(rheo/tension,FixRHEOTension) // clang-format on #else -#ifndef LMP_PAIR_RHEO_TENSION_H -#define LMP_PAIR_RHEO_TENSION_H +#ifndef LMP_FIX_RHEO_TENSION_H +#define LMP_FIX_RHEO_TENSION_H -#include "pair.h" +#include "fix.h" namespace LAMMPS_NS { -class PairRHEOTension : public Pair { +class FixRHEOTension : public Fix { public: - PairRHEOTension(class LAMMPS *); - ~PairRHEOTension() override; - void compute(int, int) override; - void settings(int, char **) override; - void coeff(int, char **) override; - void setup() override; - void init_style() override; - double init_one(int, int) override; + FixRHEOTension(class LAMMPS *, int, char **); + ~FixRHEOTension() override; + int setmask() override; + void init() override; + void init_list(int, class NeighList *) override; + void setup(int) override; + void post_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; int pack_reverse_comm(int, int, double *) override; void unpack_reverse_comm(int, int *, double *) override; + void grow_arrays(int) override; - protected: - int nmax_store; - double **nt, *ct; - double **alpha; - double h, hsq, hinv, hinv3; + private: + int nmax_store, comm_stage, interface_flag; + int index_nt, index_cgradt, index_divnt; - void allocate(); + double **nt, **cgradt, *divnt, *norm; + double alpha, h, hsq, hinv, hinv3, rho0; class ComputeRHEOKernel *compute_kernel; + class ComputeRHEOInterface *compute_interface; class FixRHEO *fix_rheo; + class NeighList *list; }; } // namespace LAMMPS_NS diff --git a/src/RHEO/pair_rheo_tension.cpp b/src/RHEO/pair_rheo_tension.cpp deleted file mode 100644 index ef0d0b60b4..0000000000 --- a/src/RHEO/pair_rheo_tension.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* ---------------------------------------------------------------------- - 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. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: - Joel Clemmer (SNL) ------------------------------------------------------------------------ */ - -#include "pair_rheo_tension.h" - -#include "atom.h" -#include "comm.h" -#include "compute_rheo_kernel.h" -#include "domain.h" -#include "error.h" -#include "fix_rheo.h" -#include "force.h" -#include "math_extra.h" -#include "memory.h" -#include "modify.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "update.h" -#include "utils.h" - -#include - -using namespace LAMMPS_NS; -using namespace RHEO_NS; -using namespace MathExtra; - -static constexpr double EPSILON = 1e-2; - -/* ---------------------------------------------------------------------- */ - -PairRHEOTension::PairRHEOTension(LAMMPS *lmp) : - Pair(lmp), compute_kernel(nullptr), fix_rheo(nullptr) -{ - restartinfo = 0; - single_enable = 0; - - comm_forward = 3; - comm_reverse = 3; -} - -/* ---------------------------------------------------------------------- */ - -PairRHEOTension::~PairRHEOTension() -{ - // Remove custom property if it exists - int tmp1, tmp2, index; - - index = atom->find_custom("rheo_c_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - - index = atom->find_custom("rheo_n_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 3); - - if (allocated) { - memory->destroy(alpha); - memory->destroy(setflag); - memory->destroy(cutsq); - } -} - -/* ---------------------------------------------------------------------- */ - -void PairRHEOTension::compute(int eflag, int vflag) -{ - int i, j, a, b, ii, jj, inum, jnum, itype, jtype; - int fluidi, fluidj; - double xtmp, ytmp, ztmp, w, wp; - double rhoi, rhoj, voli, volj; - double *dWij, *dWji; - double dx[3], ft[3]; - - int *ilist, *jlist, *numneigh, **firstneigh; - double imass, jmass, rsq, r, rinv; - - int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; - int dim = domain->dimension; - - ev_init(eflag, vflag); - - double **x = atom->x; - double **f = atom->f; - double *rho = atom->rho; - double *mass = atom->mass; - double *special_lj = force->special_lj; - int *type = atom->type; - int *status = atom->status; - tagint *tag = atom->tag; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; -/* - int nmax = atom->nmax; - if (nmax_store <= nmax) { - memory->grow(ct, nmax, "atom:rheo_c_tension"); - memory->grow(nnt_tension, nmax, 3, "atom:rheo_n_tension"); - nmax_store = atom->nmax; - } - - // loop over neighbors of my atoms - - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - imass = mass[itype]; - rhoi = rho[i]; - voli = imass / rhoi; - fluidi = !(status[i] & PHASECHECK); - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - dx[0] = xtmp - x[j][0]; - dx[1] = ytmp - x[j][1]; - dx[2] = ztmp - x[j][2]; - rsq = lensq3(dx); - jtype = type[j]; - - if (rsq > hsq) continue; - - r = sqrt(rsq); - rinv = 1 / r; - - jmass = mass[jtype]; - rhoj = rho[j]; - volj = jmass / rhoj; - fluidj = !(status[j] & PHASECHECK); - - wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2],r); - dWij = compute_kernel->dWij; - dWji = compute_kernel->dWji; - - f[i][0] += ft[0]; - f[i][1] += ft[1]; - f[i][2] += ft[2]; - - if (evflag) // Does not account for unbalanced forces - ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); - - if (newton_pair || j < nlocal) { - - f[j][0] -= ft[0]; - f[j][1] -= ft[1]; - f[j][2] -= ft[2]; - } - } - } - - if (vflag_fdotr) virial_fdotr_compute(); - - comm->reverse_comm(this); - comm->forward_comm(this); -*/ -} - -/* ---------------------------------------------------------------------- - allocate all arrays - ------------------------------------------------------------------------- */ - -void PairRHEOTension::allocate() -{ - allocated = 1; - int n = atom->ntypes; - - memory->create(setflag, n + 1, n + 1, "pair:setflag"); - for (int i = 1; i <= n; i++) - for (int j = i; j <= n; j++) - setflag[i][j] = 0; - - memory->create(alpha, n + 1, n + 1, "pair:alpha"); - memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); -} - -/* ---------------------------------------------------------------------- - global settings - ------------------------------------------------------------------------- */ - -void PairRHEOTension::settings(int narg, char **arg) -{ -} - -/* ---------------------------------------------------------------------- - set coeffs for one or more type pairs - ------------------------------------------------------------------------- */ - -void PairRHEOTension::coeff(int narg, char **arg) -{ - if (narg != 3) - error->all(FLERR,"Incorrect number of args for pair_style rheo coefficients"); - if (!allocated) - allocate(); - - int ilo, ihi, jlo, jhi; - utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); - utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); - - double alpha_one = utils::numeric(FLERR, arg[2], false, lmp); - - int count = 0; - for (int i = ilo; i <= ihi; i++) { - for (int j = 0; j <= atom->ntypes; j++) { - alpha[i][j] = alpha_one; - setflag[i][j] = 1; - count++; - } - } - - if (count == 0) - error->all(FLERR,"Incorrect args for pair rheo/tension coefficients"); -} - -/* ---------------------------------------------------------------------- - setup specific to this pair style - ------------------------------------------------------------------------- */ - -void PairRHEOTension::setup() -{ - auto fixes = modify->get_fix_by_style("rheo"); - if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use pair rheo"); - fix_rheo = dynamic_cast(fixes[0]); - /* - compute_kernel = fix_rheo->compute_kernel; - compute_grad = fix_rheo->compute_grad; - compute_interface = fix_rheo->compute_interface; - h = fix_rheo->h; - csq = fix_rheo->csq; - rho0 = fix_rheo->rho0; - - hsq = h * h; - hinv = 1.0 / h; - hinv3 = hinv * 3.0; - */ -} - -/* ---------------------------------------------------------------------- - init specific to this pair style -------------------------------------------------------------------------- */ - -void PairRHEOTension::init_style() -{ - neighbor->add_request(this); - - - // Create c_tension arrays n_tension arrays if they don't already exist - // Create a custom atom property so it works with compute property/atom - // Do not create grow callback as there's no reason to copy/exchange data - // Manually grow if nmax_store exceeded - // For B and gradC, create a local array since they are unlikely to be printed - - int tmp1, tmp2; - int index = atom->find_custom("rheo_c_tension", tmp1, tmp2); - if (index == -1) index = atom->add_custom("rheo_c_tension", 1, 0); - ct = atom->dvector[index]; - - index = atom->find_custom("rheo_n_tension", tmp1, tmp2); - if (index == -1) index = atom->add_custom("rheo_n_tension", 1, 3); - nt = atom->darray[index]; - - nmax_store = atom->nmax; -} - -/* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i - ------------------------------------------------------------------------- */ - -double PairRHEOTension::init_one(int i, int j) -{ - if (setflag[i][j] == 0) - error->all(FLERR,"All pair rheo/tension coeffs are not set"); - - alpha[j][i] = alpha[i][j]; - - return h; -} - - -/* ---------------------------------------------------------------------- */ - -int PairRHEOTension::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) -{ - /* - int i,j,k,m; - m = 0; - double *rho = atom->rho; - - for (i = 0; i < n; i++) { - j = list[i]; - if (comm_stage == 0) { - buf[m++] = fp_store[j][0]; - buf[m++] = fp_store[j][1]; - buf[m++] = fp_store[j][2]; - } else { - buf[m++] = chi[j]; - buf[m++] = rho[j]; - } - } - return m; - */ -} - -/* ---------------------------------------------------------------------- */ - -void PairRHEOTension::unpack_forward_comm(int n, int first, double *buf) -{ - /* - int i, k, m, last; - double *rho = atom->rho; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (comm_stage == 0) { - fp_store[i][0] = buf[m++]; - fp_store[i][1] = buf[m++]; - fp_store[i][2] = buf[m++]; - } else { - chi[i] = buf[m++]; - rho[i] = buf[m++]; - } - } - */ -} - - -/* ---------------------------------------------------------------------- */ - -int PairRHEOTension::pack_reverse_comm(int n, int first, double *buf) -{ - /* - int i, k, m, last; - double **fp_store = compute_interface->fp_store; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = fp_store[i][0]; - buf[m++] = fp_store[i][1]; - buf[m++] = fp_store[i][2]; - } - - return m; - */ -} - -/* ---------------------------------------------------------------------- */ - -void PairRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) -{ - /* - int i, j, k, m; - double **fp_store = compute_interface->fp_store; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - fp_store[j][0] += buf[m++]; - fp_store[j][1] += buf[m++]; - fp_store[j][2] += buf[m++]; - } - */ -} From 5b14b7c86c25d3ff5d522d101f69b998752df486 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 1 Nov 2023 13:42:33 -0600 Subject: [PATCH 053/385] Fixing gitignore --- src/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/.gitignore b/src/.gitignore index c7e022797f..1e634782dc 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -199,6 +199,8 @@ /atom_vec_rheo.cpp /atom_vec_rheo.h +/atom_vec_rheo_thermal.cpp +/atom_vec_rheo_thermal.h /compute_rheo_grad.cpp /compute_rheo_grad.h /compute_rheo_interface.cpp From 16a3abdadd53f2e6ec2bd50118db4dfe70a9fb53 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 3 Nov 2023 13:33:03 -0600 Subject: [PATCH 054/385] Filling in tension and react --- src/RHEO/fix_rheo_tension.cpp | 44 +++-- src/RHEO/fix_rheo_tension.h | 4 +- src/RHEO/pair_rheo_react.cpp | 301 +++++++++++++--------------------- src/RHEO/pair_rheo_react.h | 8 +- 4 files changed, 150 insertions(+), 207 deletions(-) diff --git a/src/RHEO/fix_rheo_tension.cpp b/src/RHEO/fix_rheo_tension.cpp index 44bc3bf580..047f1d217e 100644 --- a/src/RHEO/fix_rheo_tension.cpp +++ b/src/RHEO/fix_rheo_tension.cpp @@ -70,6 +70,10 @@ FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : if (index_divnt == -1) index_divnt = atom->add_custom("divn_rheo_tension", 1, 0); divnt = atom->dvector[index_divnt]; + index_ft = atom->find_custom("f_rheo_tension", tmp1, tmp2); + if (index_ft == -1) index_ft = atom->add_custom("f_rheo_tension", 1, 3); + ft = atom->darray[index_ft]; + norm = nullptr; nmax_store = 0; } @@ -90,6 +94,9 @@ FixRHEOTension::~FixRHEOTension() index = atom->find_custom("divn_rheo_tension", tmp1, tmp2); if (index != -1) atom->remove_custom(index, 1, 0); + index = atom->find_custom("f_rheo_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 3); + memory->destroy(norm); } @@ -148,7 +155,7 @@ void FixRHEOTension::post_force(int vflag) double xtmp, ytmp, ztmp, w, wp, c; double rhoi, rhoj, Voli, Volj; double *dWij, *dWji; - double dx[3], ft[3]; + double dx[3]; int *ilist, *jlist, *numneigh, **firstneigh; double imass, jmass, rsq, r, rinv; @@ -234,7 +241,7 @@ void FixRHEOTension::post_force(int vflag) dWji = compute_kernel->dWji; c = 0; - if (itype == jtype) c += rhoi; + if (itype != jtype) c += rhoi; c /= (rhoi + rhoj); for (a = 0; a < 3; a++) { @@ -252,7 +259,9 @@ void FixRHEOTension::post_force(int vflag) // Calculate normal direction double minv; for (i = 0; i < nlocal; i++) { - minv = 1.0 / sqrt(cgradt[i][0] * cgradt[i][0] + cgradt[i][1] * cgradt[i][1] + cgradt[i][2] * cgradt[i][2]); + minv = sqrt(cgradt[i][0] * cgradt[i][0] + cgradt[i][1] * cgradt[i][1] + cgradt[i][2] * cgradt[i][2]); + + if (minv != 0) minv = 1 / minv; for (a = 0; a < 3; a++) nt[i][a] = cgradt[i][a] * minv; @@ -310,11 +319,13 @@ void FixRHEOTension::post_force(int vflag) dWij = compute_kernel->dWij; dWji = compute_kernel->dWji; + if (itype != jtype) continue; // have to think about this... + for (a = 0; a < 3; a++) { - divnt[i] -= nt[i][a] * Volj * dWij[a]; + divnt[i] -= (nt[i][a]-nt[j][a]) * Volj * dWij[a]; norm[i] -= dx[a] * Volj * dWij[a]; if (newton || j < nlocal) { - divnt[j] -= nt[j][a] * Voli * dWji[a]; + divnt[j] += (nt[i][a]-nt[j][a]) * Voli * dWji[a]; norm[j] += dx[a] * Voli * dWji[a]; } } @@ -329,17 +340,23 @@ void FixRHEOTension::post_force(int vflag) if (update->setupflag) return; // apply force - int prefactor; + double prefactor; double unwrap[3]; double v[6]; for (i = 0; i < nlocal; i++) { itype = type[i]; - divnt[i] /= norm[i]; - prefactor *= -alpha * divnt[i] / mass[itype]; + if (norm[i] != 0) + divnt[i] /= norm[i]; + else + divnt[i] = 0.0; - for (a = 0; a < 3; a++) + prefactor = -alpha * divnt[i]; + + for (a = 0; a < 3; a++) { f[i][a] += prefactor * cgradt[i][a]; + ft[i][a] = prefactor * cgradt[i][a]; + } if (evflag) { domain->unmap(x[i], image[i], unwrap); @@ -352,13 +369,6 @@ void FixRHEOTension::post_force(int vflag) v_tally(i, v); } } - - - - if (evflag) { - - } - } @@ -440,10 +450,12 @@ void FixRHEOTension::grow_arrays(int nmax) memory->grow(atom->darray[index_cgradt], nmax, 3, "atom:rheo_cgradt"); memory->grow(atom->darray[index_nt], nmax, 3, "atom:rheo_nt"); memory->grow(atom->dvector[index_divnt], nmax, "atom:rheo_divnt"); + memory->grow(atom->darray[index_ft], nmax, 3, "atom:rheo_ft"); cgradt = atom->darray[index_cgradt]; nt = atom->darray[index_nt]; divnt = atom->dvector[index_divnt]; + ft = atom->darray[index_ft]; // Grow local variables memory->grow(norm, nmax, "rheo/tension:norm"); diff --git a/src/RHEO/fix_rheo_tension.h b/src/RHEO/fix_rheo_tension.h index 74b8b71436..11bc209d88 100644 --- a/src/RHEO/fix_rheo_tension.h +++ b/src/RHEO/fix_rheo_tension.h @@ -41,9 +41,9 @@ class FixRHEOTension : public Fix { private: int nmax_store, comm_stage, interface_flag; - int index_nt, index_cgradt, index_divnt; + int index_nt, index_cgradt, index_divnt, index_ft; - double **nt, **cgradt, *divnt, *norm; + double **nt, **cgradt, *divnt, *norm, **ft; double alpha, h, hsq, hinv, hinv3, rho0; class ComputeRHEOKernel *compute_kernel; diff --git a/src/RHEO/pair_rheo_react.cpp b/src/RHEO/pair_rheo_react.cpp index 7ec63bb2a9..4846e077f6 100644 --- a/src/RHEO/pair_rheo_react.cpp +++ b/src/RHEO/pair_rheo_react.cpp @@ -20,6 +20,7 @@ #include "atom.h" #include "comm.h" +#include "compute_rheo_surface.h" #include "error.h" #include "fix.h" #include "fix_dummy.h" @@ -35,6 +36,7 @@ #include "utils.h" using namespace LAMMPS_NS; +using namespace RHEO_NS; /* ---------------------------------------------------------------------- */ @@ -45,6 +47,7 @@ PairRHEOReact::PairRHEOReact(LAMMPS *lmp) : Pair(lmp), size_history = 2; beyond_contact = 1; comm_reverse = 1; + nondefault_history_transfer = 1; // create dummy fix as placeholder for FixNeighHistory // this is so final order of Modify:fix will conform to input script @@ -92,8 +95,6 @@ PairRHEOReact::~PairRHEOReact() memory->destroy(gamma); memory->destroy(t_form); memory->destroy(rlimit); - memory->destroy(sigma); - memory->destroy(krepel); } memory->destroy(dbond); @@ -103,23 +104,21 @@ PairRHEOReact::~PairRHEOReact() void PairRHEOReact::compute(int eflag, int vflag) { - int i,j,ii,jj,inum,jnum; - double xtmp,ytmp,ztmp,delx,dely,delz; - double rsq,r,rinv,r0; - double vxtmp,vytmp,vztmp,delvx,delvy,delvz; - double fpair,dot,evdwl,smooth; + int i, j, ii, jj, inum, jnum, fluidi, fluidj; + double xtmp, ytmp, ztmp, delx, dely, delz; + double vxtmp, vytmp, vztmp, delvx, delvy, delvz; + double rsq, r, rinv, r0, fpair, dot, smooth; int itype, jtype; - int *ilist,*jlist,*numneigh,**firstneigh; - int *saved,**firstsaved; - double *data,*alldata,**firstdata; + int *ilist, *jlist, *numneigh, **firstneigh; + int *saved, **firstsaved; + double *data, *alldata, **firstdata; ev_init(eflag,vflag); int bondupdate = 1; if (update->setupflag) bondupdate = 0; - - dt = update->dt; + double dt = update->dt; double **x = atom->x; double **v = atom->v; @@ -128,6 +127,7 @@ void PairRHEOReact::compute(int eflag, int vflag) int *status = atom->status; int *mask = atom->mask; int *nbond = atom->ivector[index_nb]; + double *rsurf = compute_surface->rsurface; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; @@ -139,17 +139,15 @@ void PairRHEOReact::compute(int eflag, int vflag) firstsaved = fix_history->firstflag; firstdata = fix_history->firstvalue; - if (atom->nmax > nmax){ - nmax = atom->nmax; + if (atom->nmax > nmax_store){ + nmax_store = atom->nmax; memory->destroy(dbond); - memory->create(dbond, nmax, "rheo/react:dbond"); + memory->create(dbond, nmax_store, "rheo/react:dbond"); } - // Switch to no shift if it has bonds (could have just been changed from reactive) - for(i = 0; i < nmax; i++) { - dbond[i] = 0; - } -/* + size_t nbytes = nmax_store * sizeof(int); + memset(&dbond, 0, nbytes); + // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; @@ -160,30 +158,30 @@ void PairRHEOReact::compute(int eflag, int vflag) vxtmp = v[i][0]; vytmp = v[i][1]; vztmp = v[i][2]; + fluidi = !(status[i] & PHASECHECK); + saved = firstsaved[i]; alldata = firstdata[i]; jlist = firstneigh[i]; jnum = numneigh[i]; - for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; jtype = type[j]; + fluidj = !(status[j] & PHASECHECK); data = &alldata[2*jj]; - // If not bonded and there's an internal fluid particle, unsave any data and skip if (!(saved[jj] == 1 && data[0] > 0)) { - if ((status[i] <= FixRHEO::FLUID_MAX && rsurf[i] > rlimit[itype][jtype]) || (status[j] <= FixRHEO::FLUID_MAX && rsurf[j] > rlimit[itype][jtype])) { + if ((fluidi && (rsurf[i] > rlimit[itype][jtype])) || (fluidj && (rsurf[j] > rlimit[itype][jtype]))) { saved[jj] = 0; continue; } } // If both are solid, unbond and skip - if ((status[i] == FixRHEO::SOLID || status[i] == FixRHEO::FREEZING) && - (status[j] == FixRHEO::SOLID || status[j] == FixRHEO::FREEZING)) { + if (!fluidi && !fluidj) { //If bonded, deincrement if (saved[jj] == 1 && data[0] > 0) { dbond[i] --; @@ -193,12 +191,10 @@ void PairRHEOReact::compute(int eflag, int vflag) continue; } - // Remaining options are react+sold, react+react, react+surf/fluid, or surf/fluid+surf/fluid - delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; - rsq = delx*delx + dely*dely + delz*delz; + rsq = delx * delx + dely * dely + delz * delz; // If unbonded and beyond bond distance, unsave and skip if (data[0] == -1 && rsq > cutbsq[itype][jtype]) { @@ -217,7 +213,7 @@ void PairRHEOReact::compute(int eflag, int vflag) // Check for bond formation (unbonded) or breakage (bonded) if (data[0] == -1) { // If unbonded, check if we count down to bonding if both on surface (not given for r or s) - if (bondupdate && rsurf[i] <= rlimit[itype][jtype] && rsurf[j] <= rlimit[itype][jtype]) { + if (bondupdate && (rsurf[i] <= rlimit[itype][jtype]) && (rsurf[j] <= rlimit[itype][jtype])) { data[1] += dt; if (data[1] >= t_form[itype][jtype]) { data[0] = r; @@ -229,7 +225,7 @@ void PairRHEOReact::compute(int eflag, int vflag) } else { // If bonded, check if breaks in tension r0 = data[0]; - if (r > ((1.0+eps[itype][jtype])*r0)) { + if (r > ((1.0 + eps[itype][jtype]) * r0)) { saved[jj] = 0; dbond[i] --; dbond[j] --; @@ -237,89 +233,57 @@ void PairRHEOReact::compute(int eflag, int vflag) } } - // Apply forces + // Skip if unbonded + if (data[0] <= 0) continue; + delvx = vxtmp - v[j][0]; delvy = vytmp - v[j][1]; delvz = vztmp - v[j][2]; - rinv = 1.0/r; + rinv = 1.0 / r; + r0 = data[0]; - if (data[0] <= 0) { - // Skip if either is fluid (only include r+s or r+r since already skipped s+s) - if (status[i] <= FixRHEO::FLUID_MAX || status[j] <= FixRHEO::FLUID_MAX) continue; + fpair = k[itype][jtype] * (r0 - r); - // Skip if out of contact - if (rsq > sigma[itype][jtype]*sigma[itype][jtype]) continue; + dot = delx * delvx + dely * delvy + delz * delvz; + fpair -= gamma[itype][jtype] * dot * rinv; - fpair = krepel[itype][jtype]*(sigma[itype][jtype]-r); - if (eflag) - evdwl = -0.5*krepel[itype][jtype]*(sigma[itype][jtype]-r)*(sigma[itype][jtype]-r); - - smooth = rsq/(sigma[itype][jtype]*sigma[itype][jtype]); + smooth = 1.0; + if (r > r0) { + smooth = (r - r0) / (r0 * eps[itype][jtype]); smooth *= smooth; - smooth = 1.0 - smooth; - dot = delx*delvx + dely*delvy + delz*delvz; - fpair -= gamma[itype][jtype]*dot*smooth*rinv; - - fpair *= rinv; - - f[i][0] += delx*fpair; - f[i][1] += dely*fpair; - f[i][2] += delz*fpair; - if (newton_pair || j < nlocal) { - f[j][0] -= delx*fpair; - f[j][1] -= dely*fpair; - f[j][2] -= delz*fpair; - } - - if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz); - } else { - // Bonded - r0 = data[0]; - - fpair = k[itype][jtype]*(r0-r); - if (evflag) evdwl = -0.5*fpair*(r0-r); - - dot = delx*delvx + dely*delvy + delz*delvz; - fpair -= gamma[itype][jtype]*dot*rinv; - - smooth = 1.0; - if (r > r0) { - smooth = (r-r0)/(r0*eps[itype][jtype]); - smooth *= smooth; - smooth *= smooth; - smooth = 1 - smooth; - } - - fpair *= rinv*smooth; - - f[i][0] += delx*fpair; - f[i][1] += dely*fpair; - f[i][2] += delz*fpair; - if (newton_pair || j < nlocal) { - f[j][0] -= delx*fpair; - f[j][1] -= dely*fpair; - f[j][2] -= delz*fpair; - } - - if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz); + smooth *= smooth; + smooth = 1 - smooth; } + + fpair *= rinv * smooth; + + f[i][0] += delx * fpair; + f[i][1] += dely * fpair; + f[i][2] += delz * fpair; + if (newton_pair || j < nlocal) { + f[j][0] -= delx * fpair; + f[j][1] -= dely * fpair; + f[j][2] -= delz * fpair; + } + + if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.0, 0.0, fpair, delx, dely, delz); } } // Communicate changes in nbond - if(newton_pair) comm->reverse_comm_pair(this); + if (newton_pair) comm->reverse_comm(this); for(i = 0; i < nlocal; i++) { + fluidi = !(status[i] & PHASECHECK); nbond[i] += dbond[i]; // If it has bonds it is reactive (no shifting) // If a reactive particle breaks all bonds, return to fluid // Keep it non-shifting for this timestep to be safe - if (nbond[i] != 0 && status[i] <= FixRHEO::FLUID_MAX) status[i] = FixRHEO::FLUID_NO_SHIFT; + if (nbond[i] != 0 && fluidi) status[i] |= STATUS_NO_SHIFT; } if (vflag_fdotr) virial_fdotr_compute(); - */ } /* ---------------------------------------------------------------------- @@ -331,22 +295,20 @@ void PairRHEOReact::allocate() allocated = 1; int n = atom->ntypes; - memory->create(setflag,n+1,n+1,"pair:setflag"); + memory->create(setflag, n+1, n+1,"pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; - memory->create(cut,n+1,n+1,"pair:cut"); - memory->create(cutbond,n+1,n+1,"pair:cutbond"); - memory->create(cutsq,n+1,n+1,"pair:cutsq"); - memory->create(cutbsq,n+1,n+1,"pair:cutbsq"); - memory->create(k,n+1,n+1,"pair:k"); - memory->create(eps,n+1,n+1,"pair:eps"); - memory->create(gamma,n+1,n+1,"pair:gamma"); - memory->create(t_form,n+1,n+1,"pair:t_form"); - memory->create(rlimit,n+1,n+1,"pair:rlimit"); - memory->create(sigma,n+1,n+1,"pair:sigma"); - memory->create(krepel,n+1,n+1,"pair:krepel"); + memory->create(cut, n+1, n+1,"pair:cut"); + memory->create(cutbond, n+1, n+1,"pair:cutbond"); + memory->create(cutsq, n+1, n+1,"pair:cutsq"); + memory->create(cutbsq, n+1, n+1,"pair:cutbsq"); + memory->create(k, n+1, n+1,"pair:k"); + memory->create(eps, n+1, n+1,"pair:eps"); + memory->create(gamma, n+1, n+1,"pair:gamma"); + memory->create(t_form, n+1, n+1,"pair:t_form"); + memory->create(rlimit, n+1, n+1,"pair:rlimit"); } /* ---------------------------------------------------------------------- @@ -363,25 +325,23 @@ void PairRHEOReact::settings(int narg, char **arg) void PairRHEOReact::coeff(int narg, char **arg) { - if (narg != 11) error->all(FLERR,"Incorrect args for pair coefficients"); + if (narg != 9) error->all(FLERR,"Incorrect args for pair coefficients"); if (!allocated) allocate(); - int ilo,ihi,jlo,jhi; - utils::bounds(FLERR,arg[0],1, atom->ntypes, ilo, ihi,error); - utils::bounds(FLERR,arg[1],1, atom->ntypes, jlo, jhi,error); + int ilo, ihi, jlo, jhi; + utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); + utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); - double cut_one = utils::numeric(FLERR,arg[2],false,lmp); - double cutb_one = utils::numeric(FLERR,arg[3],false,lmp); - double k_one = utils::numeric(FLERR,arg[4],false,lmp); - double eps_one = utils::numeric(FLERR,arg[5],false,lmp); - double gamma_one = utils::numeric(FLERR,arg[6],false,lmp); - double t_form_one = utils::numeric(FLERR,arg[7],false,lmp); - double rlimit_one = utils::numeric(FLERR,arg[8],false,lmp); - double sigma_one = utils::numeric(FLERR,arg[9],false,lmp); - double krepel_one = utils::numeric(FLERR,arg[10],false,lmp); + double cut_one = utils::numeric(FLERR, arg[2], false, lmp); + double cutb_one = utils::numeric(FLERR, arg[3], false, lmp); + double k_one = utils::numeric(FLERR, arg[4], false, lmp); + double eps_one = utils::numeric(FLERR, arg[5], false, lmp); + double gamma_one = utils::numeric(FLERR, arg[6], false, lmp); + double t_form_one = utils::numeric(FLERR, arg[7], false, lmp); + double rlimit_one = utils::numeric(FLERR, arg[8], false, lmp); if (k_one < 0.0 || eps_one < 0.0 || - t_form_one < 0.0 || (1.0+eps_one)*cutb_one > cut_one) + t_form_one < 0.0 || (1.0 + eps_one) * cutb_one > cut_one) error->all(FLERR,"Illegal pair_style command"); int count = 0; @@ -394,8 +354,6 @@ void PairRHEOReact::coeff(int narg, char **arg) gamma[i][j] = gamma_one; t_form[i][j] = t_form_one; rlimit[i][j] = rlimit_one; - sigma[i][j] = sigma_one; - krepel[i][j] = krepel_one; setflag[i][j] = 1; count++; } @@ -414,47 +372,31 @@ void PairRHEOReact::init_style() //neighbor->requests[irequest]->history = 1; if (fix_history == nullptr) { - - // Don't want history[i][j] = -history[j][i] - nondefault_history_transfer = 1; - - char dnumstr[16]; - sprintf(dnumstr,"%d",size_history); - char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY_RHEO_REACT"; - fixarg[1] = (char *) "all"; - fixarg[2] = (char *) "NEIGH_HISTORY"; - fixarg[3] = dnumstr; - modify->replace_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY",4,fixarg,1); - delete [] fixarg; - int ifix = modify->find_fix("NEIGH_HISTORY_RHEO_REACT"); - fix_history = (FixNeighHistory *) modify->fix[ifix]; + auto cmd = fmt::format("NEIGH_HISTORY_RHEO_REACT {} all NEIGH_HISTORY {}", instance_me, size_history); + fix_history = dynamic_cast( + modify->replace_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY" + std::to_string(instance_me), cmd, 1)); fix_history->pair = this; fix_dummy = nullptr; } - - //int temp_flag; - //index_rsurf = atom->find_custom("rsurf", temp_flag); - //if ((index_rsurf < 0) || (temp_flag != 1)) - // error->all(FLERR, "Pair rheo/react can't find fix property/atom rsurf"); } /* ---------------------------------------------------------------------- setup specific to this pair style ------------------------------------------------------------------------- */ -void PairRHEOReact::setup() { - /* - int ifix = modify->find_fix_by_style("rheo"); - if (ifix == -1) error->all(FLERR, "Using pair rheo/react without fix rheo"); - fix_rheo = ((FixRHEO *) modify->fix[ifix]); +void PairRHEOReact::setup() +{ + auto fixes = modify->get_fix_by_style("^rheo$"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/tension"); + fix_rheo = dynamic_cast(fixes[0]); - ifix = modify->find_fix_by_style("rheo/surface"); - if (ifix == -1) error->all(FLERR, "Using pair rheo/react without fix rheo/surface"); + if (!fix_rheo->surface_flag) error->all(FLERR, + "Pair rheo/react requires surface calculation in fix rheo"); + + compute_surface = fix_rheo->compute_surface; if (force->newton_pair == 0) error->all(FLERR, "Pair rheo/react needs newton pair on for bond changes to be consistent"); - */ } /* ---------------------------------------------------------------------- @@ -465,9 +407,7 @@ double PairRHEOReact::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); - double einv = 1/eps[i][j]; - - cutbsq[i][j] = cutbond[i][j]*cutbond[i][j]; + cutbsq[i][j] = cutbond[i][j] * cutbond[i][j]; cutbsq[j][i] = cutbsq[i][j]; cut[j][i] = cut[i][j]; @@ -477,8 +417,6 @@ double PairRHEOReact::init_one(int i, int j) gamma[j][i] = gamma[i][j]; t_form[j][i] = t_form[i][j]; rlimit[j][i] = rlimit[i][j]; - sigma[j][i] = sigma[i][j]; - krepel[j][i] = krepel[i][j]; return cut[i][j]; } @@ -494,17 +432,15 @@ void PairRHEOReact::write_restart(FILE *fp) int i,j; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) - fwrite(&setflag[i][j],sizeof(int),1,fp); + fwrite(&setflag[i][j], sizeof(int), 1, fp); if (setflag[i][j]) { - fwrite(&cut[i][j],sizeof(double),1,fp); - fwrite(&cutbond[i][j],sizeof(double),1,fp); - fwrite(&k[i][j],sizeof(double),1,fp); - fwrite(&eps[i][j],sizeof(double),1,fp); - fwrite(&gamma[i][j],sizeof(double),1,fp); - fwrite(&t_form[i][j],sizeof(double),1,fp); - fwrite(&rlimit[i][j],sizeof(double),1,fp); - fwrite(&sigma[i][j],sizeof(double),1,fp); - fwrite(&krepel[i][j],sizeof(double),1,fp); + fwrite(&cut[i][j], sizeof(double), 1, fp); + fwrite(&cutbond[i][j], sizeof(double), 1, fp); + fwrite(&k[i][j], sizeof(double), 1, fp); + fwrite(&eps[i][j], sizeof(double), 1, fp); + fwrite(&gamma[i][j], sizeof(double), 1, fp); + fwrite(&t_form[i][j], sizeof(double), 1, fp); + fwrite(&rlimit[i][j], sizeof(double), 1, fp); } } @@ -521,29 +457,25 @@ void PairRHEOReact::read_restart(FILE *fp) int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { - if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); - MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (me == 0) fread(&setflag[i][j], sizeof(int), 1, fp); + MPI_Bcast(&setflag[i][j], 1, MPI_INT, 0, world); if (setflag[i][j]) { if (me == 0) { - fread(&cut[i][j],sizeof(double),1,fp); - fread(&cutbond[i][j],sizeof(double),1,fp); - fread(&k[i][j],sizeof(double),1,fp); - fread(&eps[i][j],sizeof(double),1,fp); - fread(&gamma[i][j],sizeof(double),1,fp); - fread(&t_form[i][j],sizeof(double),1,fp); - fread(&rlimit[i][j],sizeof(double),1,fp); - fread(&sigma[i][j],sizeof(double),1,fp); - fread(&krepel[i][j],sizeof(double),1,fp); + fread(&cut[i][j], sizeof(double), 1, fp); + fread(&cutbond[i][j], sizeof(double), 1, fp); + fread(&k[i][j], sizeof(double), 1, fp); + fread(&eps[i][j], sizeof(double), 1, fp); + fread(&gamma[i][j], sizeof(double), 1, fp); + fread(&t_form[i][j], sizeof(double), 1, fp); + fread(&rlimit[i][j], sizeof(double), 1, fp); } - MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&cutbond[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&k[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&eps[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&gamma[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&t_form[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&rlimit[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); - MPI_Bcast(&krepel[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j], 1,MPI_DOUBLE, 0, world); + MPI_Bcast(&cutbond[i][j], 1,MPI_DOUBLE, 0, world); + MPI_Bcast(&k[i][j], 1,MPI_DOUBLE, 0, world); + MPI_Bcast(&eps[i][j], 1,MPI_DOUBLE, 0, world); + MPI_Bcast(&gamma[i][j], 1,MPI_DOUBLE, 0, world); + MPI_Bcast(&t_form[i][j], 1,MPI_DOUBLE, 0, world); + MPI_Bcast(&rlimit[i][j], 1,MPI_DOUBLE, 0, world); } } } @@ -565,8 +497,7 @@ void PairRHEOReact::transfer_history(double* source, double* target) int PairRHEOReact::pack_reverse_comm(int n, int first, double *buf) { - int i,m,last; - + int i, m, last; m = 0; last = first + n; @@ -580,7 +511,7 @@ int PairRHEOReact::pack_reverse_comm(int n, int first, double *buf) void PairRHEOReact::unpack_reverse_comm(int n, int *list, double *buf) { - int i,j,m; + int i, j, m; m = 0; for (i = 0; i < n; i++) { diff --git a/src/RHEO/pair_rheo_react.h b/src/RHEO/pair_rheo_react.h index b349300f27..144859e68b 100644 --- a/src/RHEO/pair_rheo_react.h +++ b/src/RHEO/pair_rheo_react.h @@ -40,21 +40,21 @@ class PairRHEOReact : public Pair { void unpack_reverse_comm(int, int *, double *) override; protected: - double **cut,**cutbond,**cutbsq, **k, **eps, **gamma, **t_form, **rlimit, **sigma, **krepel; + double **cut, **cutbond, **cutbsq, **k, **eps, **gamma, **t_form, **rlimit; void allocate(); void transfer_history(double*, double*); - int size_history, nmax_store; + int size_history; int *dbond, *nbond; - double dt; - int index_nb, nmax; + int index_nb, nmax_store; char *id_fix; class FixDummy *fix_dummy; class FixNeighHistory *fix_history; class FixRHEO *fix_rheo; + class ComputeRHEOSurface *compute_surface; }; } // namespace LAMMPS_NS From 92ff79af0810209c5ac96a31148f79a6e3693b29 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 6 Nov 2023 16:22:02 -0700 Subject: [PATCH 055/385] Debugging BPM coupling --- src/RHEO/fix_rheo.cpp | 4 +- src/RHEO/fix_rheo.h | 2 +- src/RHEO/fix_rheo_thermal.cpp | 150 +++++++++++++++++++++------------- src/RHEO/fix_rheo_thermal.h | 6 +- src/set.cpp | 2 +- 5 files changed, 101 insertions(+), 63 deletions(-) diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index c8dca74d32..97b867179e 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -150,7 +150,7 @@ void FixRHEO::post_constructor() compute_kernel->fix_rheo = this; std::string cmd = "rheo_grad all RHEO/GRAD velocity rho viscosity"; - if (thermal_flag) cmd += "temperature"; + if (thermal_flag) cmd += " temperature"; compute_grad = dynamic_cast(modify->add_compute(cmd)); compute_grad->fix_rheo = this; @@ -254,7 +254,7 @@ void FixRHEO::setup(int /*vflag*/) covered = 0; for (auto fix : therm_fixes) if (mask[i] & fix->groupbit) covered = 1; - if (!covered) v_coverage_flag = 0; + if (!covered) t_coverage_flag = 0; } } diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 0b864bb602..da98f3d09a 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -75,7 +75,7 @@ namespace RHEO_NS { enum Status{ // Phase status STATUS_SOLID = 1 << 0, - STATUS_REACTIVE = 1 << 1, + // STATUS_REACTIVE = 1 << 1, // Surface status STATUS_BULK = 1 << 2, diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 48a22a5419..ba61619594 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -51,6 +51,9 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : { if (narg < 4) error->all(FLERR,"Illegal fix command"); + force_reneighbor = 1; + next_reneighbor = -1; + Tc_style = NONE; cv_style = NONE; conductivity_style = NONE; @@ -109,7 +112,6 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); Tc_style = CONSTANT; Tc = utils::numeric(FLERR,arg[iarg + 2],false,lmp); - if (Tc < 0.0) error->all(FLERR,"The melting temperature must be positive"); iarg += 2; } else if (strcmp(arg[iarg + 1],"type") == 0) { if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); @@ -130,6 +132,8 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : comm_forward = 1; if (cut_bond <= 0.0) error->all(FLERR, "Illegal value for bond lengths");\ if (btype < 1 || btype > atom->nbondtypes) error->all(FLERR, "Illegal value for bond type"); + + cutsq_bond = cut_bond * cut_bond; iarg += 2; } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg]); @@ -175,6 +179,10 @@ void FixRHEOThermal::init() auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); + cut_kernel = fix_rheo->h; + + if (cut_bond > cut_kernel) + error->all(FLERR, "Bonding length exceeds kernel cutoff"); if (!fix_rheo->thermal_flag) error->all(FLERR, "Need to define thermal setting in fix rheo"); @@ -204,7 +212,7 @@ void FixRHEOThermal::init() // need a half neighbor list, built only when particles freeze auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL); - req->set_cutoff(cut_bond); + req->set_cutoff(cut_kernel); // find instances of bond history to delete data histories = modify->get_fix_by_style("BOND_HISTORY"); @@ -276,7 +284,8 @@ void FixRHEOThermal::post_integrate() double cvi, Tci, Ti; - int phase_changes = 0; + int n_melt = 0; + int n_freeze = 0; //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { @@ -299,7 +308,7 @@ void FixRHEOThermal::post_integrate() if (status[i] & STATUS_SOLID) { status[i] &= PHASEMASK; status[i] |= STATUS_MELTING; - phase_changes += 1; + n_melt += 1; } } else { // If fluid, freeze @@ -307,21 +316,21 @@ void FixRHEOThermal::post_integrate() status[i] &= PHASEMASK; status[i] |= STATUS_SOLID; status[i] |= STATUS_FREEZING; - phase_changes += 1; + n_freeze += 1; } } } } } - if (cut_bond > 0 && phase_changes != 0) { + if (cut_bond > 0 && (n_melt || n_freeze)) { // Forward status then delete/create bonds comm->forward_comm(this); - for (int i = 0; i < atom->nlocal; i++) { - if (status[i] & STATUS_MELTING) break_bonds(i); - if (status[i] & STATUS_FREEZING) create_bonds(i); - } + if (n_freeze) create_bonds(); + if (n_melt) break_bonds(); + + next_reneighbor = update->ntimestep; } } @@ -387,9 +396,9 @@ void FixRHEOThermal::reset_dt() /* ---------------------------------------------------------------------- */ -void FixRHEOThermal::break_bonds(int i) +void FixRHEOThermal::break_bonds() { - int m, n, nmax, j; + int m, n, nmax, i, j; tagint *tag = atom->tag; int *status = atom->status; @@ -397,84 +406,113 @@ void FixRHEOThermal::break_bonds(int i) tagint **bond_atom = atom->bond_atom; int *num_bond = atom->num_bond; - for (m = 0; m < num_bond[i]; m++) { - j = bond_atom[i][m]; - if (n_histories > 0) - for (auto &ihistory: histories) - dynamic_cast(ihistory)->delete_history(i,num_bond[i]-1); + int nlocal = atom->nlocal; - if (fix_update_special_bonds) fix_update_special_bonds->add_broken_bond(i,j); + for (int i = 0; i < nlocal; i++) { + if (!(status[i] & STATUS_MELTING)) continue; - if (j >= atom->nlocal) continue; + for (m = 0; m < num_bond[i]; m++) { + j = atom->map(bond_atom[i][m]); + if (n_histories > 0) + for (auto &ihistory: histories) + dynamic_cast(ihistory)->delete_history(i, num_bond[i] - 1); - for (n = 0; n < num_bond[j]; n++) { - if (bond_atom[j][n] == tag[i]) { - bond_type[j][n] = 0; - nmax = num_bond[j] - 1; - bond_type[j][n] = bond_type[j][nmax]; - bond_atom[j][n] = bond_atom[j][nmax]; - if (n_histories > 0) { - for (auto &ihistory: histories) { - dynamic_cast(ihistory)->shift_history(j, n, nmax); - dynamic_cast(ihistory)->delete_history(j, nmax); + if (fix_update_special_bonds) fix_update_special_bonds->add_broken_bond(i, j); + + // For non-melting neighbors, selectively delete bond if necessary + if (j >= nlocal || (status[j] & STATUS_MELTING)) continue; + for (n = 0; n < num_bond[j]; n++) { + if (bond_atom[j][n] == tag[i]) { + bond_type[j][n] = 0; + nmax = num_bond[j] - 1; + bond_type[j][n] = bond_type[j][nmax]; + bond_atom[j][n] = bond_atom[j][nmax]; + if (n_histories > 0) { + for (auto &ihistory: histories) { + dynamic_cast(ihistory)->shift_history(j, n, nmax); + dynamic_cast(ihistory)->delete_history(j, nmax); + } } + num_bond[j]--; + break; } - num_bond[j]--; - break; } } + num_bond[i] = 0; } - - num_bond[i] = 0; } /* ---------------------------------------------------------------------- */ -void FixRHEOThermal::create_bonds(int i) +void FixRHEOThermal::create_bonds() { - int i1, i2, j, jj, jnum; - int *jlist, *numneigh, **firstneigh; - double rsq; + int i, j, ii, jj, inum, jnum; + int *ilist, *jlist, *numneigh, **firstneigh; + double xtmp, ytmp, ztmp, delx, dely, delz, rsq; int nlocal = atom->nlocal; + int newton_bond = force->newton_bond; tagint *tag = atom->tag; + tagint **bond_atom = atom->bond_atom; + int *status = atom->status; + int **bond_type = atom->bond_type; + int *num_bond = atom->num_bond; double **x = atom->x; + + neighbor->build_one(list, 1); + + + inum = list->inum; + ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; - int *status = atom->status; - int **bond_type = atom->bond_type; - tagint **bond_atom = atom->bond_atom; - int *num_bond = atom->num_bond; - int newton_bond = force->newton_bond; + // loop over neighbors of my atoms + // might be faster to do a full list and just act on the atom that freezes + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + if (!(status[i] & STATUS_SOLID)) continue; - double xtmp = x[i][0]; - double ytmp = x[i][1]; - double ztmp = x[i][2]; - double delx, dely, delz; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= SPECIALMASK; + + if (!(status[j] & STATUS_SOLID)) continue; + if (!(status[i] & STATUS_FREEZING) && !(status[j] & STATUS_FREEZING)) continue; - // Loop through atoms of owned atoms - jlist = firstneigh[i]; - jnum = numneigh[i]; - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= SPECIALMASK; - if (status[j] & STATUS_SOLID) { delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx * delx + dely * dely + delz * delz; - if (rsq > cut_bond) continue; + if (rsq > cutsq_bond) continue; - if (!newton_bond || tag[i] < tag[j]) { + // Add bonds to owned atoms + // If newton bond, add to both, otherwise add to whichever has a smaller tag + if (i < nlocal && (!newton_bond || tag[i] < tag[j])) { if (num_bond[i] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); - if (fix_update_special_bonds) fix_update_special_bonds->add_created_bond(i,j); + if (fix_update_special_bonds) fix_update_special_bonds->add_created_bond(i, j); bond_type[i][num_bond[i]] = btype; bond_atom[i][num_bond[i]] = tag[j]; num_bond[i]++; } + + if (j < nlocal && (!newton_bond || tag[j] < tag[i])) { + if (num_bond[j] == atom->bond_per_atom) + error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); + if (fix_update_special_bonds) fix_update_special_bonds->add_created_bond(i, j); + bond_type[j][num_bond[j]] = btype; + bond_atom[j][num_bond[j]] = tag[i]; + num_bond[j]++; + } } } } diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index 75d32b7bc1..da48a59e22 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -49,7 +49,7 @@ class FixRHEOThermal : public Fix { double *Tc_type, Tc; double *kappa_type, kappa; double dtf, dtv; - double cut_bond; + double cut_kernel, cut_bond, cutsq_bond; int Tc_style, cv_style; int btype; int conductivity_style; @@ -64,8 +64,8 @@ class FixRHEOThermal : public Fix { class FixUpdateSpecialBonds *fix_update_special_bonds; void grow_array(int); - void break_bonds(int); - void create_bonds(int); + void break_bonds(); + void create_bonds(); }; } // namespace LAMMPS_NS diff --git a/src/set.cpp b/src/set.cpp index 92033b772e..3e1058b048 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -1105,7 +1105,7 @@ void Set::set(int keyword) // set temperature of particle - else if (keyword == ANGMOM) { + else if (keyword == TEMPERATURE) { if (dvalue < 0.0) error->one(FLERR,"Invalid temperature in set command"); atom->temperature[i] = dvalue; } From 44ae758bf5257e1594c59b9bd512371d5929b1bc Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 6 Nov 2023 20:27:18 -0700 Subject: [PATCH 056/385] Parallel support for bond creation/deletion --- src/RHEO/fix_rheo_thermal.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index ba61619594..7c29e17f93 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -323,12 +323,16 @@ void FixRHEOThermal::post_integrate() } } - if (cut_bond > 0 && (n_melt || n_freeze)) { + int n_melt_all, n_freeze_all; + MPI_Allreduce(&n_melt, &n_melt_all, 1, MPI_INT, MPI_SUM, world); + MPI_Allreduce(&n_freeze, &n_freeze_all, 1, MPI_INT, MPI_SUM, world); + + if (cut_bond > 0 && (n_melt_all || n_freeze_all)) { // Forward status then delete/create bonds comm->forward_comm(this); - if (n_freeze) create_bonds(); - if (n_melt) break_bonds(); + if (n_freeze_all) create_bonds(); + if (n_melt_all) break_bonds(); next_reneighbor = update->ntimestep; } @@ -409,10 +413,10 @@ void FixRHEOThermal::break_bonds() int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { - if (!(status[i] & STATUS_MELTING)) continue; - for (m = 0; m < num_bond[i]; m++) { j = atom->map(bond_atom[i][m]); + if (!(status[i] & STATUS_MELTING) && !(status[j] & STATUS_MELTING)) continue; + if (n_histories > 0) for (auto &ihistory: histories) dynamic_cast(ihistory)->delete_history(i, num_bond[i] - 1); @@ -462,7 +466,6 @@ void FixRHEOThermal::create_bonds() neighbor->build_one(list, 1); - inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; From b8b2141993ecdf6383150f512a2223f431f1d21f Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 7 Nov 2023 14:47:46 -0700 Subject: [PATCH 057/385] Fixing errors in oxide model --- src/RHEO/compute_rheo_property_atom.cpp | 2 +- src/RHEO/compute_rheo_surface.cpp | 81 ++++++++++++------------- src/RHEO/fix_rheo.cpp | 7 ++- src/RHEO/pair_rheo_react.cpp | 21 ++++--- 4 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 3afeb03e43..615d5ea740 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -103,7 +103,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (avec_index[i] < 0) error->all(FLERR, "Invalid keyword {} for atom style {} in compute rheo/property/atom command ", - atom->get_style(), arg[iarg]); + arg[iarg], atom->get_style()); pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; if (strcmp(arg[iarg],"temperature") == 0) thermal_flag = 1; diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 88b33c09af..882977f3e9 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -152,16 +152,12 @@ void ComputeRHEOSurface::compute_peratom() grow_arrays(atom->nmax); size_t nbytes = nmax_store * sizeof(double); - memset(&divr, 0, nbytes); - memset(&rsurface, 0, nbytes); - memset(&nsurface, 0, 3 * nbytes); - memset(&gradC, 0, 3 * 3 * nbytes); - memset(&B, 0, 3 * 3 * nbytes); + memset(&divr[0], 0, nbytes); + memset(&rsurface[0], 0, nbytes); + memset(&nsurface[0][0], 0, dim * nbytes); + memset(&gradC[0][0], 0, dim * dim * nbytes); + memset(&B[0][0], 0, dim * dim * nbytes); - // Remove surface settings - int nall = nlocal + atom->nghost; - for (i = 0; i < nall; i++) - status[i] &= SURFACEMASK; // loop over neighbors to calculate the average orientation of neighbors for (ii = 0; ii < inum; ii++) { @@ -208,7 +204,7 @@ void ComputeRHEOSurface::compute_peratom() wp = compute_kernel->calc_dw_quintic(i, j, dx[0], dx[1], dx[2], sqrt(rsq), dWij, dWji); - for (a = 0; a < dim; a++){ + for (a = 0; a < dim; a++) { divr[i] -= dWij[a] * dx[a] * Volj; gradC[i][a] += dWij[a] * Volj; } @@ -245,35 +241,32 @@ void ComputeRHEOSurface::compute_peratom() } } - // Find the free-surface - if (threshold_style == DIVR) { - for (i = 0; i < nall; i++) { - if (mask[i] & groupbit) { + // Remove surface settings and assign new values + int nall = nlocal + atom->nghost; + int test; + + for (i = 0; i < nall; i++) { + status[i] &= SURFACEMASK; + if (mask[i] & groupbit) { + if (threshold_style == DIVR) + test = divr[i] < threshold_divr; + else + test = coordination[i] < threshold_z; + + if (test) { + if (coordination[i] < threshold_splash) + status[i] |= STATUS_SPLASH; + else + status[i] |= STATUS_SURFACE; + rsurface[i] = 0.0; + } else { status[i] |= STATUS_BULK; rsurface[i] = cut; - if (divr[i] < threshold_divr) { - status[i] |= STATUS_SURFACE; - rsurface[i] = 0.0; - if (coordination[i] < threshold_splash) - status[i] |= STATUS_SPLASH; - } - } - } - } else { - for (i = 0; i < nall; i++) { - if (mask[i] & groupbit) { - status[i] |= STATUS_BULK; - rsurface[i] = cut; - if (coordination[i] < threshold_z) { - status[i] |= STATUS_SURFACE; - rsurface[i] = 0.0; - if (coordination[i] < threshold_splash) - status[i] |= STATUS_SPLASH; - } } } } + for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; @@ -297,7 +290,8 @@ void ComputeRHEOSurface::compute_peratom() status[i] |= STATUS_LAYER; } - if (status[j] & STATUS_SURFACE) rsurface[i] = MIN(rsurface[i], sqrt(rsq)); + if (status[j] & STATUS_SURFACE) + rsurface[i] = MIN(rsurface[i], sqrt(rsq)); if (j < nlocal || newton) { @@ -306,7 +300,8 @@ void ComputeRHEOSurface::compute_peratom() status[j] |= STATUS_LAYER; } - if (status[i] & STATUS_SURFACE) rsurface[j] = MIN(rsurface[j], sqrt(rsq)); + if (status[i] & STATUS_SURFACE) + rsurface[j] = MIN(rsurface[j], sqrt(rsq)); } } } @@ -351,7 +346,8 @@ void ComputeRHEOSurface::unpack_reverse_comm(int n, int *list, double *buf) int i,a,b,k,j,m; int dim = domain->dimension; int *status = atom->status; - int temp; + int tmp1; + double tmp2; m = 0; for (i = 0; i < n; i++) { @@ -362,12 +358,13 @@ void ComputeRHEOSurface::unpack_reverse_comm(int n, int *list, double *buf) for (b = 0; b < dim; b ++) gradC[j][a * dim + b] += buf[m++]; } else if (comm_stage == 1) { - - temp = (int) buf[m++]; - if ((status[j] & STATUS_BULK) && (temp & STATUS_LAYER)) - status[j] = temp; - - rsurface[j] = MIN(rsurface[j], buf[m++]); + tmp1 = (int) buf[m++]; + if ((status[j] & STATUS_BULK) && (tmp1 & STATUS_LAYER)) { + status[j] &= SURFACEMASK; + status[j] |= STATUS_LAYER; + } + tmp2 = buf[m++]; + rsurface[j] = MIN(rsurface[j], tmp2); } } } diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 97b867179e..b1bc0fe0c0 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -133,7 +133,7 @@ FixRHEO::~FixRHEO() if (compute_kernel) modify->delete_compute("rheo_kernel"); if (compute_grad) modify->delete_compute("rheo_grad"); if (compute_interface) modify->delete_compute("rheo_interface"); - if (compute_surface) modify->delete_compute("compute_surface"); + if (compute_surface) modify->delete_compute("rheo_surface"); if (compute_rhosum) modify->delete_compute("rheo_rhosum"); if (compute_vshift) modify->delete_compute("rheo_vshift"); } @@ -211,7 +211,10 @@ void FixRHEO::setup_pre_force(int /*vflag*/) error->all(FLERR, "Fix RHEO must be defined before all other RHEO fixes"); // Calculate surfaces - if (surface_flag) compute_surface->compute_peratom(); + if (surface_flag) { + compute_kernel->compute_coordination(); + compute_surface->compute_peratom(); + } pre_force(0); } diff --git a/src/RHEO/pair_rheo_react.cpp b/src/RHEO/pair_rheo_react.cpp index 4846e077f6..d7412d5d0e 100644 --- a/src/RHEO/pair_rheo_react.cpp +++ b/src/RHEO/pair_rheo_react.cpp @@ -61,13 +61,13 @@ PairRHEOReact::PairRHEOReact(LAMMPS *lmp) : Pair(lmp), // between timesteps (fix property atom will handle callbacks) int tmp1, tmp2; - int index = atom->find_custom("react_nbond", tmp1, tmp2); - if (index == -1) { + index_nb = atom->find_custom("react_nbond", tmp1, tmp2); + if (index_nb == -1) { id_fix = utils::strdup("pair_rheo_react_fix_property_atom"); modify->add_fix(fmt::format("{} all property/atom i_react_nbond", id_fix)); - index = atom->find_custom("nbond", tmp1, tmp2); + index_nb = atom->find_custom("react_nbond", tmp1, tmp2); } - nbond = atom->ivector[index]; + nbond = atom->ivector[index_nb]; //Store non-persistent per atom quantities, intermediate @@ -79,9 +79,10 @@ PairRHEOReact::PairRHEOReact(LAMMPS *lmp) : Pair(lmp), PairRHEOReact::~PairRHEOReact() { - if (modify->nfix && fix_history) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT"); - if (modify->nfix && fix_dummy) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY"); - if (modify->nfix) modify->delete_fix("PROPERTY_ATOM_RHEO_REACT"); + if (modify->nfix && fix_history) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT" + std::to_string(instance_me)); + if (modify->nfix && fix_dummy) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY" + std::to_string(instance_me)); + if (modify->nfix) modify->delete_fix(id_fix); + delete[] id_fix; if (allocated) { memory->destroy(setflag); @@ -146,7 +147,7 @@ void PairRHEOReact::compute(int eflag, int vflag) } size_t nbytes = nmax_store * sizeof(int); - memset(&dbond, 0, nbytes); + memset(&dbond[0], 0, nbytes); // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { @@ -368,11 +369,11 @@ void PairRHEOReact::coeff(int narg, char **arg) void PairRHEOReact::init_style() { - int irequest = neighbor->request(this,instance_me); + int irequest = neighbor->request(this, instance_me); //neighbor->requests[irequest]->history = 1; if (fix_history == nullptr) { - auto cmd = fmt::format("NEIGH_HISTORY_RHEO_REACT {} all NEIGH_HISTORY {}", instance_me, size_history); + auto cmd = fmt::format("NEIGH_HISTORY_RHEO_REACT{} all NEIGH_HISTORY {}", instance_me, size_history); fix_history = dynamic_cast( modify->replace_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY" + std::to_string(instance_me), cmd, 1)); fix_history->pair = this; From c922fcef5a7849cc930f4057973e7460ecb5a7c6 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 8 Nov 2023 14:30:37 -0700 Subject: [PATCH 058/385] prototyping limit on tension --- src/RHEO/compute_rheo_vshift.cpp | 2 +- src/RHEO/fix_rheo_pressure.cpp | 12 ++-- src/RHEO/fix_rheo_tension.cpp | 112 +++++++++++++++++++++++++------ src/RHEO/fix_rheo_tension.h | 4 +- src/RHEO/fix_rheo_thermal.cpp | 64 +++++++++--------- src/RHEO/fix_rheo_viscosity.cpp | 2 +- 6 files changed, 134 insertions(+), 62 deletions(-) diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 9741026324..aa59f80ff2 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -232,7 +232,7 @@ void ComputeRHEOVShift::correct_surfaces() int nlocal = atom->nlocal; int dim = domain->dimension; - double nx,ny,nz,vx,vy,vz; + double nx, ny, nz, vx, vy, vz; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if ((status[i] & STATUS_SURFACE) || (status[i] & STATUS_LAYER)) { diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 84d21ee872..5049ab0a4e 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -51,14 +51,14 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : int ntypes = atom->ntypes; int iarg = 3; - if (strcmp(arg[iarg],"linear") == 0) { + if (strcmp(arg[iarg], "linear") == 0) { pressure_style = LINEAR; - } else if (strcmp(arg[iarg],"taitwater") == 0) { + } else if (strcmp(arg[iarg], "taitwater") == 0) { pressure_style = TAITWATER; - } else if (strcmp(arg[iarg],"cubic") == 0) { + } else if (strcmp(arg[iarg], "cubic") == 0) { pressure_style = CUBIC; - if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for pressure option"); - c_cubic = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for pressure option"); + c_cubic = utils::numeric(FLERR, arg[iarg + 1], false, lmp); } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg]); } @@ -96,7 +96,7 @@ void FixRHEOPressure::init() // Cannot define multiple as pair rheo cannot currently distinguish if (modify->get_fix_by_style("rheo/pressure").size() > 1) - error->all(FLERR,"Can only specify one instance of fix rheo/pressure"); + error->all(FLERR, "Can only specify one instance of fix rheo/pressure"); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_tension.cpp b/src/RHEO/fix_rheo_tension.cpp index 047f1d217e..8b79fcebd6 100644 --- a/src/RHEO/fix_rheo_tension.cpp +++ b/src/RHEO/fix_rheo_tension.cpp @@ -46,8 +46,10 @@ using namespace FixConst; FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), compute_kernel(nullptr), compute_interface(nullptr), fix_rheo(nullptr) { - if (narg != 4) error->all(FLERR,"Illegal fix command"); - alpha = utils::numeric(FLERR,arg[3],false,lmp); + if (narg != 6) error->all(FLERR,"Illegal fix command"); + alpha = utils::numeric(FLERR, arg[3], false, lmp); + alpha = utils::numeric(FLERR, arg[4], false, lmp); + wmin = utils::numeric(FLERR, arg[5], false, lmp); comm_forward = 3; comm_reverse = 3; @@ -75,6 +77,7 @@ FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : ft = atom->darray[index_ft]; norm = nullptr; + wsame = nullptr; nmax_store = 0; } @@ -98,6 +101,7 @@ FixRHEOTension::~FixRHEOTension() if (index != -1) atom->remove_custom(index, 1, 3); memory->destroy(norm); + memory->destroy(wsame); } /* ---------------------------------------------------------------------- */ @@ -182,13 +186,11 @@ void FixRHEOTension::post_force(int vflag) if (nmax_store <= atom->nmax) grow_arrays(atom->nmax); - for (i = 0; i < nlocal+atom->nghost; i++) { - cgradt[i][0] = 0.0; - cgradt[i][1] = 0.0; - cgradt[i][2] = 0.0; - norm[i] = 0.0; - divnt[i] = 0.0; - } + size_t nbytes = nmax_store * sizeof(double); + memset(&norm[0], 0, nbytes); + memset(&wsame[0], 0, nbytes); + memset(&divnt[0], 0, nbytes); + memset(&cgradt[0][0], 0, 3 * nbytes); // Calculate color gradient for (ii = 0; ii < inum; ii++) { @@ -315,17 +317,26 @@ void FixRHEOTension::post_force(int vflag) Voli = mass[itype] / rhoi; Volj = mass[jtype] / rhoj; + w = compute_kernel->calc_w(i, j, dx[0], dx[1], dx[2],r); wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2],r); dWij = compute_kernel->dWij; dWji = compute_kernel->dWji; - if (itype != jtype) continue; // have to think about this... - for (a = 0; a < 3; a++) { - divnt[i] -= (nt[i][a]-nt[j][a]) * Volj * dWij[a]; + if (itype != jtype) + divnt[i] -= (nt[i][a]+nt[j][a]) * Volj * dWij[a]; + else { + divnt[i] -= (nt[i][a]-nt[j][a]) * Volj * dWij[a]; + wsame[i] += w; + } norm[i] -= dx[a] * Volj * dWij[a]; if (newton || j < nlocal) { - divnt[j] += (nt[i][a]-nt[j][a]) * Voli * dWji[a]; + if (itype != jtype) + divnt[j] -= (nt[j][a]+nt[i][a]) * Voli * dWji[a]; + else { + divnt[j] -= (nt[j][a]-nt[i][a]) * Voli * dWji[a]; + wsame[j] += w; + } norm[j] += dx[a] * Voli * dWji[a]; } } @@ -333,26 +344,28 @@ void FixRHEOTension::post_force(int vflag) } comm_stage = 1; - comm_reverse = 2; + comm_reverse = 3; if (newton) comm->reverse_comm(this); // Skip forces if it's setup if (update->setupflag) return; // apply force - double prefactor; - double unwrap[3]; - double v[6]; + double weight, prefactor, unwrap[3], v[6]; + double wmin_inv = 1.0 / wmin; for (i = 0; i < nlocal; i++) { + + weight = MAX(1.0, (wsame[i] - wmin) * wmin_inv); + //if (wsame[i] < wmin) continue; + itype = type[i]; if (norm[i] != 0) - divnt[i] /= norm[i]; + divnt[i] *= dim * norm[i]; else divnt[i] = 0.0; - prefactor = -alpha * divnt[i]; - + prefactor = -alpha * divnt[i] * weight; for (a = 0; a < 3; a++) { f[i][a] += prefactor * cgradt[i][a]; ft[i][a] = prefactor * cgradt[i][a]; @@ -369,6 +382,62 @@ void FixRHEOTension::post_force(int vflag) v_tally(i, v); } } + + // If there is no lower limit, apply optional pairwise forces + if (wmin == 0 || beta == 0.0) return; + + double fpair, wi, wj; + double cut_two_thirds = 2.0 * h / 3.0; + double h_third_squared = (h / 3.0) * (h / 3.0); + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + imass = mass[itype]; + + wi = MIN(1.0, (wsame[i] - wmin) * wmin_inv); + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + if (wsame[i] >= wmin && wsame[j] >= wmin) continue; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = lensq3(dx); + + if (rsq > hsq) continue; + + wj = MIN(1.0, (wsame[j] - wmin) * wmin_inv); + r = sqrt(rsq); + rinv = 1.0 / r; + + fpair = (r - cut_two_thirds); + fpair *= fpair; + fpair -= h_third_squared; + fpair *= wi * wj * beta * rinv; + + f[i][0] += dx[0] * fpair; + f[i][1] += dx[1] * fpair; + f[i][2] += dx[2] * fpair; + + if (newton || j < nlocal) { + f[j][0] -= dx[0] * fpair; + f[j][1] -= dx[1] * fpair; + f[j][2] -= dx[2] * fpair; + } + + if (evflag) { + // In progress + } + } + } } @@ -417,6 +486,7 @@ int FixRHEOTension::pack_reverse_comm(int n, int first, double *buf) for (i = first; i < last; i++) { buf[m++] = norm[i]; buf[m++] = divnt[i]; + buf[m++] = wsame[i]; } return m; } @@ -439,6 +509,7 @@ void FixRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) j = list[i]; norm[j] += buf[m++]; divnt[j] += buf[m++]; + wsame[j] += buf[m++]; } } @@ -459,6 +530,7 @@ void FixRHEOTension::grow_arrays(int nmax) // Grow local variables memory->grow(norm, nmax, "rheo/tension:norm"); + memory->grow(wsame, nmax, "rheo/tension:wsame"); nmax_store = atom->nmax; } \ No newline at end of file diff --git a/src/RHEO/fix_rheo_tension.h b/src/RHEO/fix_rheo_tension.h index 11bc209d88..f56a61e688 100644 --- a/src/RHEO/fix_rheo_tension.h +++ b/src/RHEO/fix_rheo_tension.h @@ -43,8 +43,8 @@ class FixRHEOTension : public Fix { int nmax_store, comm_stage, interface_flag; int index_nt, index_cgradt, index_divnt, index_ft; - double **nt, **cgradt, *divnt, *norm, **ft; - double alpha, h, hsq, hinv, hinv3, rho0; + double **nt, **cgradt, *divnt, *norm, **ft, *wsame; + double alpha, beta, wmin, h, hsq, hinv, hinv3, rho0; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 7c29e17f93..3b38089fad 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -65,67 +65,67 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : while (iarg < narg) { if (strcmp(arg[iarg],"conductivity") == 0) { // Conductivity arguments - if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for conductivity option"); - if (strcmp(arg[iarg + 1],"constant") == 0) { - if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for conductivity option"); + if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for conductivity option"); + if (strcmp(arg[iarg + 1], "constant") == 0) { + if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for conductivity option"); conductivity_style = CONSTANT; - kappa = utils::numeric(FLERR,arg[iarg + 2],false,lmp); - if (kappa < 0.0) error->all(FLERR,"The conductivity must be positive"); + kappa = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + if (kappa < 0.0) error->all(FLERR, "The conductivity must be positive"); iarg += 2; - } else if (strcmp(arg[iarg + 1],"type") == 0) { - if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for conductivity option"); + } else if (strcmp(arg[iarg + 1], "type") == 0) { + if (iarg + 1 + ntypes >= narg) error->all(FLERR, "Insufficient arguments for conductivity option"); conductivity_style = TYPE; - memory->create(kappa_type,ntypes+1,"rheo_thermal:kappa_type"); + memory->create(kappa_type, ntypes+1, "rheo_thermal:kappa_type"); for (int i = 1; i <= ntypes; i++) { - kappa_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i],false,lmp); - if (kappa_type[i] < 0.0) error->all(FLERR,"The conductivity must be positive"); + kappa_type[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); + if (kappa_type[i] < 0.0) error->all(FLERR, "The conductivity must be positive"); } iarg += 1 + ntypes; } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } - } else if (strcmp(arg[iarg],"specific/heat") == 0) { + } else if (strcmp(arg[iarg], "specific/heat") == 0) { // Cv arguments - if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for cv option"); - if (strcmp(arg[iarg + 1],"constant") == 0) { - if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for cv option"); + if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for cv option"); + if (strcmp(arg[iarg + 1], "constant") == 0) { + if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for cv option"); cv_style = CONSTANT; - cv = utils::numeric(FLERR,arg[iarg + 2],false,lmp); - if (cv < 0.0) error->all(FLERR,"The specific heat must be positive"); + cv = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + if (cv < 0.0) error->all(FLERR, "The specific heat must be positive"); iarg += 2; - } else if (strcmp(arg[iarg + 1],"type") == 0) { - if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for cv option"); + } else if (strcmp(arg[iarg + 1], "type") == 0) { + if (iarg + 1 + ntypes >= narg) error->all(FLERR, "Insufficient arguments for cv option"); cv_style = TYPE; - memory->create(cv_type,ntypes + 1,"rheo_thermal:cv_type"); + memory->create(cv_type,ntypes + 1, "rheo_thermal:cv_type"); for (int i = 1; i <= ntypes; i++) { - cv_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i],false,lmp); - if (cv_type[i] < 0.0) error->all(FLERR,"The specific heat must be positive"); + cv_type[i] = utils::numeric(FLERR, arg[iarg + 1 + i], false, lmp); + if (cv_type[i] < 0.0) error->all(FLERR, "The specific heat must be positive"); } iarg += 1 + ntypes; } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); } - } else if (strcmp(arg[iarg],"Tfreeze") == 0) { + } else if (strcmp(arg[iarg], "Tfreeze") == 0) { // T freeze arguments - if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); - if (strcmp(arg[iarg + 1],"constant") == 0) { - if (iarg + 2 >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); + if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for Tfreeze option"); + if (strcmp(arg[iarg + 1], "constant") == 0) { + if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for Tfreeze option"); Tc_style = CONSTANT; - Tc = utils::numeric(FLERR,arg[iarg + 2],false,lmp); + Tc = utils::numeric(FLERR, arg[iarg + 2], false, lmp); iarg += 2; - } else if (strcmp(arg[iarg + 1],"type") == 0) { - if (iarg + 1 + ntypes >= narg) error->all(FLERR,"Insufficient arguments for Tfreeze option"); + } else if (strcmp(arg[iarg + 1], "type") == 0) { + if (iarg + 1 + ntypes >= narg) error->all(FLERR, "Insufficient arguments for Tfreeze option"); Tc_style = TYPE; memory->create(Tc_type, ntypes + 1, "rheo_thermal:Tc_type"); for (int i = 1; i <= ntypes; i++) { - Tc_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i],false,lmp); - if (Tc_type[i] < 0.0) error->all(FLERR,"The melting temperature must be positive"); + Tc_type[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); + if (Tc_type[i] < 0.0) error->all(FLERR, "The melting temperature must be positive"); } iarg += 1 + ntypes; } else { - error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); + error->all(FLERR, "Illegal fix command, {}", arg[iarg + 1]); } - } else if (strcmp(arg[iarg],"react") == 0) { + } else if (strcmp(arg[iarg], "react") == 0) { if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for react option"); cut_bond = utils::numeric(FLERR, arg[iarg + 1], false, lmp); btype = utils::numeric(FLERR, arg[iarg + 2], false, lmp); diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 7d915c9b93..e33bd43244 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -58,7 +58,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : viscosity_style = TYPE; memory->create(eta_type, ntypes + 1, "rheo_thermal:eta_type"); for (int i = 1; i <= ntypes; i++) { - eta_type[i] = utils::numeric(FLERR,arg[iarg + 1 + i], false, lmp); + eta_type[i] = utils::numeric(FLERR,arg[iarg + i], false, lmp); if (eta_type[i] < 0.0) error->all(FLERR,"The viscosity must be positive"); } iarg += ntypes; From 73a3ae7602bb16b0308223f46d0ecf99633e9963 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 8 Nov 2023 15:57:42 -0700 Subject: [PATCH 059/385] Debugging some compute property items, allow surface shifting inward --- src/RHEO/compute_rheo_property_atom.cpp | 45 +++++++++++++++++-------- src/RHEO/compute_rheo_property_atom.h | 1 + src/RHEO/compute_rheo_vshift.cpp | 17 +++++++--- src/RHEO/fix_rheo.cpp | 4 ++- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 615d5ea740..ed35484bd5 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -70,6 +70,8 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (strcmp(arg[iarg],"phase") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_phase; + } else if (strcmp(arg[iarg],"rho") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_rho; } else if (strcmp(arg[iarg],"chi") == 0) { interface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_chi; @@ -82,7 +84,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a } else if (strcmp(arg[iarg],"surface/divr") == 0) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_divr; - } else if (strcmp(arg[iarg],"^surface/n") == 0) { + } else if (utils::strmatch(arg[iarg], "^surface/n")) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_n; col_index[i] = get_vector_index(arg[iarg]); @@ -91,11 +93,11 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a } else if (strcmp(arg[iarg],"cv") == 0) { thermal_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; - } else if (strcmp(arg[iarg],"^shift/v") == 0) { + } else if (utils::strmatch(arg[iarg], "^shift/v")) { shift_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_v; col_index[i] = get_vector_index(arg[iarg]); - } else if (utils::strmatch(arg[iarg],"^gradv")) { + } else if (utils::strmatch(arg[iarg], "^grad/v")) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_gradv; col_index[i] = get_tensor_index(arg[iarg]); } else { @@ -167,10 +169,10 @@ void ComputeRHEOPropertyAtom::compute_peratom() nmax = atom->nmax; if (nvalues == 1) { memory->destroy(vector_atom); - memory->create(vector_atom,nmax,"rheo/property/atom:vector"); + memory->create(vector_atom, nmax, "rheo/property/atom:vector"); } else { memory->destroy(array_atom); - memory->create(array_atom,nmax,nvalues,"rheo/property/atom:array"); + memory->create(array_atom, nmax, nvalues, "rheo/property/atom:array"); } } @@ -220,6 +222,21 @@ void ComputeRHEOPropertyAtom::pack_phase(int n) /* ---------------------------------------------------------------------- */ +void ComputeRHEOPropertyAtom::pack_rho(int n) +{ + double *rho = atom->rho; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = rho[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + void ComputeRHEOPropertyAtom::pack_chi(int n) { double *chi = compute_interface->chi; @@ -370,29 +387,29 @@ int ComputeRHEOPropertyAtom::get_tensor_index(char* option) int dim = domain->dimension; int dim_error = 0; - if (utils::strmatch(option,"xx$")) { + if (utils::strmatch(option, "xx$")) { index = 0; - } else if (utils::strmatch(option,"xy$")) { + } else if (utils::strmatch(option, "xy$")) { index = 1; - } else if (utils::strmatch(option,"xz$")) { + } else if (utils::strmatch(option, "xz$")) { index = 2; if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option,"yx$")) { + } else if (utils::strmatch(option, "yx$")) { if (dim == 2) index = 2; else index = 3; - } else if (utils::strmatch(option,"yy$")) { + } else if (utils::strmatch(option, "yy$")) { if (dim == 2) index = 3; else index = 4; - } else if (utils::strmatch(option,"yz$")) { + } else if (utils::strmatch(option, "yz$")) { index = 5; if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option,"zx$")) { + } else if (utils::strmatch(option, "zx$")) { index = 6; if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option,"zy$")) { + } else if (utils::strmatch(option, "zy$")) { index = 7; if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option,"zz$")) { + } else if (utils::strmatch(option, "zz$")) { index = 8; if (dim == 2) dim_error = 1; } else { diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index 344e249d11..bfae870ee5 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -43,6 +43,7 @@ class ComputeRHEOPropertyAtom : public Compute { FnPtrPack *pack_choice; // ptrs to pack functions void pack_phase(int); + void pack_rho(int); void pack_chi(int); void pack_surface(int); void pack_surface_r(int); diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index aa59f80ff2..1f9314e99b 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -232,7 +232,7 @@ void ComputeRHEOVShift::correct_surfaces() int nlocal = atom->nlocal; int dim = domain->dimension; - double nx, ny, nz, vx, vy, vz; + double nx, ny, nz, vx, vy, vz, dot; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if ((status[i] & STATUS_SURFACE) || (status[i] & STATUS_LAYER)) { @@ -240,11 +240,20 @@ void ComputeRHEOVShift::correct_surfaces() ny = nsurface[i][1]; vx = vshift[i][0]; vy = vshift[i][1]; - vz = vshift[i][2]; + + dot = nx * vx + ny * vy; + if (dim == 3) { + nz = nsurface[i][2]; + vz = vshift[i][2]; + dot += nz * vz; + } + + // Allowing shifting into the bulk + if (dot < 0.0) continue; + vshift[i][0] = (1 - nx * nx) * vx - nx * ny * vy; vshift[i][1] = (1 - ny * ny) * vy - nx * ny * vx; - if (dim > 2) { - nz = nsurface[i][2]; + if (dim == 3) { vshift[i][0] -= nx * nz * vz; vshift[i][1] -= ny * nz * vz; vshift[i][2] = (1 - nz * nz) * vz - nz * ny * vy - nx * nz * vx; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index b1bc0fe0c0..f1f1a1bc4b 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -351,7 +351,6 @@ void FixRHEO::initial_integrate(int /*vflag*/) // Shifting atoms if (shift_flag) { - compute_vshift->correct_surfaces(); // Could this be moved to preforce after the surface fix runs? for (i = 0; i < nlocal; i++) { if (status[i] & STATUS_NO_SHIFT) continue; @@ -407,6 +406,9 @@ void FixRHEO::pre_force(int /*vflag*/) // Calculate surfaces, update status if (surface_flag) compute_surface->compute_peratom(); + + if (shift_flag) + compute_vshift->correct_surfaces(); } /* ---------------------------------------------------------------------- */ From f9b385061b0d2017aec568109f984045c7de8088 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 14 Nov 2023 12:33:51 -0700 Subject: [PATCH 060/385] Multiphase support --- src/RHEO/compute_rheo_grad.cpp | 6 +- src/RHEO/compute_rheo_grad.h | 2 +- src/RHEO/compute_rheo_interface.cpp | 16 +- src/RHEO/compute_rheo_interface.h | 3 +- src/RHEO/compute_rheo_property_atom.cpp | 3 +- src/RHEO/compute_rheo_surface.cpp | 6 +- src/RHEO/compute_rheo_surface.h | 2 +- src/RHEO/fix_rheo.cpp | 86 +++++---- src/RHEO/fix_rheo.h | 3 +- src/RHEO/fix_rheo_pressure.cpp | 102 +++++++--- src/RHEO/fix_rheo_pressure.h | 7 +- src/RHEO/fix_rheo_thermal.cpp | 246 ++++++++++++------------ src/RHEO/fix_rheo_thermal.h | 9 +- src/RHEO/fix_rheo_viscosity.cpp | 168 ++++++++-------- src/RHEO/fix_rheo_viscosity.h | 5 +- src/RHEO/pair_rheo.cpp | 71 ++++--- src/RHEO/pair_rheo.h | 4 +- src/RHEO/pair_rheo_react.cpp | 28 +-- 18 files changed, 430 insertions(+), 337 deletions(-) diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 46c1500556..b2ca0c9dc4 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -41,7 +41,7 @@ enum{COMMGRAD, COMMFIELD}; /* ---------------------------------------------------------------------- */ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), compute_interface(nullptr), compute_kernel(nullptr), + Compute(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), rho0(nullptr), compute_interface(nullptr), compute_kernel(nullptr), gradv(nullptr), gradr(nullptr), gradt(nullptr), gradn(nullptr) { if (narg < 4) error->all(FLERR,"Illegal compute rheo/grad command"); @@ -221,8 +221,8 @@ void ComputeRHEOGrad::compute_peratom() //compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0; - rhoj = rho0; + rhoi = rho0[itype]; + rhoj = rho0[jtype]; } } diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index db5e84d32a..489f3c641d 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -46,7 +46,7 @@ class ComputeRHEOGrad : public Compute { private: int comm_stage, ncomm_grad, ncomm_field, nmax_store; - double cut, cutsq, rho0; + double cut, cutsq, *rho0; int velocity_flag, temperature_flag, rho_flag, eta_flag; int interface_flag, remap_v_flag; diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 8cd69b49e3..001f15a472 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -25,6 +25,7 @@ #include "error.h" #include "force.h" #include "fix_rheo.h" +#include "fix_rheo_pressure.h" #include "memory.h" #include "modify.h" #include "neighbor.h" @@ -42,7 +43,7 @@ static constexpr double EPSILON = 1e-1; ComputeRHEOInterface::ComputeRHEOInterface(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), fix_rheo(nullptr), compute_kernel(nullptr), fp_store(nullptr), - norm(nullptr), normwf(nullptr), chi(nullptr), id_fix_pa(nullptr) + rho0(nullptr), norm(nullptr), normwf(nullptr), chi(nullptr), id_fix_pa(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute rheo/interface command"); @@ -86,11 +87,12 @@ void ComputeRHEOInterface::init() compute_kernel = fix_rheo->compute_kernel; rho0 = fix_rheo->rho0; cut = fix_rheo->cut; - csq = fix_rheo->csq; - csq_inv = 1.0 / csq; cutsq = cut * cut; wall_max = sqrt(3.0) / 12.0 * cut; + auto fixes = modify->get_fix_by_style("rheo/pressure"); + fix_pressure = dynamic_cast(fixes[0]); + neighbor->add_request(this, NeighConst::REQ_DEFAULT); } @@ -174,7 +176,7 @@ void ComputeRHEOInterface::compute_peratom() dot += (-fp_store[j][1] + fp_store[i][1]) * dely; dot += (-fp_store[j][2] + fp_store[i][2]) * delz; - rho[i] += w * (csq * (rho[j] - rho0) - rho[j] * dot); + rho[i] += w * (fix_pressure->calc_pressure(rho[j], jtype) - rho[j] * dot); normwf[i] += w; } } @@ -189,7 +191,7 @@ void ComputeRHEOInterface::compute_peratom() dot += (-fp_store[i][1] + fp_store[j][1]) * dely; dot += (-fp_store[i][2] + fp_store[j][2]) * delz; - rho[j] += w * (csq * (rho[i] - rho0) + rho[i] * dot); + rho[j] += w * (fix_pressure->calc_pressure(rho[i], itype) + rho[i] * dot); normwf[j] += w; } } @@ -207,9 +209,9 @@ void ComputeRHEOInterface::compute_peratom() if (status[i] & PHASECHECK) { if (normwf[i] != 0.0) { // Stores rho for solid particles 1+Pw in Adami Adams 2012 - rho[i] = MAX(EPSILON, rho0 + (rho[i] / normwf[i]) * csq_inv); + rho[i] = MAX(EPSILON, fix_pressure->calc_rho(rho[i] / normwf[i], type[i])); } else { - rho[i] = rho0; + rho[i] = rho0[itype]; } } } diff --git a/src/RHEO/compute_rheo_interface.h b/src/RHEO/compute_rheo_interface.h index 50cec97790..a8cd448822 100644 --- a/src/RHEO/compute_rheo_interface.h +++ b/src/RHEO/compute_rheo_interface.h @@ -45,13 +45,14 @@ class ComputeRHEOInterface : public Compute { private: int nmax_store, comm_stage; - double rho0, cut, cutsq, csq, csq_inv, wall_max; + double *rho0, cut, cutsq, wall_max; double *norm, *normwf; char *id_fix_pa; class NeighList *list; class ComputeRHEOKernel *compute_kernel; + class FixRHEOPressure *fix_pressure; }; } // namespace LAMMPS_NS diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index ed35484bd5..50bcb2a2d0 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -330,11 +330,12 @@ void ComputeRHEOPropertyAtom::pack_coordination(int n) void ComputeRHEOPropertyAtom::pack_cv(int n) { + int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = fix_thermal->calc_cv(i); + if (mask[i] & groupbit) buf[n] = fix_thermal->calc_cv(i, type[i]); else buf[n] = 0.0; n += nvalues; } diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 882977f3e9..1ef69bb6f0 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -42,7 +42,7 @@ static constexpr double EPSILON = 1e-10; /* ---------------------------------------------------------------------- */ ComputeRHEOSurface::ComputeRHEOSurface(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), compute_kernel(nullptr), compute_interface(nullptr), + Compute(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), rho0(nullptr), compute_kernel(nullptr), compute_interface(nullptr), B(nullptr), gradC(nullptr), nsurface(nullptr), divr(nullptr), rsurface(nullptr) { if (narg != 3) error->all(FLERR,"Illegal compute RHEO/SURFACE command"); @@ -194,8 +194,8 @@ void ComputeRHEOSurface::compute_peratom() } else if ((!fluidi) && fluidj) { rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0; - rhoj = rho0; + rhoi = rho0[itype]; + rhoj = rho0[jtype]; } } diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index f1b1af7742..6ef2428499 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -44,7 +44,7 @@ class ComputeRHEOSurface : public Compute { int threshold_style, comm_stage; int index_divr, index_rsurf, index_nsurf; - double cut, cutsq, rho0, threshold_divr; + double cut, cutsq, *rho0, threshold_divr; double **B, **gradC; class NeighList *list; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index f1f1a1bc4b..d07f0d1a1f 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -28,6 +28,7 @@ #include "domain.h" #include "error.h" #include "force.h" +#include "memory.h" #include "modify.h" #include "update.h" #include "utils.h" @@ -40,7 +41,7 @@ using namespace FixConst; FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), compute_grad(nullptr), compute_kernel(nullptr), compute_surface(nullptr), - compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr) + compute_interface(nullptr), compute_rhosum(nullptr), compute_vshift(nullptr), rho0(nullptr), csq(nullptr) { time_integrate = 1; @@ -54,71 +55,81 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : interface_flag = 0; surface_flag = 0; - rho0 = 1.0; - csq = 1.0; + int i; + int n = atom->ntypes; + memory->create(rho0, n + 1, "rheo:rho0"); + memory->create(csq, n + 1, "rheo:csq"); + for (i = 1; i <= n; i++) { + rho0[i] = 1.0; + csq[i] = 1.0; + } if (igroup != 0) - error->all(FLERR,"fix rheo command requires group all"); + error->all(FLERR, "fix rheo command requires group all"); if (atom->pressure_flag != 1) - error->all(FLERR,"fix rheo command requires atom_style with pressure"); + error->all(FLERR, "fix rheo command requires atom_style with pressure"); if (atom->rho_flag != 1) - error->all(FLERR,"fix rheo command requires atom_style with density"); + error->all(FLERR, "fix rheo command requires atom_style with density"); if (atom->viscosity_flag != 1) - error->all(FLERR,"fix rheo command requires atom_style with viscosity"); + error->all(FLERR, "fix rheo command requires atom_style with viscosity"); if (atom->status_flag != 1) - error->all(FLERR,"fix rheo command requires atom_style with status"); + error->all(FLERR, "fix rheo command requires atom_style with status"); if (narg < 5) - error->all(FLERR,"Insufficient arguments for fix rheo command"); + error->all(FLERR, "Insufficient arguments for fix rheo command"); - h = utils::numeric(FLERR,arg[3],false,lmp); + h = utils::numeric(FLERR, arg[3], false, lmp); cut = h; - if (strcmp(arg[4],"quintic") == 0) { + if (strcmp(arg[4], "quintic") == 0) { kernel_style = QUINTIC; - } else if (strcmp(arg[4],"RK0") == 0) { + } else if (strcmp(arg[4], "RK0") == 0) { kernel_style = RK0; - } else if (strcmp(arg[4],"RK1") == 0) { + } else if (strcmp(arg[4], "RK1") == 0) { kernel_style = RK1; - } else if (strcmp(arg[4],"RK2") == 0) { + } else if (strcmp(arg[4], "RK2") == 0) { kernel_style = RK2; - } else error->all(FLERR,"Unknown kernel style {} in fix rheo", arg[4]); - zmin_kernel = utils::numeric(FLERR,arg[5],false,lmp); + } else error->all(FLERR, "Unknown kernel style {} in fix rheo", arg[4]); + zmin_kernel = utils::numeric(FLERR, arg[5], false, lmp); int iarg = 6; while (iarg < narg){ - if (strcmp(arg[iarg],"shift") == 0) { + if (strcmp(arg[iarg], "shift") == 0) { shift_flag = 1; - } else if (strcmp(arg[iarg],"thermal") == 0) { + } else if (strcmp(arg[iarg], "thermal") == 0) { thermal_flag = 1; - } else if (strcmp(arg[iarg],"surface/detection") == 0) { + } else if (strcmp(arg[iarg], "surface/detection") == 0) { surface_flag = 1; - if(iarg + 2 >= narg) error->all(FLERR,"Illegal surface/detection option in fix rheo"); + if(iarg + 2 >= narg) error->all(FLERR, "Illegal surface/detection option in fix rheo"); if (strcmp(arg[iarg + 1], "coordination") == 0) { surface_style = COORDINATION; - zmin_surface = utils::inumeric(FLERR,arg[iarg + 2],false,lmp); - zmin_splash = utils::inumeric(FLERR,arg[iarg + 3],false,lmp); + zmin_surface = utils::inumeric(FLERR, arg[iarg + 2], false, lmp); + zmin_splash = utils::inumeric(FLERR, arg[iarg + 3], false, lmp); } else if (strcmp(arg[iarg + 1], "divergence") == 0) { surface_style = DIVR; - divr_surface = utils::numeric(FLERR,arg[iarg + 2],false,lmp); - zmin_splash = utils::inumeric(FLERR,arg[iarg + 3],false,lmp); + divr_surface = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + zmin_splash = utils::inumeric(FLERR, arg[iarg + 3], false, lmp); } else { - error->all(FLERR,"Illegal surface/detection option in fix rheo, {}", arg[iarg + 1]); + error->all(FLERR, "Illegal surface/detection option in fix rheo, {}", arg[iarg + 1]); } iarg += 3; - } else if (strcmp(arg[iarg],"interface/reconstruct") == 0) { + } else if (strcmp(arg[iarg], "interface/reconstruct") == 0) { interface_flag = 1; - } else if (strcmp(arg[iarg],"rho/sum") == 0) { + } else if (strcmp(arg[iarg], "rho/sum") == 0) { rhosum_flag = 1; - } else if (strcmp(arg[iarg],"density") == 0) { - if(iarg + 1 >= narg) error->all(FLERR,"Illegal rho0 option in fix rheo"); - rho0 = utils::numeric(FLERR,arg[iarg + 1],false,lmp); - iarg += 1; - } else if (strcmp(arg[iarg],"sound/squared") == 0) { - if(iarg+1 >= narg) error->all(FLERR,"Illegal csq option in fix rheo"); - csq = utils::numeric(FLERR,arg[iarg + 1],false,lmp); - iarg += 1; + } else if (strcmp(arg[iarg], "density") == 0) { + if (iarg + n >= narg) error->all(FLERR, "Illegal rho0 option in fix rheo"); + for (i = 1; i <= n; i++) + rho0[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); + iarg += n; + } else if (strcmp(arg[iarg], "speed/sound") == 0) { + if (iarg + n >= narg) error->all(FLERR, "Illegal csq option in fix rheo"); + for (i = 1; i <= n; i++) { + csq[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); + csq[i] *= csq[i]; + } + iarg += n; } else { error->all(FLERR, "Illegal fix rheo command: {}", arg[iarg]); } @@ -136,6 +147,9 @@ FixRHEO::~FixRHEO() if (compute_surface) modify->delete_compute("rheo_surface"); if (compute_rhosum) modify->delete_compute("rheo_rhosum"); if (compute_vshift) modify->delete_compute("rheo_vshift"); + + memory->destroy(csq); + memory->destroy(rho0); } @@ -198,7 +212,7 @@ void FixRHEO::init() dtf = 0.5 * update->dt * force->ftm2v; if (modify->get_fix_by_style("^rheo$").size() > 1) - error->all(FLERR,"Can only specify one instance of fix rheo"); + error->all(FLERR, "Can only specify one instance of fix rheo"); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index da98f3d09a..8ec28c7d0e 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -39,7 +39,8 @@ class FixRHEO : public Fix { void reset_dt() override; // Model parameters - double h, cut, rho0, csq; + double h, cut; + double *rho0, *csq; int zmin_kernel, zmin_surface, zmin_splash; int kernel_style, surface_style; double divr_surface; diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 5049ab0a4e..eac4b34046 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -38,39 +38,62 @@ static constexpr double SEVENTH = 1.0 / 7.0; /* ---------------------------------------------------------------------- */ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fix_rheo(nullptr) + Fix(lmp, narg, arg), fix_rheo(nullptr), rho0(nullptr), csq(nullptr), rho0inv(nullptr), csqinv(nullptr), c_cubic(nullptr), pressure_style(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); - pressure_style = NONE; comm_forward = 1; // Currently can only have one instance of fix rheo/pressure if (igroup != 0) error->all(FLERR,"fix rheo/pressure command requires group all"); - int ntypes = atom->ntypes; + int i, nlo, nhi; + int n = atom->ntypes; + memory->create(pressure_style, n + 1, "rheo:pressure_style"); + for (i = 1; i <= n; i++) pressure_style[i] = NONE; + int iarg = 3; - if (strcmp(arg[iarg], "linear") == 0) { - pressure_style = LINEAR; - } else if (strcmp(arg[iarg], "taitwater") == 0) { - pressure_style = TAITWATER; - } else if (strcmp(arg[iarg], "cubic") == 0) { - pressure_style = CUBIC; - if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for pressure option"); - c_cubic = utils::numeric(FLERR, arg[iarg + 1], false, lmp); - } else { - error->all(FLERR,"Illegal fix command, {}", arg[iarg]); + while (iarg < narg) { + utils::bounds(FLERR, arg[iarg], 1, n, nlo, nhi, error); + + if (iarg + 1 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/pressure", error); + + if (strcmp(arg[iarg + 1], "linear") == 0) { + for (i = nlo; i <= nhi; i++) + pressure_style[i] = LINEAR; + } else if (strcmp(arg[iarg + 1], "taitwater") == 0) { + for (i = nlo; i <= nhi; i++) + pressure_style[i] = TAITWATER; + } else if (strcmp(arg[iarg + 1], "cubic") == 0) { + if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/pressure cubic", error); + + double c_cubic_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 1; + + for (i = nlo; i <= nhi; i++) { + pressure_style[i] = CUBIC; + c_cubic[i] = c_cubic_one; + } + } else { + error->all(FLERR,"Illegal fix command, {}", arg[iarg]); + } + iarg += 2; } - if (pressure_style == NONE) - error->all(FLERR,"Must specify pressure style for fix/rheo/pressure"); + for (i = 1; i <= n; i++) + if (pressure_style[i] == NONE) + error->all(FLERR,"Must specify pressure for atom type {} in fix/rheo/pressure", i); } /* ---------------------------------------------------------------------- */ FixRHEOPressure::~FixRHEOPressure() { + memory->destroy(pressure_style); + memory->destroy(csqinv); + memory->destroy(rho0inv); + memory->destroy(c_cubic); } /* ---------------------------------------------------------------------- */ @@ -92,9 +115,15 @@ void FixRHEOPressure::init() csq = fix_rheo->csq; rho0 = fix_rheo->rho0; - rho0inv = 1.0 / rho0; - // Cannot define multiple as pair rheo cannot currently distinguish + int n = atom->ntypes; + memory->create(csqinv, n + 1, "rheo:rho0inv"); + memory->create(rho0inv, n + 1, "rheo:rho0inv"); + for (int i = 0; i <= n; i++) { + csqinv[i] = 1.0 / csq[i]; + rho0inv[i] = 1.0 / rho0[i]; + } + if (modify->get_fix_by_style("rheo/pressure").size() > 1) error->all(FLERR, "Can only specify one instance of fix rheo/pressure"); } @@ -117,6 +146,7 @@ void FixRHEOPressure::pre_force(int /*vflag*/) double dr, rr3, rho_ratio; int *mask = atom->mask; + int *type = atom->type; double *rho = atom->rho; double *pressure = atom->pressure; @@ -124,7 +154,7 @@ void FixRHEOPressure::pre_force(int /*vflag*/) for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) - pressure[i] = calc_pressure(rho[i]); + pressure[i] = calc_pressure(rho[i], type[i]); if (comm_forward) comm->forward_comm(this); } @@ -161,19 +191,37 @@ void FixRHEOPressure::unpack_forward_comm(int n, int first, double *buf) /* ---------------------------------------------------------------------- */ -double FixRHEOPressure::calc_pressure(double rho) +double FixRHEOPressure::calc_pressure(double rho, int type) { double p, dr, rr3, rho_ratio; - if (pressure_style == LINEAR) { - p = csq * (rho - rho0); - } else if (pressure_style == CUBIC) { - dr = rho - rho0; - p = csq * (dr + c_cubic * dr * dr * dr); - } else if (pressure_style == TAITWATER) { - rho_ratio = rho / rho0inv; + if (pressure_style[type] == LINEAR) { + p = csq[type] * (rho - rho0[type]); + } else if (pressure_style[type] == CUBIC) { + dr = rho - rho0[type]; + p = csq[type] * (dr + c_cubic[type] * dr * dr * dr); + } else if (pressure_style[type] == TAITWATER) { + rho_ratio = rho * rho0inv[type]; rr3 = rho_ratio * rho_ratio * rho_ratio; - p = csq * rho0 * SEVENTH * (rr3 * rr3 * rho_ratio - 1.0); + p = csq[type] * rho0[type] * SEVENTH * (rr3 * rr3 * rho_ratio - 1.0); } return p; } + +/* ---------------------------------------------------------------------- */ + +double FixRHEOPressure::calc_rho(double p, int type) +{ + double rho, dr, rr3, rho_ratio; + + if (pressure_style[type] == LINEAR) { + rho = csqinv[type] * p + rho0[type]; + } else if (pressure_style[type] == CUBIC) { + error->one(FLERR, "Rho calculation from pressure not yet supported for cubic pressure equation"); + } else if (pressure_style[type] == TAITWATER) { + rho = pow(7.0 * p + csq[type] * rho0[type], SEVENTH); + rho *= pow(rho0[type], 6.0 * SEVENTH); + rho *= pow(csq[type], -SEVENTH); + } + return rho; +} diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index cbcb495244..ee86c5e184 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -34,11 +34,12 @@ class FixRHEOPressure : public Fix { void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; - double calc_pressure(double); + double calc_pressure(double, int); + double calc_rho(double, int); private: - double c_cubic, csq, rho0, rho0inv; - int pressure_style; + double *c_cubic, *csq, *csqinv, *rho0, *rho0inv; + int *pressure_style; class FixRHEO *fix_rheo; }; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 3b38089fad..dd2c6eddbd 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -41,108 +41,124 @@ using namespace LAMMPS_NS; using namespace RHEO_NS; using namespace FixConst; -enum {NONE, CONSTANT, TYPE}; +enum {NONE, CONSTANT}; /* ---------------------------------------------------------------------- */ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), compute_vshift(nullptr), - Tc_type(nullptr), kappa_type(nullptr), cv_type(nullptr), fix_update_special_bonds(nullptr) + Tc(nullptr), kappa(nullptr), cv(nullptr), Tc_style(nullptr), kappa_style(nullptr), cv_style(nullptr), + fix_update_special_bonds(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); force_reneighbor = 1; next_reneighbor = -1; - - Tc_style = NONE; - cv_style = NONE; - conductivity_style = NONE; cut_bond = 0; comm_forward = 0; - int ntypes = atom->ntypes; + if (igroup != 0) + error->all(FLERR,"fix rheo/thermal command requires group all"); + + int i, nlo, nhi; + int n = atom->ntypes; + memory->create(Tc_style, n + 1, "rheo:Tc_style"); + memory->create(kappa_style, n + 1, "rheo:kappa_style"); + memory->create(cv_style, n + 1, "rheo:cv_style"); + for (i = 1; i <= n; i++) { + Tc_style[i] = NONE; + kappa_style[i] = NONE; + cv_style[i] = NONE; + } + int iarg = 3; while (iarg < narg) { if (strcmp(arg[iarg],"conductivity") == 0) { + if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal conductivity", error); + utils::bounds(FLERR, arg[iarg + 1], 1, n, nlo, nhi, error); + // Conductivity arguments - if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for conductivity option"); - if (strcmp(arg[iarg + 1], "constant") == 0) { - if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for conductivity option"); - conductivity_style = CONSTANT; - kappa = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - if (kappa < 0.0) error->all(FLERR, "The conductivity must be positive"); - iarg += 2; - } else if (strcmp(arg[iarg + 1], "type") == 0) { - if (iarg + 1 + ntypes >= narg) error->all(FLERR, "Insufficient arguments for conductivity option"); - conductivity_style = TYPE; - memory->create(kappa_type, ntypes+1, "rheo_thermal:kappa_type"); - for (int i = 1; i <= ntypes; i++) { - kappa_type[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); - if (kappa_type[i] < 0.0) error->all(FLERR, "The conductivity must be positive"); + if (strcmp(arg[iarg + 2], "constant") == 0) { + if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal conductivity constant", error); + + double kappa_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + if (kappa_one < 0.0) error->all(FLERR, "The conductivity must be positive"); + iarg += 1; + + for (i = nlo; i <= nhi; i++) { + kappa_style[i] = CONSTANT; + kappa[i] = kappa_one; } - iarg += 1 + ntypes; } else { - error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); + error->all(FLERR,"Illegal fix command, {}", arg[iarg + 2]); } + + iarg += 2; } else if (strcmp(arg[iarg], "specific/heat") == 0) { + if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal specific/heat", error); + utils::bounds(FLERR, arg[iarg + 1], 1, n, nlo, nhi, error); + // Cv arguments - if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for cv option"); - if (strcmp(arg[iarg + 1], "constant") == 0) { - if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for cv option"); - cv_style = CONSTANT; - cv = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - if (cv < 0.0) error->all(FLERR, "The specific heat must be positive"); - iarg += 2; - } else if (strcmp(arg[iarg + 1], "type") == 0) { - if (iarg + 1 + ntypes >= narg) error->all(FLERR, "Insufficient arguments for cv option"); - cv_style = TYPE; - memory->create(cv_type,ntypes + 1, "rheo_thermal:cv_type"); - for (int i = 1; i <= ntypes; i++) { - cv_type[i] = utils::numeric(FLERR, arg[iarg + 1 + i], false, lmp); - if (cv_type[i] < 0.0) error->all(FLERR, "The specific heat must be positive"); + if (strcmp(arg[iarg + 2], "constant") == 0) { + if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal specific/heat constant", error); + + double cv_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + if (cv_one < 0.0) error->all(FLERR, "The specific heat must be positive"); + iarg += 1; + + for (i = nlo; i <= nhi; i++) { + cv_style[i] = CONSTANT; + cv[i] = cv_one; } - iarg += 1 + ntypes; + } else { - error->all(FLERR,"Illegal fix command, {}", arg[iarg + 1]); + error->all(FLERR,"Illegal fix command, {}", arg[iarg + 2]); } + + iarg += 2; } else if (strcmp(arg[iarg], "Tfreeze") == 0) { + if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal Tfreeze", error); + utils::bounds(FLERR, arg[iarg + 1], 1, n, nlo, nhi, error); + // T freeze arguments - if (iarg + 1 >= narg) error->all(FLERR, "Insufficient arguments for Tfreeze option"); - if (strcmp(arg[iarg + 1], "constant") == 0) { - if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for Tfreeze option"); - Tc_style = CONSTANT; - Tc = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 2; - } else if (strcmp(arg[iarg + 1], "type") == 0) { - if (iarg + 1 + ntypes >= narg) error->all(FLERR, "Insufficient arguments for Tfreeze option"); - Tc_style = TYPE; - memory->create(Tc_type, ntypes + 1, "rheo_thermal:Tc_type"); - for (int i = 1; i <= ntypes; i++) { - Tc_type[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); - if (Tc_type[i] < 0.0) error->all(FLERR, "The melting temperature must be positive"); + if (strcmp(arg[iarg + 2], "constant") == 0) { + if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal Tfreeze constant", error); + + double Tc_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + iarg += 1; + + for (i = nlo; i <= nhi; i++) { + Tc_style[i] = CONSTANT; + Tc[i] = Tc_one; } - iarg += 1 + ntypes; + } else { - error->all(FLERR, "Illegal fix command, {}", arg[iarg + 1]); + error->all(FLERR, "Illegal fix command, {}", arg[iarg + 2]); } + + iarg += 2; } else if (strcmp(arg[iarg], "react") == 0) { - if (iarg + 2 >= narg) error->all(FLERR, "Insufficient arguments for react option"); + if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal react", error); cut_bond = utils::numeric(FLERR, arg[iarg + 1], false, lmp); btype = utils::numeric(FLERR, arg[iarg + 2], false, lmp); comm_forward = 1; - if (cut_bond <= 0.0) error->all(FLERR, "Illegal value for bond lengths");\ + if (cut_bond <= 0.0) error->all(FLERR, "Illegal max bond length must be greater than zero");\ if (btype < 1 || btype > atom->nbondtypes) error->all(FLERR, "Illegal value for bond type"); cutsq_bond = cut_bond * cut_bond; - iarg += 2; + iarg += 3; } else { error->all(FLERR,"Illegal fix command, {}", arg[iarg]); } - iarg += 1; } - if (cv_style == NONE || conductivity_style == NONE) - error->all(FLERR, "Must specify specific heat and conductivity styles\n"); + + for (i = 1; i <= n; i++) { + if (cv_style[i] == NONE) + error->all(FLERR,"Must specify specific/heat for atom type {} in fix/rheo/thermal", i); + if (kappa_style[i] == NONE) + error->all(FLERR,"Must specify conductivity for atom type {} in fix/rheo/thermal", i); + } } /* ---------------------------------------------------------------------- */ @@ -154,9 +170,12 @@ FixRHEOThermal::~FixRHEOThermal() index = atom->find_custom("rheo_conductivity", tmp1, tmp2); if (index != -1) atom->remove_custom(index, 1, 0); - memory->destroy(cv_type); - memory->destroy(Tc_type); - memory->destroy(kappa_type); + memory->destroy(cv_style); + memory->destroy(Tc_style); + memory->destroy(kappa_style); + memory->destroy(cv); + memory->destroy(Tc); + memory->destroy(kappa); } /* ---------------------------------------------------------------------- */ @@ -198,7 +217,6 @@ void FixRHEOThermal::init() if (atom->conductivity_flag != 1) error->all(FLERR,"fix rheo/thermal command requires atom property conductivity"); - if (cut_bond > 0.0) { if (!force->bond) error->all(FLERR,"Must define a bond style to use reactive bond generation with fix rheo/thermal"); if (!atom->avec->bonds_allow) error->all(FLERR, "Reactive bond generation in fix rheo/thermal requires atom bonds"); @@ -249,7 +267,6 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) int i, a; int *status = atom->status; - int *mask = atom->mask; double *temperature = atom->temperature; double **gradt = compute_grad->gradt; double **vshift = compute_vshift->array_atom; @@ -263,11 +280,8 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) for (i = 0; i < nlocal; i++) { if (status[i] & STATUS_NO_SHIFT) continue; - if (mask[i] & groupbit) { - for (a = 0; a < dim; a++) { - temperature[i] += dtv * vshift[i][a] * gradt[i][a]; - } - } + for (a = 0; a < dim; a++) + temperature[i] += dtv * vshift[i][a] * gradt[i][a]; } } @@ -275,52 +289,50 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) void FixRHEOThermal::post_integrate() { + int i, itype; + double cvi, Tci, Ti; + int *status = atom->status; double *temperature = atom->temperature; double *heatflow = atom->heatflow; double *rho = atom->rho; - int *mask = atom->mask; int *type = atom->type; - double cvi, Tci, Ti; - int n_melt = 0; int n_freeze = 0; //Integrate temperature and check status - for (int i = 0; i < atom->nlocal; i++) { - if (mask[i] & groupbit) { - if (status[i] & STATUS_NO_INTEGRATION) continue; + for (i = 0; i < atom->nlocal; i++) { + if (status[i] & STATUS_NO_INTEGRATION) continue; - cvi = calc_cv(i); - temperature[i] += dtf * heatflow[i] / cvi; + itype = type[i]; + cvi = calc_cv(i, type[i]); + temperature[i] += dtf * heatflow[i] / cvi; - if (Tc_style != NONE) { - Ti = temperature[i]; - if (Tc_style == CONSTANT) { - Tci = Tc; - } else if (Tc_style == TYPE) { - Tci = Tc_type[type[i]]; + if (Tc_style[itype] != NONE) { + Ti = temperature[i]; + if (Tc_style[itype] == CONSTANT) { + Tci = Tc[itype]; + } + + if (Ti > Tci) { + // If solid, melt + if (status[i] & STATUS_SOLID) { + status[i] &= PHASEMASK; + status[i] |= STATUS_MELTING; + n_melt += 1; } - - if (Ti > Tci) { - // If solid, melt - if (status[i] & STATUS_SOLID) { - status[i] &= PHASEMASK; - status[i] |= STATUS_MELTING; - n_melt += 1; - } - } else { - // If fluid, freeze - if (!(status[i] & STATUS_SOLID)) { - status[i] &= PHASEMASK; - status[i] |= STATUS_SOLID; - status[i] |= STATUS_FREEZING; - n_freeze += 1; - } + } else { + // If fluid, freeze + if (!(status[i] & STATUS_SOLID)) { + status[i] &= PHASEMASK; + status[i] |= STATUS_SOLID; + status[i] |= STATUS_FREEZING; + n_freeze += 1; } } } + } int n_melt_all, n_freeze_all; @@ -344,19 +356,16 @@ void FixRHEOThermal::post_integrate() void FixRHEOThermal::post_neighbor() { - int i; + int i, itype; int *type = atom->type; - int *mask = atom->mask; double *conductivity = atom->conductivity; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (conductivity_style == CONSTANT) { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) conductivity[i] = kappa; - } else if (conductivity_style == TYPE) { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) conductivity[i] = kappa_type[type[i]]; + for (i = 0; i < nall; i++) { + itype = type[i]; + if (kappa_style[itype] == CONSTANT) + conductivity[i] = kappa[itype]; } } @@ -372,21 +381,18 @@ void FixRHEOThermal::pre_force(int /*vflag*/) void FixRHEOThermal::final_integrate() { + int *status = atom->status; + int *type = atom->type; double *temperature = atom->temperature; double *heatflow = atom->heatflow; - int *status = atom->status; - int *mask = atom->mask; - double cvi; //Integrate temperature and check status for (int i = 0; i < atom->nlocal; i++) { - if (mask[i] & groupbit) { - if (status[i] & STATUS_NO_INTEGRATION) continue; + if (status[i] & STATUS_NO_INTEGRATION) continue; - cvi = calc_cv(i); - temperature[i] += dtf * heatflow[i] / cvi; - } + cvi = calc_cv(i, type[i]); + temperature[i] += dtf * heatflow[i] / cvi; } } @@ -522,12 +528,10 @@ void FixRHEOThermal::create_bonds() /* ---------------------------------------------------------------------- */ -double FixRHEOThermal::calc_cv(int i) +double FixRHEOThermal::calc_cv(int i, int itype) { - if (cv_style == CONSTANT) { - return cv; - } else if (cv_style == TYPE) { - return(cv_type[atom->type[i]]); + if (cv_style[itype] == CONSTANT) { + return cv[itype]; } } diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index da48a59e22..dc412d20b9 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -42,17 +42,14 @@ class FixRHEOThermal : public Fix { int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; void reset_dt() override; - double calc_cv(int); + double calc_cv(int, int); private: - double *cv_type, cv; - double *Tc_type, Tc; - double *kappa_type, kappa; + double *cv, *Tc, *kappa; double dtf, dtv; double cut_kernel, cut_bond, cutsq_bond; - int Tc_style, cv_style; + int *cv_style, *Tc_style, *kappa_style; int btype; - int conductivity_style; class NeighList *list; int n_histories; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index e33bd43244..91799ccfd0 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -32,60 +32,87 @@ using namespace LAMMPS_NS; using namespace FixConst; -enum {NONE, CONSTANT, TYPE, POWER}; +enum {NONE, CONSTANT, POWER}; /* ---------------------------------------------------------------------- */ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), eta_type(nullptr) + Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), eta(nullptr), + npow(nullptr), K(nullptr), gd0(nullptr), tau0(nullptr), viscosity_style(nullptr) { - if (narg < 4) error->all(FLERR,"Illegal fix command"); - - viscosity_style = NONE; + if (narg < 4) error->all(FLERR, "Illegal fix command"); comm_forward = 0; + constant_flag = 0; + evolve_flag = 0; + + if (igroup != 0) + error->all(FLERR,"fix rheo/viscosity command requires group all"); + + int i, nlo, nhi; + int n = atom->ntypes; + memory->create(viscosity_style, n + 1, "rheo:viscosity_style"); + for (i = 1; i <= n; i++) viscosity_style[i] = NONE; - int ntypes = atom->ntypes; int iarg = 3; - if (strcmp(arg[iarg],"constant") == 0) { - if (iarg + 1 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); - viscosity_style = CONSTANT; - eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); - if (eta < 0.0) error->all(FLERR,"The viscosity must be positive"); - iarg += 1; - } else if (strcmp(arg[iarg],"type") == 0) { - if (iarg + ntypes >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); - viscosity_style = TYPE; - memory->create(eta_type, ntypes + 1, "rheo_thermal:eta_type"); - for (int i = 1; i <= ntypes; i++) { - eta_type[i] = utils::numeric(FLERR,arg[iarg + i], false, lmp); - if (eta_type[i] < 0.0) error->all(FLERR,"The viscosity must be positive"); + while (iarg < narg) { + utils::bounds(FLERR, arg[iarg], 1, n, nlo, nhi, error); + + if (iarg + 1 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/viscosity", error); + + if (strcmp(arg[iarg + 1], "constant") == 0) { + if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/viscosity constant", error); + + constant_flag = 1; + double eta_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + if (eta_one < 0.0) error->all(FLERR, "The viscosity must be positive"); + iarg += 1; + + for (i = nlo; i <= nhi; i++) { + viscosity_style[i] = CONSTANT; + eta[i] = eta_one; + } + } else if (strcmp(arg[iarg], "power") == 0) { + if (iarg + 5 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/viscosity power", error); + + comm_forward = 1; + evolve_flag = 1; + double eta_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + double gd0_one = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + double K_one = utils::numeric(FLERR, arg[iarg + 4], false, lmp); + double npow_one = utils::numeric(FLERR, arg[iarg + 5], false, lmp); + if (eta_one < 0.0) error->all(FLERR, "The viscosity must be positive"); + iarg += 4; + + for (i = nlo; i <= nhi; i++) { + viscosity_style[i] = POWER; + eta[i] = eta_one; + gd0[i] = gd0_one; + K[i] = K_one; + npow[i] = npow_one; + tau0[i] = eta[i] * gd0[i] - K[i] * pow(gd0[i], npow[i]); + } + } else { + error->all(FLERR, "Illegal fix command, {}", arg[iarg]); } - iarg += ntypes; - } else if (strcmp(arg[iarg],"power") == 0) { - if (iarg + 4 >= narg) error->all(FLERR,"Insufficient arguments for viscosity option"); - viscosity_style = POWER; - comm_forward = 1; - eta = utils::numeric(FLERR,arg[iarg + 1],false,lmp); - gd0 = utils::numeric(FLERR,arg[iarg + 2],false,lmp); - K = utils::numeric(FLERR,arg[iarg + 3],false,lmp); - npow = utils::numeric(FLERR,arg[iarg + 4],false,lmp); - tau0 = eta * gd0 - K * pow(gd0, npow); - if (eta < 0.0) error->all(FLERR,"The viscosity must be positive"); - iarg += 5; - } else { - error->all(FLERR,"Illegal fix command, {}", arg[iarg]); + iarg += 2; } - if (viscosity_style == NONE) - error->all(FLERR,"Must specify viscosity style for fix/rheo/viscosity"); + for (i = 1; i <= n; i++) + if (viscosity_style[i] == NONE) + error->all(FLERR,"Must specify viscosity for atom type {} in fix/rheo/viscosity", i); } /* ---------------------------------------------------------------------- */ FixRHEOViscosity::~FixRHEOViscosity() { - memory->destroy(eta_type); + memory->destroy(viscosity_style); + memory->destroy(eta); + memory->destroy(gd0); + memory->destroy(K); + memory->destroy(npow); + memory->destroy(tau0); } /* ---------------------------------------------------------------------- */ @@ -115,17 +142,8 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) { fix_rheo->viscosity_fix_defined = 1; - // Identify whether this is the last instance of fix viscosity - last_flag = 0; - - int i = 0; - auto fixlist = modify->get_fix_by_style("rheo/viscosity"); - for (const auto &fix : fixlist) { - if (strcmp(fix->id, id) == 0) break; - i++; - } - - if ((i + 1) == fixlist.size()) last_flag = 1; + if (modify->get_fix_by_style("rheo/viscosity").size() > 1) + error->all(FLERR, "More than one fix rheo/viscosity defined"); post_neighbor(); pre_force(0); @@ -137,20 +155,18 @@ void FixRHEOViscosity::setup_pre_force(int /*vflag*/) void FixRHEOViscosity::post_neighbor() { - int i; + if (!constant_flag) return; + int i, itype; int *type = atom->type; - int *mask = atom->mask; double *viscosity = atom->viscosity; int nall = atom->nlocal + atom->nghost; - if (viscosity_style == CONSTANT) { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) viscosity[i] = eta; - } else if (viscosity_style == TYPE) { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) viscosity[i] = eta_type[type[i]]; + for (i = 0; i < nall; i++) { + itype = type[i]; + if (viscosity_style[itype]) + viscosity[i] = eta[itype]; } } @@ -160,39 +176,41 @@ void FixRHEOViscosity::post_neighbor() void FixRHEOViscosity::pre_force(int /*vflag*/) { - int i, a, b; + if (!evolve_flag) return; + + int i, itype, a, b; double tmp, gdot; - int *mask = atom->mask; + int *type = atom->type; double *viscosity = atom->viscosity; double **gradv = compute_grad->gradv; int nlocal = atom->nlocal; int dim = domain->dimension; - if (viscosity_style == POWER) { - for (i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) { - gdot = 0.0; - for (a = 0; a < dim; a++) { - for (b = a; b < dim; b++) { - tmp = gradv[i][a * dim + b] + gradv[i][b * dim + a]; - tmp = tmp * tmp; - if (a == b) tmp *= 0.5; - gdot += tmp; - } - } - gdot = sqrt(gdot); - if (gdot <= gd0) { - viscosity[i] = eta; - } else { - viscosity[i] = K * pow(gdot, npow - 1) + tau0 / gdot; + + for (i = 0; i < nlocal; i++) { + itype = type[i]; + if (viscosity_style[itype] == POWER) { + gdot = 0.0; + for (a = 0; a < dim; a++) { + for (b = a; b < dim; b++) { + tmp = gradv[i][a * dim + b] + gradv[i][b * dim + a]; + tmp = tmp * tmp; + if (a == b) tmp *= 0.5; + gdot += tmp; } } + gdot = sqrt(gdot); + if (gdot <= gd0[itype]) { + viscosity[i] = eta[itype]; + } else { + viscosity[i] = K[itype] * pow(gdot, npow[itype] - 1) + tau0[itype] / gdot; + } } } - if (last_flag && comm_forward) comm->forward_comm(this); + if (comm_forward) comm->forward_comm(this); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_viscosity.h b/src/RHEO/fix_rheo_viscosity.h index c681d18c00..f81feb74b2 100644 --- a/src/RHEO/fix_rheo_viscosity.h +++ b/src/RHEO/fix_rheo_viscosity.h @@ -37,9 +37,8 @@ class FixRHEOViscosity : public Fix { void unpack_forward_comm(int, int, double *) override; private: - double *eta_type, eta; - double npow, K, gd0, tau0; - int viscosity_style, last_flag; + double *eta, *npow, *K, *gd0, *tau0; + int *viscosity_style, constant_flag, evolve_flag; class FixRHEO *fix_rheo; class ComputeRHEOGrad *compute_grad; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index e22715eab1..bb3d5c3fda 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -47,8 +47,8 @@ static constexpr double EPSILON = 1e-2; /* ---------------------------------------------------------------------- */ PairRHEO::PairRHEO(LAMMPS *lmp) : - Pair(lmp), compute_kernel(nullptr), compute_grad(nullptr), - compute_interface(nullptr), fix_rheo(nullptr), fix_pressure(nullptr) + Pair(lmp), compute_kernel(nullptr), compute_grad(nullptr), compute_interface(nullptr), fix_rheo(nullptr), + fix_pressure(nullptr), rho0(nullptr), csq(nullptr), cs(nullptr) { restartinfo = 0; single_enable = 0; @@ -68,6 +68,8 @@ PairRHEO::~PairRHEO() memory->destroy(setflag); memory->destroy(cutsq); } + + memory->destroy(cs); } /* ---------------------------------------------------------------------- */ @@ -77,8 +79,8 @@ void PairRHEO::compute(int eflag, int vflag) int i, j, a, b, ii, jj, inum, jnum, itype, jtype; int pair_force_flag, pair_rho_flag, pair_avisc_flag; int fluidi, fluidj; - double xtmp, ytmp, ztmp, w, wp, Ti, Tj, dT; - double rhoi, rhoj, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj; + double xtmp, ytmp, ztmp, w, wp, Ti, Tj, dT, csq_ave, cs_ave; + double rhoi, rhoj, rho0i, rho0j, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj; double mu, q, fp_prefactor, drho_damp, fmag, psi_ij, Fij; double *dWij, *dWji, *dW1ij, *dW1ji; double dx[3], du[3], dv[3], fv[3], dfp[3], fsolid[3], ft[3], vi[3], vj[3]; @@ -178,6 +180,9 @@ void PairRHEO::compute(int eflag, int vflag) kappaj = conductivity[j]; } + cs_ave = 0.5 * (cs[itype] + cs[jtype]); + csq_ave = cs_ave * cs_ave; + pair_rho_flag = 0; pair_force_flag = 0; pair_avisc_flag = 0; @@ -201,31 +206,31 @@ void PairRHEO::compute(int eflag, int vflag) // Add corrections for walls rhoi = rho[i]; rhoj = rho[j]; + rho0i = rho[itype]; + rho0j = rho[jtype]; Pi = pressure[i]; Pj = pressure[j]; fmag = 0; if (interface_flag) { if (fluidi && (!fluidj)) { compute_interface->correct_v(vi, vj, i, j); - //compute_interface->correct_v(vj, vi, j, i); rhoj = compute_interface->correct_rho(j, i); - Pj = fix_pressure->calc_pressure(rhoj); + Pj = fix_pressure->calc_pressure(rhoj, jtype); if ((chi[j] > 0.9) && (r < (h * 0.5))) - fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; + fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0j * csq_ave * h * rinv; } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vj, vi, j, i); - //compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i, j); - Pi = fix_pressure->calc_pressure(rhoi); + Pi = fix_pressure->calc_pressure(rhoi, itype); if (chi[i] > 0.9 && r < (h * 0.5)) - fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0 * csq * h * rinv; + fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0i * csq_ave * h * rinv; } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0; - rhoj = rho0; + rhoi = rho0i; + rhoj = rho0j; } } @@ -239,12 +244,12 @@ void PairRHEO::compute(int eflag, int vflag) // Thermal Evolution if (thermal_flag) { dT = dot3(dx, dWij); - dT *= (kappai + kappaj) * (Ti - Tj) * rinv * rinv * voli * volj / rho0; + dT *= (kappai + kappaj) * (Ti - Tj) * rinv * rinv * voli * volj * 2.0 / (rhoi + rhoj); heatflow[i] += dT; if (newton_pair || j < nlocal) { dT = dot3(dx, dWji); - dT *= (kappai + kappaj) * (Tj - Ti) * rinv * rinv * voli * volj / rho0; + dT *= (kappai + kappaj) * (Tj - Ti) * rinv * rinv * voli * volj * 2.0 / (rhoi + rhoj); heatflow[j] -= dT; } } @@ -266,7 +271,7 @@ void PairRHEO::compute(int eflag, int vflag) mu = dot3(du, dx) * hinv3; mu /= (rsq * hinv3 * hinv3 + EPSILON); mu = MIN(0.0, mu); - q = av * (-2.0 * cs * mu + mu * mu); + q = av * (-2.0 * cs_ave * mu + mu * mu); fp_prefactor += voli * volj * q * (rhoj + rhoi); } @@ -334,7 +339,7 @@ void PairRHEO::compute(int eflag, int vflag) psi_ij += 0.5 * (gradr[i][a] + gradr[j][a]) * dx[a]; drho[i] += 2 * rho_damp * psi_ij * Fij * volj; } else { - drho_damp = 2 * rho_damp * (rhoj - rhoi) * rinv * wp; + drho_damp = 2 * rho_damp * ((rhoj - rho0[jtype]) - (rhoi - rho0[itype])) * rinv * wp; drho[i] -= drho_damp * volj; } @@ -383,23 +388,23 @@ void PairRHEO::allocate() void PairRHEO::settings(int narg, char **arg) { - if (narg < 1) error->all(FLERR,"Illegal pair_style command"); + if (narg < 1) error->all(FLERR, "Illegal pair_style command"); - h = utils::numeric(FLERR,arg[0],false,lmp); + h = utils::numeric(FLERR, arg[0], false, lmp); int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg], "rho/damp") == 0) { - if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_style command"); + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_style command"); rho_damp_flag = 1; - rho_damp = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + rho_damp = utils::numeric(FLERR, arg[iarg + 1], false, lmp); iarg++; } else if (strcmp(arg[iarg], "artificial/visc") == 0) { - if (iarg + 1 >= narg) error->all(FLERR,"Illegal pair_style command"); + if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_style command"); artificial_visc_flag = 1; - av = utils::numeric(FLERR,arg[iarg + 1],false,lmp); + av = utils::numeric(FLERR, arg[iarg + 1], false, lmp); iarg++; - } else error->all(FLERR,"Illegal pair_style command, {}", arg[iarg]); + } else error->all(FLERR, "Illegal pair_style command, {}", arg[iarg]); iarg++; } } @@ -411,13 +416,13 @@ void PairRHEO::settings(int narg, char **arg) void PairRHEO::coeff(int narg, char **arg) { if (narg != 2) - error->all(FLERR,"Incorrect number of args for pair_style rheo coefficients"); + error->all(FLERR, "Incorrect number of args for pair_style rheo coefficients"); if (!allocated) allocate(); int ilo, ihi, jlo, jhi; - utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); - utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); + utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi, error); + utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi, error); int count = 0; for (int i = ilo; i <= ihi; i++) { @@ -428,7 +433,7 @@ void PairRHEO::coeff(int narg, char **arg) } if (count == 0) - error->all(FLERR,"Incorrect args for pair rheo coefficients"); + error->all(FLERR, "Incorrect args for pair rheo coefficients"); } /* ---------------------------------------------------------------------- @@ -460,11 +465,14 @@ void PairRHEO::setup() hsq = h * h; hinv = 1.0 / h; hinv3 = hinv * 3.0; - cs = sqrt(csq); laplacian_order = -1; + int n = atom->ntypes; + memory->create(cs, n + 1, "rheo:cs"); + for (int i = 0; i <= n; i++) cs[i] = sqrt(csq[i]); + if (comm->ghost_velocity == 0) - error->all(FLERR,"Pair RHEO requires ghost atoms store velocity"); + error->all(FLERR, "Pair RHEO requires ghost atoms store velocity"); if (laplacian_order == -1) { if (fix_rheo->kernel_style == RK2) @@ -482,9 +490,8 @@ void PairRHEO::setup() double PairRHEO::init_one(int i, int j) { - if (setflag[i][j] == 0) { - error->all(FLERR,"All pair rheo coeffs are not set"); - } + if (setflag[i][j] == 0) + error->all(FLERR, "All pair rheo coeffs are not set"); return h; } diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index cb2227c8d6..c43d450b8b 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -37,8 +37,8 @@ class PairRHEO : public Pair { void unpack_reverse_comm(int, int *, double *) override; protected: - double h, csq, rho0; // From fix RHEO - double cs, hsq, hinv, hinv3, av, rho_damp; + double h, *csq, *rho0; // From fix RHEO + double *cs, hsq, hinv, hinv3, av, rho_damp; int laplacian_order; int artificial_visc_flag; diff --git a/src/RHEO/pair_rheo_react.cpp b/src/RHEO/pair_rheo_react.cpp index d7412d5d0e..1d54208792 100644 --- a/src/RHEO/pair_rheo_react.cpp +++ b/src/RHEO/pair_rheo_react.cpp @@ -296,20 +296,20 @@ void PairRHEOReact::allocate() allocated = 1; int n = atom->ntypes; - memory->create(setflag, n+1, n+1,"pair:setflag"); + memory->create(setflag, n + 1, n + 1, "pair:setflag"); for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) setflag[i][j] = 0; - memory->create(cut, n+1, n+1,"pair:cut"); - memory->create(cutbond, n+1, n+1,"pair:cutbond"); - memory->create(cutsq, n+1, n+1,"pair:cutsq"); - memory->create(cutbsq, n+1, n+1,"pair:cutbsq"); - memory->create(k, n+1, n+1,"pair:k"); - memory->create(eps, n+1, n+1,"pair:eps"); - memory->create(gamma, n+1, n+1,"pair:gamma"); - memory->create(t_form, n+1, n+1,"pair:t_form"); - memory->create(rlimit, n+1, n+1,"pair:rlimit"); + memory->create(cut, n + 1, n + 1, "pair:cut"); + memory->create(cutbond, n + 1, n + 1, "pair:cutbond"); + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); + memory->create(cutbsq, n + 1, n + 1, "pair:cutbsq"); + memory->create(k, n + 1, n + 1, "pair:k"); + memory->create(eps, n + 1, n + 1, "pair:eps"); + memory->create(gamma, n + 1, n + 1, "pair:gamma"); + memory->create(t_form, n + 1, n + 1, "pair:t_form"); + memory->create(rlimit, n + 1, n + 1, "pair:rlimit"); } /* ---------------------------------------------------------------------- @@ -326,7 +326,7 @@ void PairRHEOReact::settings(int narg, char **arg) void PairRHEOReact::coeff(int narg, char **arg) { - if (narg != 9) error->all(FLERR,"Incorrect args for pair coefficients"); + if (narg != 9) error->all(FLERR, "Incorrect args for pair coefficients"); if (!allocated) allocate(); int ilo, ihi, jlo, jhi; @@ -343,7 +343,7 @@ void PairRHEOReact::coeff(int narg, char **arg) if (k_one < 0.0 || eps_one < 0.0 || t_form_one < 0.0 || (1.0 + eps_one) * cutb_one > cut_one) - error->all(FLERR,"Illegal pair_style command"); + error->all(FLERR, "Illegal pair_style command"); int count = 0; for (int i = ilo; i <= ihi; i++) { @@ -360,7 +360,7 @@ void PairRHEOReact::coeff(int narg, char **arg) } } - if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); + if (count == 0) error->all(FLERR, "Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- @@ -406,7 +406,7 @@ void PairRHEOReact::setup() double PairRHEOReact::init_one(int i, int j) { - if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); + if (setflag[i][j] == 0) error->all(FLERR, "All pair coeffs are not set"); cutbsq[i][j] = cutbond[i][j] * cutbond[i][j]; From 1e26c6d0c5c344cbb69dea7ca9b24774b6a090c6 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 27 Nov 2023 15:53:19 -0700 Subject: [PATCH 061/385] Adding multiphase support, new stress --- src/RHEO/compute_rheo_property_atom.cpp | 31 ++++++- src/RHEO/compute_rheo_property_atom.h | 4 +- src/RHEO/compute_rheo_rho_sum.cpp | 5 +- src/RHEO/fix_rheo.cpp | 12 ++- src/RHEO/fix_rheo_pressure.cpp | 32 +++++++- src/RHEO/fix_rheo_pressure.h | 2 +- src/RHEO/fix_rheo_thermal.cpp | 2 +- src/RHEO/fix_rheo_viscosity.cpp | 4 + src/RHEO/pair_rheo.cpp | 52 +++++++++--- src/RHEO/pair_rheo.h | 2 + src/pair.cpp | 102 ++++++++++++++++++++++++ src/pair.h | 2 + 12 files changed, 222 insertions(+), 28 deletions(-) diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 50bcb2a2d0..e450eaaf0b 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -14,7 +14,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL) ----------------------------------------------------------------------- */ #include "compute_rheo_property_atom.h" @@ -29,6 +29,7 @@ #include "domain.h" #include "error.h" #include "fix_rheo.h" +#include "fix_rheo_pressure.h" #include "fix_rheo_thermal.h" #include "memory.h" #include "modify.h" @@ -44,7 +45,7 @@ using namespace RHEO_NS; /* ---------------------------------------------------------------------- */ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg), fix_rheo(nullptr), fix_thermal(nullptr), compute_interface(nullptr), + Compute(lmp, narg, arg), fix_rheo(nullptr), fix_pressure(nullptr), fix_thermal(nullptr), compute_interface(nullptr), compute_kernel(nullptr), compute_surface(nullptr), compute_vshift(nullptr), compute_grad(nullptr), avec_index(nullptr), pack_choice(nullptr), col_index(nullptr) { @@ -55,7 +56,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; - thermal_flag = interface_flag = surface_flag = shift_flag = 0; + pressure_flag = thermal_flag = interface_flag = surface_flag = shift_flag = 0; // parse input values // customize a new keyword by adding to if statement @@ -90,6 +91,9 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a col_index[i] = get_vector_index(arg[iarg]); } else if (strcmp(arg[iarg],"coordination") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_coordination; + } else if (strcmp(arg[iarg],"pressure") == 0) { + pressure_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_pressure; } else if (strcmp(arg[iarg],"cv") == 0) { thermal_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; @@ -155,6 +159,11 @@ void ComputeRHEOPropertyAtom::init() fixes = modify->get_fix_by_style("rheo/thermal"); fix_thermal = dynamic_cast(fixes[0]); } + + if (pressure_flag) { + fixes = modify->get_fix_by_style("rheo/pressure"); + fix_pressure = dynamic_cast(fixes[0]); + } } /* ---------------------------------------------------------------------- */ @@ -343,6 +352,22 @@ void ComputeRHEOPropertyAtom::pack_cv(int n) /* ---------------------------------------------------------------------- */ +void ComputeRHEOPropertyAtom::pack_pressure(int n) +{ + int *type = atom->type; + int *mask = atom->mask; + double *rho = atom->rho; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = fix_pressure->calc_pressure(rho[i], type[i]); + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + void ComputeRHEOPropertyAtom::pack_shift_v(int n) { double **vshift = compute_vshift->vshift; diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index bfae870ee5..f3596fbbf9 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -34,7 +34,7 @@ class ComputeRHEOPropertyAtom : public Compute { private: int nvalues, nmax; - int thermal_flag, interface_flag, surface_flag, shift_flag; + int pressure_flag, thermal_flag, interface_flag, surface_flag, shift_flag; int *avec_index; int *col_index; double *buf; @@ -53,12 +53,14 @@ class ComputeRHEOPropertyAtom : public Compute { void pack_cv(int); void pack_shift_v(int); void pack_gradv(int); + void pack_pressure(int); void pack_atom_style(int); int get_vector_index(char*); int get_tensor_index(char*); class FixRHEO *fix_rheo; + class FixRHEOPressure *fix_pressure; class FixRHEOThermal *fix_thermal; class ComputeRHEOInterface *compute_interface; class ComputeRHEOKernel *compute_kernel; diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp index 0a2096a2b9..82d3aa4bc6 100644 --- a/src/RHEO/compute_rheo_rho_sum.cpp +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -88,7 +88,7 @@ void ComputeRHEORhoSum::compute_peratom() // initialize arrays, local with quintic self-contribution, ghosts are zeroed for (i = 0; i < nlocal; i++) { w = compute_kernel->calc_w_quintic(i, i, 0.0, 0.0, 0.0, 0.0); - rho[i] += w * mass[type[i]]; + rho[i] = w * mass[type[i]]; } for (i = nlocal; i < nall; i++) rho[i] = 0.0; @@ -131,12 +131,11 @@ int ComputeRHEORhoSum::pack_forward_comm(int n, int *list, double *buf, { int i, j, k, m; double *rho = atom->rho; - int *coordination = compute_kernel->coordination; m = 0; for (i = 0; i < n; i++) { j = list[i]; - buf[m++] = coordination[j]; + buf[m++] = rho[j]; } return m; } diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index d07f0d1a1f..f0f380f23a 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -279,6 +279,9 @@ void FixRHEO::setup(int /*vflag*/) error->one(FLERR, "Fix rheo/viscosity does not fully cover all atoms"); if (!t_coverage_flag) error->one(FLERR, "Fix rheo/thermal does not fully cover all atoms"); + + if (rhosum_flag) + compute_rhosum->compute_peratom(); } /* ---------------------------------------------------------------------- */ @@ -419,10 +422,11 @@ void FixRHEO::pre_force(int /*vflag*/) status[i] &= OPTIONSMASK; // Calculate surfaces, update status - if (surface_flag) compute_surface->compute_peratom(); - - if (shift_flag) - compute_vshift->correct_surfaces(); + if (surface_flag) { + compute_surface->compute_peratom(); + if (shift_flag) + compute_vshift->correct_surfaces(); + } } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index eac4b34046..8c523b2b35 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -31,14 +31,14 @@ using namespace LAMMPS_NS; using namespace FixConst; -enum {NONE, LINEAR, CUBIC, TAITWATER}; +enum {NONE, LINEAR, CUBIC, TAITWATER, TAITGENERAL}; static constexpr double SEVENTH = 1.0 / 7.0; /* ---------------------------------------------------------------------- */ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), fix_rheo(nullptr), rho0(nullptr), csq(nullptr), rho0inv(nullptr), csqinv(nullptr), c_cubic(nullptr), pressure_style(nullptr) + Fix(lmp, narg, arg), fix_rheo(nullptr), rho0(nullptr), csq(nullptr), rho0inv(nullptr), csqinv(nullptr), c_cubic(nullptr), tpower(nullptr), pbackground(nullptr), pressure_style(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -51,6 +51,9 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : int i, nlo, nhi; int n = atom->ntypes; memory->create(pressure_style, n + 1, "rheo:pressure_style"); + memory->create(c_cubic, n + 1, "rheo:c_cubic"); + memory->create(tpower, n + 1, "rheo:tpower"); + memory->create(pbackground, n + 1, "rheo:pbackground"); for (i = 1; i <= n; i++) pressure_style[i] = NONE; int iarg = 3; @@ -62,9 +65,21 @@ FixRHEOPressure::FixRHEOPressure(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg + 1], "linear") == 0) { for (i = nlo; i <= nhi; i++) pressure_style[i] = LINEAR; - } else if (strcmp(arg[iarg + 1], "taitwater") == 0) { + } else if (strcmp(arg[iarg + 1], "tait/water") == 0) { for (i = nlo; i <= nhi; i++) pressure_style[i] = TAITWATER; + } else if (strcmp(arg[iarg + 1], "tait/general") == 0) { + if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/pressure tait", error); + + double tpower_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + double pbackground_one = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 2; + + for (i = nlo; i <= nhi; i++) { + pressure_style[i] = TAITGENERAL; + tpower[i] = tpower_one; + pbackground[i] = pbackground_one; + } } else if (strcmp(arg[iarg + 1], "cubic") == 0) { if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/pressure cubic", error); @@ -94,6 +109,8 @@ FixRHEOPressure::~FixRHEOPressure() memory->destroy(csqinv); memory->destroy(rho0inv); memory->destroy(c_cubic); + memory->destroy(tpower); + memory->destroy(pbackground); } /* ---------------------------------------------------------------------- */ @@ -204,6 +221,10 @@ double FixRHEOPressure::calc_pressure(double rho, int type) rho_ratio = rho * rho0inv[type]; rr3 = rho_ratio * rho_ratio * rho_ratio; p = csq[type] * rho0[type] * SEVENTH * (rr3 * rr3 * rho_ratio - 1.0); + } else if (pressure_style[type] == TAITGENERAL) { + rho_ratio = rho * rho0inv[type]; + p = csq[type] * rho0[type] * (pow(rho_ratio, tpower[type]) - 1.0) / tpower[type]; + p += pbackground[type]; } return p; } @@ -222,6 +243,11 @@ double FixRHEOPressure::calc_rho(double p, int type) rho = pow(7.0 * p + csq[type] * rho0[type], SEVENTH); rho *= pow(rho0[type], 6.0 * SEVENTH); rho *= pow(csq[type], -SEVENTH); + } else if (pressure_style[type] == TAITGENERAL) { + p -= pbackground[type]; + rho = pow(tpower[type] * p + csq[type] * rho0[type], 1.0 / tpower[type]); + rho *= pow(rho0[type], 1.0 - 1.0 / tpower[type]); + rho *= pow(csq[type], -1.0 / tpower[type]); } return rho; } diff --git a/src/RHEO/fix_rheo_pressure.h b/src/RHEO/fix_rheo_pressure.h index ee86c5e184..ca165b1ed5 100644 --- a/src/RHEO/fix_rheo_pressure.h +++ b/src/RHEO/fix_rheo_pressure.h @@ -38,7 +38,7 @@ class FixRHEOPressure : public Fix { double calc_rho(double, int); private: - double *c_cubic, *csq, *csqinv, *rho0, *rho0inv; + double *c_cubic, *csq, *csqinv, *rho0, *rho0inv, *tpower, *pbackground; int *pressure_style; class FixRHEO *fix_rheo; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index dd2c6eddbd..e6c598418b 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL) ----------------------------------------------------------------------- */ #include "fix_rheo_thermal.h" diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 91799ccfd0..2fffa8b29c 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -52,6 +52,10 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : int i, nlo, nhi; int n = atom->ntypes; memory->create(viscosity_style, n + 1, "rheo:viscosity_style"); + memory->create(eta, n + 1, "rheo:eta"); + memory->create(gd0, n + 1, "rheo:gd0"); + memory->create(K, n + 1, "rheo:K"); + memory->create(npow, n + 1, "rheo:npow"); for (i = 1; i <= n; i++) viscosity_style[i] = NONE; int iarg = 3; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index bb3d5c3fda..339efed866 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -56,6 +56,7 @@ PairRHEO::PairRHEO(LAMMPS *lmp) : artificial_visc_flag = 0; rho_damp_flag = 0; thermal_flag = 0; + harmonic_means_flag = 0; comm_reverse = 3; } @@ -80,7 +81,7 @@ void PairRHEO::compute(int eflag, int vflag) int pair_force_flag, pair_rho_flag, pair_avisc_flag; int fluidi, fluidj; double xtmp, ytmp, ztmp, w, wp, Ti, Tj, dT, csq_ave, cs_ave; - double rhoi, rhoj, rho0i, rho0j, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj; + double rhoi, rhoj, rho0i, rho0j, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj, eta_ave, kappa_ave,dT_prefactor; double mu, q, fp_prefactor, drho_damp, fmag, psi_ij, Fij; double *dWij, *dWji, *dW1ij, *dW1ji; double dx[3], du[3], dv[3], fv[3], dfp[3], fsolid[3], ft[3], vi[3], vj[3]; @@ -112,6 +113,7 @@ void PairRHEO::compute(int eflag, int vflag) int *type = atom->type; int *status = atom->status; tagint *tag = atom->tag; + double fnorm, ftang[3]; double **fp_store, *chi; if (compute_interface) { @@ -243,14 +245,19 @@ void PairRHEO::compute(int eflag, int vflag) // Thermal Evolution if (thermal_flag) { + if (harmonic_means_flag) { + kappa_ave = 2.0 * kappai * kappaj / (kappai + kappaj); + } else { + kappa_ave = 0.5 * (kappai * kappaj); + } + dT_prefactor = 2.0 * kappa_ave * (Ti - Tj) * rinv * rinv * voli * volj * 2.0 / (rhoi + rhoj); + dT = dot3(dx, dWij); - dT *= (kappai + kappaj) * (Ti - Tj) * rinv * rinv * voli * volj * 2.0 / (rhoi + rhoj); - heatflow[i] += dT; + heatflow[i] += dT * dT_prefactor; if (newton_pair || j < nlocal) { dT = dot3(dx, dWji); - dT *= (kappai + kappaj) * (Tj - Ti) * rinv * rinv * voli * volj * 2.0 / (rhoi + rhoj); - heatflow[j] -= dT; + heatflow[j] += dT * dT_prefactor; } } @@ -260,6 +267,12 @@ void PairRHEO::compute(int eflag, int vflag) fp_prefactor = voli * volj * (Pj + Pi); sub3(vi, vj, dv); + if (harmonic_means_flag) { + eta_ave = 2.0 * etai * etaj / (etai + etaj); + } else { + eta_ave = 0.5 * (etai * etaj); + } + //Add artificial viscous pressure if required if (artificial_visc_flag && pair_avisc_flag) { //Interpolate velocities to midpoint and use this difference for artificial viscosity @@ -283,7 +296,7 @@ void PairRHEO::compute(int eflag, int vflag) fv[a] = 0.0; for (b = 0; b < dim; b++) fv[a] += dv[a] * dx[b] * dWij[b]; - fv[a] *= (etai + etaj) * voli * volj * rinv * rinv; + fv[a] *= 2.0 * eta_ave * voli * volj * rinv * rinv; } add3(fv, dfp, ft); @@ -293,26 +306,38 @@ void PairRHEO::compute(int eflag, int vflag) f[i][1] += ft[1]; f[i][2] += ft[2]; - if (evflag) // Does not account for unbalanced forces - ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); + if (evflag) { + fnorm = dot3(ft, dx) * rinv * rinv * 0.5; + ftang[0] = ft[0] * 0.5 - dx[0] * fnorm; + ftang[1] = ft[1] * 0.5 - dx[1] * fnorm; + ftang[2] = ft[2] * 0.5 - dx[2] * fnorm; + ev_tally_nt(i, j, nlocal, newton_pair, 0.0, 0.0, fnorm, ftang[0], ftang[1], ftang[2], dx[0], dx[1], dx[2]); + } if (newton_pair || j < nlocal) { for (a = 0; a < dim; a ++) { fv[a] = 0.0; for (b = 0; b < dim; b++) fv[a] += (vi[a] - vj[a]) * dx[b] * dWji[b]; - fv[a] *= -(etai + etaj) * voli * volj * rinv * rinv; + fv[a] *= -2.0 * eta_ave * voli * volj * rinv * rinv; // flip sign here b/c -= at accummulator } scale3(fp_prefactor, dWji, dfp); - add3(fv, dfp, ft); add3(fsolid, ft, ft); f[j][0] -= ft[0]; f[j][1] -= ft[1]; f[j][2] -= ft[2]; + + if (evflag) { + fnorm = - dot3(ft, dx) * rinv * rinv * 0.5; + ftang[0] = ft[0] * 0.5 + dx[0] * fnorm; + ftang[1] = ft[1] * 0.5 + dx[1] * fnorm; + ftang[2] = ft[2] * 0.5 + dx[2] * fnorm; + ev_tally_nt(i, j, nlocal, newton_pair, 0.0, 0.0, fnorm, ftang[0], ftang[1], ftang[2], -dx[0], -dx[1], -dx[2]); + } } if (compute_interface) { @@ -360,7 +385,7 @@ void PairRHEO::compute(int eflag, int vflag) if (vflag_fdotr) virial_fdotr_compute(); if (compute_interface) { - comm->reverse_comm(this); + if (newton_pair) comm->reverse_comm(this); comm->forward_comm(this); } } @@ -404,6 +429,8 @@ void PairRHEO::settings(int narg, char **arg) artificial_visc_flag = 1; av = utils::numeric(FLERR, arg[iarg + 1], false, lmp); iarg++; + } else if (strcmp(arg[iarg], "harmonic/means") == 0) { + harmonic_means_flag = 1; } else error->all(FLERR, "Illegal pair_style command, {}", arg[iarg]); iarg++; } @@ -469,7 +496,8 @@ void PairRHEO::setup() int n = atom->ntypes; memory->create(cs, n + 1, "rheo:cs"); - for (int i = 0; i <= n; i++) cs[i] = sqrt(csq[i]); + for (int i = 1; i <= n; i++) + cs[i] = sqrt(csq[i]); if (comm->ghost_velocity == 0) error->all(FLERR, "Pair RHEO requires ghost atoms store velocity"); diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index c43d450b8b..7a47927962 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -46,6 +46,8 @@ class PairRHEO : public Pair { int thermal_flag; int interface_flag; + int harmonic_means_flag; + void allocate(); class ComputeRHEOKernel *compute_kernel; diff --git a/src/pair.cpp b/src/pair.cpp index 5d789fbb9b..56a6283afa 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -1246,6 +1246,108 @@ void Pair::ev_tally_xyz(int i, int j, int nlocal, int newton_pair, } } + +/* ---------------------------------------------------------------------- + tally eng_vdwl and virial into global or per-atom accumulators + for virial, have delx,dely,delz and fnormal and ftangential +------------------------------------------------------------------------- */ + +void Pair::ev_tally_nt(int i, int j, int nlocal, int newton_pair, + double evdwl, double ecoul, double fn, + double ftx, double fty, double ftz, + double delx, double dely, double delz) +{ + double evdwlhalf,ecoulhalf,epairhalf,v[6]; + + if (eflag_either) { + if (eflag_global) { + if (newton_pair) { + eng_vdwl += evdwl; + eng_coul += ecoul; + } else { + evdwlhalf = 0.5*evdwl; + ecoulhalf = 0.5*ecoul; + if (i < nlocal) { + eng_vdwl += evdwlhalf; + eng_coul += ecoulhalf; + } + if (j < nlocal) { + eng_vdwl += evdwlhalf; + eng_coul += ecoulhalf; + } + } + } + if (eflag_atom) { + epairhalf = 0.5 * (evdwl + ecoul); + if (newton_pair || i < nlocal) eatom[i] += epairhalf; + if (newton_pair || j < nlocal) eatom[j] += epairhalf; + } + } + + if (vflag_either) { + v[0] = delx*delx*fn; + v[1] = dely*dely*fn; + v[2] = delz*delz*fn; + v[3] = delx*dely*fn; + v[4] = delx*delz*fn; + v[5] = dely*delz*fn; + + v[0] += delx*ftx; + v[1] += dely*fty; + v[2] += delz*ftz; + v[3] += delx*fty + dely*ftx; + v[4] += delx*ftz + delz*ftx; + v[5] += dely*ftz + delz*fty; + + if (vflag_global) { + if (newton_pair) { + virial[0] += v[0]; + virial[1] += v[1]; + virial[2] += v[2]; + virial[3] += v[3]; + virial[4] += v[4]; + virial[5] += v[5]; + } else { + if (i < nlocal) { + virial[0] += 0.5*v[0]; + virial[1] += 0.5*v[1]; + virial[2] += 0.5*v[2]; + virial[3] += 0.5*v[3]; + virial[4] += 0.5*v[4]; + virial[5] += 0.5*v[5]; + } + if (j < nlocal) { + virial[0] += 0.5*v[0]; + virial[1] += 0.5*v[1]; + virial[2] += 0.5*v[2]; + virial[3] += 0.5*v[3]; + virial[4] += 0.5*v[4]; + virial[5] += 0.5*v[5]; + } + } + } + + if (vflag_atom) { + if (newton_pair || i < nlocal) { + vatom[i][0] += 0.5*v[0]; + vatom[i][1] += 0.5*v[1]; + vatom[i][2] += 0.5*v[2]; + vatom[i][3] += 0.5*v[3]; + vatom[i][4] += 0.5*v[4]; + vatom[i][5] += 0.5*v[5]; + } + if (newton_pair || j < nlocal) { + vatom[j][0] += 0.5*v[0]; + vatom[j][1] += 0.5*v[1]; + vatom[j][2] += 0.5*v[2]; + vatom[j][3] += 0.5*v[3]; + vatom[j][4] += 0.5*v[4]; + vatom[j][5] += 0.5*v[5]; + } + } + } +} + /* ---------------------------------------------------------------------- tally eng_vdwl and virial into global or per-atom accumulators for virial, have delx,dely,delz and fx,fy,fz diff --git a/src/pair.h b/src/pair.h index 885a2c45ff..6533c7b124 100644 --- a/src/pair.h +++ b/src/pair.h @@ -295,6 +295,8 @@ class Pair : protected Pointers { void ev_tally_tip4p(int, int *, double *, double, double); void ev_tally_xyz(int, int, int, int, double, double, double, double, double, double, double, double); + void ev_tally_nt(int, int, int, int, double, double, double, double, double, double, double, + double, double); void v_tally2(int, int, double, double *); void v_tally_tensor(int, int, int, int, double, double, double, double, double, double); void virial_fdotr_compute(); From f7aeecd3be03f98182d91d0a8ed50b94a6e9a46e Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 1 Dec 2023 09:58:40 -0700 Subject: [PATCH 062/385] Fixing error in averaging --- src/RHEO/pair_rheo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 339efed866..4ef0066e93 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -248,7 +248,7 @@ void PairRHEO::compute(int eflag, int vflag) if (harmonic_means_flag) { kappa_ave = 2.0 * kappai * kappaj / (kappai + kappaj); } else { - kappa_ave = 0.5 * (kappai * kappaj); + kappa_ave = 0.5 * (kappai + kappaj); } dT_prefactor = 2.0 * kappa_ave * (Ti - Tj) * rinv * rinv * voli * volj * 2.0 / (rhoi + rhoj); @@ -270,7 +270,7 @@ void PairRHEO::compute(int eflag, int vflag) if (harmonic_means_flag) { eta_ave = 2.0 * etai * etaj / (etai + etaj); } else { - eta_ave = 0.5 * (etai * etaj); + eta_ave = 0.5 * (etai + etaj); } //Add artificial viscous pressure if required From 7403426046c013a1f5c5b17fd4a50bcf59e2714e Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 19 Dec 2023 13:58:22 -0700 Subject: [PATCH 063/385] Argument error in fix rheo --- src/RHEO/fix_rheo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index f0f380f23a..0c74b2bad1 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -100,7 +100,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : thermal_flag = 1; } else if (strcmp(arg[iarg], "surface/detection") == 0) { surface_flag = 1; - if(iarg + 2 >= narg) error->all(FLERR, "Illegal surface/detection option in fix rheo"); + if(iarg + 3 >= narg) error->all(FLERR, "Illegal surface/detection option in fix rheo"); if (strcmp(arg[iarg + 1], "coordination") == 0) { surface_style = COORDINATION; zmin_surface = utils::inumeric(FLERR, arg[iarg + 2], false, lmp); From 08d2dd26991dce65f9beee61039952bd3f81ca37 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 22 Dec 2023 10:46:44 -0700 Subject: [PATCH 064/385] Prototyping latent heat, other misc fixes --- src/.gitignore | 35 +-- src/RHEO/atom_vec_rheo_thermal.cpp | 46 ++-- src/RHEO/atom_vec_rheo_thermal.h | 2 +- src/RHEO/compute_rheo_grad.cpp | 69 +++-- src/RHEO/compute_rheo_grad.h | 4 +- src/RHEO/compute_rheo_kernel.cpp | 15 +- src/RHEO/compute_rheo_kernel.h | 1 + src/RHEO/compute_rheo_property_atom.cpp | 8 + src/RHEO/compute_rheo_vshift.cpp | 4 + src/RHEO/fix_rheo.cpp | 3 +- src/RHEO/fix_rheo_thermal.cpp | 139 ++++++++-- src/RHEO/fix_rheo_thermal.h | 6 +- src/RHEO/pair_rheo.cpp | 1 - src/RHEO/pair_rheo_solid.cpp | 351 ++++++++++++++++++++++++ src/RHEO/pair_rheo_solid.h | 51 ++++ src/set.cpp | 2 +- 16 files changed, 611 insertions(+), 126 deletions(-) create mode 100644 src/RHEO/pair_rheo_solid.cpp create mode 100644 src/RHEO/pair_rheo_solid.h diff --git a/src/.gitignore b/src/.gitignore index 1e634782dc..ccf8072922 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -197,40 +197,7 @@ /pair_tdpd.cpp /pair_tdpd.h -/atom_vec_rheo.cpp -/atom_vec_rheo.h -/atom_vec_rheo_thermal.cpp -/atom_vec_rheo_thermal.h -/compute_rheo_grad.cpp -/compute_rheo_grad.h -/compute_rheo_interface.cpp -/compute_rheo_interface.h -/compute_rheo_kernel.cpp -/compute_rheo_kernel.h -/compute_rheo_property_atom.cpp -/compute_rheo_property_atom.h -/compute_rheo_rho_sum.cpp -/compute_rheo_rho_sum.h -/compute_rheo_surface.cpp -/compute_rheo_surface.h -/compute_rheo_vshift.cpp -/compute_rheo_vshift.h -/fix_rheo.cpp -/fix_rheo.h -/fix_rheo_pressure.cpp -/fix_rheo_pressure.h -/fix_rheo_stress.cpp -/fix_rheo_stress.h -/fix_rheo_tension.cpp -/fix_rheo_tension.h -/fix_rheo_thermal.cpp -/fix_rheo_thermal.h -/fix_rheo_viscosity.cpp -/fix_rheo_viscosity.h -/pair_rheo.cpp -/pair_rheo.h -/pair_rheo_react.cpp -/pair_rheo_react.h +/*rheo* /compute_grid.cpp /compute_grid.h diff --git a/src/RHEO/atom_vec_rheo_thermal.cpp b/src/RHEO/atom_vec_rheo_thermal.cpp index de0c7fa5d7..4ecb7136a8 100644 --- a/src/RHEO/atom_vec_rheo_thermal.cpp +++ b/src/RHEO/atom_vec_rheo_thermal.cpp @@ -35,6 +35,7 @@ AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) atom->status_flag = 1; atom->conductivity_flag = 1; atom->temperature_flag = 1; + atom->esph_flag = 1; atom->heatflow_flag = 1; atom->pressure_flag = 1; atom->rho_flag = 1; @@ -45,17 +46,17 @@ AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) // order of fields in a string does not matter // except: fields_data_atom & fields_data_vel must match data file - fields_grow = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_copy = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_comm = {"status", "rho", "temperature"}; - fields_comm_vel = {"status", "rho", "temperature"}; + fields_grow = {"status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_copy = {"status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_comm = {"status", "rho", "esph"}; + fields_comm_vel = {"status", "rho", "esph"}; fields_reverse = {"drho", "heatflow"}; - fields_border = {"status", "rho", "temperature"}; - fields_border_vel = {"status", "rho", "temperature"}; - fields_exchange = {"status", "rho", "temperature"}; - fields_restart = {"status", "rho", "temperature"}; - fields_create = {"status", "rho", "drho", "temperature", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_data_atom = {"id", "type", "status", "rho", "temperature", "x"}; + fields_border = {"status", "rho", "esph"}; + fields_border_vel = {"status", "rho", "esph"}; + fields_exchange = {"status", "rho", "esph"}; + fields_restart = {"status", "rho", "esph"}; + fields_create = {"status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_data_atom = {"id", "type", "status", "rho", "esph", "x"}; fields_data_vel = {"id", "v"}; setup_fields(); @@ -71,6 +72,7 @@ void AtomVecRHEOThermal::grow_pointers() status = atom->status; conductivity = atom->conductivity; temperature = atom->temperature; + esph = atom->esph; heatflow = atom->heatflow; pressure = atom->pressure; rho = atom->rho; @@ -98,6 +100,7 @@ void AtomVecRHEOThermal::data_atom_post(int ilocal) { drho[ilocal] = 0.0; heatflow[ilocal] = 0.0; + temperature[ilocal] = 0.0; pressure[ilocal] = 0.0; viscosity[ilocal] = 0.0; conductivity[ilocal] = 0.0; @@ -114,10 +117,11 @@ int AtomVecRHEOThermal::property_atom(const std::string &name) if (name == "rho") return 1; if (name == "drho") return 2; if (name == "temperature") return 3; - if (name == "heatflow") return 4; - if (name == "conductivity") return 5; - if (name == "pressure") return 6; - if (name == "viscosity") return 7; + if (name == "esph") return 4; + if (name == "heatflow") return 5; + if (name == "conductivity") return 6; + if (name == "pressure") return 7; + if (name == "viscosity") return 8; return -1; } @@ -167,7 +171,7 @@ void AtomVecRHEOThermal::pack_property_atom(int index, double *buf, int nvalues, } else if (index == 4) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) - buf[n] = heatflow[i]; + buf[n] = esph[i]; else buf[n] = 0.0; n += nvalues; @@ -175,7 +179,7 @@ void AtomVecRHEOThermal::pack_property_atom(int index, double *buf, int nvalues, } else if (index == 5) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) - buf[n] = conductivity[i]; + buf[n] = heatflow[i]; else buf[n] = 0.0; n += nvalues; @@ -183,12 +187,20 @@ void AtomVecRHEOThermal::pack_property_atom(int index, double *buf, int nvalues, } else if (index == 6) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) - buf[n] = pressure[i]; + buf[n] = conductivity[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 7) { + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) + buf[n] = pressure[i]; + else + buf[n] = 0.0; + n += nvalues; + } + } else if (index == 8) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = viscosity[i]; diff --git a/src/RHEO/atom_vec_rheo_thermal.h b/src/RHEO/atom_vec_rheo_thermal.h index 27c6c3c9b5..ad467f9de7 100644 --- a/src/RHEO/atom_vec_rheo_thermal.h +++ b/src/RHEO/atom_vec_rheo_thermal.h @@ -36,7 +36,7 @@ class AtomVecRHEOThermal : virtual public AtomVec { private: int *status; - double *conductivity, *temperature, *heatflow; + double *conductivity, *temperature, *heatflow, *esph; double *pressure, *rho, *drho, *viscosity; }; diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index b2ca0c9dc4..acfc01d793 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -42,16 +42,16 @@ enum{COMMGRAD, COMMFIELD}; ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), fix_rheo(nullptr), list(nullptr), rho0(nullptr), compute_interface(nullptr), compute_kernel(nullptr), - gradv(nullptr), gradr(nullptr), gradt(nullptr), gradn(nullptr) + gradv(nullptr), gradr(nullptr), grade(nullptr), gradn(nullptr) { if (narg < 4) error->all(FLERR,"Illegal compute rheo/grad command"); - velocity_flag = temperature_flag = rho_flag = eta_flag = 0; + velocity_flag = energy_flag = rho_flag = eta_flag = 0; for (int iarg = 3; iarg < narg; iarg++) { - if (strcmp(arg[iarg],"velocity") == 0) velocity_flag = 1; - else if (strcmp(arg[iarg],"rho") == 0) rho_flag = 1; - else if (strcmp(arg[iarg],"temperature") == 0) temperature_flag = 1; - else if (strcmp(arg[iarg],"viscosity") == 0) eta_flag = 1; + if (strcmp(arg[iarg], "velocity") == 0) velocity_flag = 1; + else if (strcmp(arg[iarg], "rho") == 0) rho_flag = 1; + else if (strcmp(arg[iarg], "energy") == 0) energy_flag = 1; + else if (strcmp(arg[iarg], "viscosity") == 0) eta_flag = 1; else error->all(FLERR, "Illegal compute rheo/grad command, {}", arg[iarg]); } @@ -72,7 +72,7 @@ ComputeRHEOGrad::ComputeRHEOGrad(LAMMPS *lmp, int narg, char **arg) : comm_reverse += dim; } - if (temperature_flag) { + if (energy_flag) { ncomm_grad += dim; ncomm_field += 1; comm_reverse += dim; @@ -96,7 +96,7 @@ ComputeRHEOGrad::~ComputeRHEOGrad() { memory->destroy(gradv); memory->destroy(gradr); - memory->destroy(gradt); + memory->destroy(grade); memory->destroy(gradn); } @@ -130,7 +130,7 @@ void ComputeRHEOGrad::compute_peratom() int i, j, k, ii, jj, jnum, itype, jtype, a, b, fluidi, fluidj; double xtmp, ytmp, ztmp, delx, dely, delz; double rsq, imass, jmass; - double rhoi, rhoj, Voli, Volj, drho, dT, deta; + double rhoi, rhoj, Voli, Volj, drho, de, deta; double vi[3], vj[3], vij[3]; double wp, *dWij, *dWji; @@ -141,7 +141,7 @@ void ComputeRHEOGrad::compute_peratom() double **x = atom->x; double **v = atom->v; double *rho = atom->rho; - double *temperature = atom->temperature; + double *energy = atom->esph; double *viscosity = atom->viscosity; int *status = atom->status; int *type = atom->type; @@ -166,9 +166,9 @@ void ComputeRHEOGrad::compute_peratom() for (k = 0; k < dim; k++) gradr[i][k] = 0.0; } - if (temperature_flag) { + if (energy_flag) { for (k = 0; k < dim; k++) - gradt[i][k] = 0.0; + grade[i][k] = 0.0; } if (eta_flag) { for (k = 0; k < dim; k++) @@ -234,7 +234,7 @@ void ComputeRHEOGrad::compute_peratom() vij[2] = vi[2] - vj[2]; if (rho_flag) drho = rhoi - rhoj; - if (temperature_flag) dT = temperature[i] - temperature[j]; + if (energy_flag) de = energy[i] - energy[j]; if (eta_flag) deta = viscosity[i] - viscosity[j]; wp = compute_kernel->calc_dw(i, j, delx, dely, delz, sqrt(rsq)); @@ -250,8 +250,8 @@ void ComputeRHEOGrad::compute_peratom() if (rho_flag) // P,x P,y P,z gradr[i][a] -= drho * Volj * dWij[a]; - if (temperature_flag) // T,x T,y T,z - gradt[i][a] -= dT * Volj * dWij[a]; + if (energy_flag) // e,x e,y e,z + grade[i][a] -= de * Volj * dWij[a]; if (eta_flag) // n,x n,y n,z gradn[i][a] -= deta * Volj * dWij[a]; @@ -267,8 +267,8 @@ void ComputeRHEOGrad::compute_peratom() if (rho_flag) // P,x P,y P,z gradr[j][a] += drho * Voli * dWji[a]; - if (temperature_flag) // T,x T,y T,z - gradt[j][a] += dT * Voli * dWji[a]; + if (energy_flag) // e,x e,y e,z + grade[j][a] += de * Voli * dWji[a]; if (eta_flag) // n,x n,y n,z gradn[j][a] += deta * Voli * dWji[a]; @@ -308,7 +308,7 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, int i,j,k,m; int *mask = atom->mask; double *rho = atom->rho; - double *temperature = atom->temperature; + double *energy = atom->esph; double **v = atom->v; int dim = domain->dimension; double *h_rate = domain->h_rate; @@ -335,9 +335,9 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, for (k = 0; k < dim; k++) buf[m++] = gradr[j][k]; - if (temperature_flag) + if (energy_flag) for (k = 0; k < dim; k++) - buf[m++] = gradt[j][k]; + buf[m++] = grade[j][k]; if (eta_flag) for (k = 0; k < dim; k++) @@ -358,8 +358,8 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, if (rho_flag) buf[m++] = rho[j]; - if (temperature_flag) - buf[m++] = temperature[j]; + if (energy_flag) + buf[m++] = energy[j]; } } return m; @@ -371,8 +371,7 @@ void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; double *rho = atom->rho; - double *temperature = atom->temperature; - double **v = atom->v; + double *energy = atom->esph; double **v = atom->v; int dim = domain->dimension; m = 0; @@ -387,9 +386,9 @@ void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) for (k = 0; k < dim; k++) gradr[i][k] = buf[m++]; - if (temperature_flag) + if (energy_flag) for (k = 0; k < dim; k++) - gradt[i][k] = buf[m++]; + grade[i][k] = buf[m++]; if (eta_flag) for (k = 0; k < dim; k++) @@ -403,8 +402,8 @@ void ComputeRHEOGrad::unpack_forward_comm(int n, int first, double *buf) if (rho_flag) rho[i] = buf[m++]; - if (temperature_flag) - temperature[i] = buf[m++]; + if (energy_flag) + energy[i] = buf[m++]; } } } @@ -427,9 +426,9 @@ int ComputeRHEOGrad::pack_reverse_comm(int n, int first, double *buf) for (k = 0; k < dim; k++) buf[m++] = gradr[i][k]; - if (temperature_flag) + if (energy_flag) for (k = 0; k < dim; k++) - buf[m++] = gradt[i][k]; + buf[m++] = grade[i][k]; if (eta_flag) for (k = 0; k < dim; k++) @@ -456,9 +455,9 @@ void ComputeRHEOGrad::unpack_reverse_comm(int n, int *list, double *buf) for (k = 0; k < dim; k++) gradr[j][k] += buf[m++]; - if (temperature_flag) + if (energy_flag) for (k = 0; k < dim; k++) - gradt[j][k] += buf[m++]; + grade[j][k] += buf[m++]; if (eta_flag) for (k = 0; k < dim; k++) @@ -477,8 +476,8 @@ void ComputeRHEOGrad::grow_arrays(int nmax) if (rho_flag) memory->grow(gradr, nmax, dim, "rheo:grad_rho"); - if (temperature_flag) - memory->grow(gradt, nmax, dim, "rheo:grad_temp"); + if (energy_flag) + memory->grow(grade, nmax, dim, "rheo:grad_energy"); if (eta_flag) memory->grow(gradn, nmax, dim, "rheo:grad_eta"); @@ -498,7 +497,7 @@ double ComputeRHEOGrad::memory_usage() if (rho_flag) bytes = (size_t) nmax_store * dim * sizeof(double); - if (temperature_flag) + if (energy_flag) bytes = (size_t) nmax_store * dim * sizeof(double); if (eta_flag) diff --git a/src/RHEO/compute_rheo_grad.h b/src/RHEO/compute_rheo_grad.h index 489f3c641d..2d663a5b07 100644 --- a/src/RHEO/compute_rheo_grad.h +++ b/src/RHEO/compute_rheo_grad.h @@ -40,7 +40,7 @@ class ComputeRHEOGrad : public Compute { void forward_fields(); double **gradv; double **gradr; - double **gradt; + double **grade; double **gradn; class FixRHEO *fix_rheo; @@ -48,7 +48,7 @@ class ComputeRHEOGrad : public Compute { int comm_stage, ncomm_grad, ncomm_field, nmax_store; double cut, cutsq, *rho0; - int velocity_flag, temperature_flag, rho_flag, eta_flag; + int velocity_flag, energy_flag, rho_flag, eta_flag; int interface_flag, remap_v_flag; class ComputeRHEOKernel *compute_kernel; diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 52380a4337..6f58d79243 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -86,6 +86,8 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : } comm_forward_save = comm_forward; + corrections_calculated = 0; + gsl_error_flag = 0; } /* ---------------------------------------------------------------------- */ @@ -152,6 +154,10 @@ int ComputeRHEOKernel::check_corrections(int i) if (coordination[i] < zmin) return 0; + // Skip if corrections not yet calculated + if (!corrections_calculated) + return 0; + return 1; } @@ -479,6 +485,7 @@ void ComputeRHEOKernel::compute_peratom() gsl_error_tags.clear(); if (kernel_style == QUINTIC) return; + corrections_calculated = 1; int i, j, ii, jj, inum, jnum, itype, g, a, b, gsl_error; double xtmp, ytmp, ztmp, r, rsq, w, vj, rhoj; @@ -530,11 +537,11 @@ void ComputeRHEOKernel::compute_peratom() if (rsq < hsq) { r = sqrt(rsq); - w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); + w = calc_w_quintic(i, j, dx[0], dx[1], dx[2], r); rhoj = rho[j]; if (interface_flag) if (status[j] & PHASECHECK) - rhoj = compute_interface->correct_rho(j,i); + rhoj = compute_interface->correct_rho(j, i); vj = mass[type[j]] / rhoj; M += w * vj; @@ -578,12 +585,12 @@ void ComputeRHEOKernel::compute_peratom() if (rsq < hsq) { r = sqrt(rsq); - w = calc_w_quintic(i,j,dx[0],dx[1],dx[2],r); + w = calc_w_quintic(i, j, dx[0], dx[1], dx[2], r); rhoj = rho[j]; if (interface_flag) if (status[j] & PHASECHECK) - rhoj = compute_interface->correct_rho(j,i); + rhoj = compute_interface->correct_rho(j, i); vj = mass[type[j]] / rhoj; diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 2c9f4768e1..ed190c19ce 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -53,6 +53,7 @@ class ComputeRHEOKernel : public Compute { int gsl_error_flag; std::unordered_set gsl_error_tags; + int corrections_calculated; int kernel_style, zmin, dim, Mdim, ncor; int nmax_store; double h, hsq, hinv, hsqinv, pre_w, pre_wp; diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index e450eaaf0b..380ff398d8 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -104,6 +104,14 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a } else if (utils::strmatch(arg[iarg], "^grad/v")) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_gradv; col_index[i] = get_tensor_index(arg[iarg]); + } else if (strcmp(arg[iarg], "energy") == 0) { + avec_index[i] = atom->avec->property_atom("esph"); + if (avec_index[i] < 0) + error->all(FLERR, + "Invalid keyword {} for atom style {} in compute rheo/property/atom command ", + arg[iarg], atom->get_style()); + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; + thermal_flag = 1; } else { avec_index[i] = atom->avec->property_atom(arg[iarg]); if (avec_index[i] < 0) diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 1f9314e99b..569c8569f7 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -32,6 +32,8 @@ #include "neigh_list.h" #include "neigh_request.h" +#include "update.h" + using namespace LAMMPS_NS; using namespace RHEO_NS; @@ -195,6 +197,7 @@ void ComputeRHEOVShift::compute_peratom() if (mask[i] & groupbit) { vmag = sqrt(vi[0] * vi[0] + vi[1] * vi[1] + vi[2] * vi[2]); prefactor = vmag * volj * dr; + vshift[i][0] += prefactor * dx[0]; vshift[i][1] += prefactor * dx[1]; vshift[i][2] += prefactor * dx[2]; @@ -204,6 +207,7 @@ void ComputeRHEOVShift::compute_peratom() if (mask[j] & groupbit) { vmag = sqrt(vj[0] * vj[0] + vj[1] * vj[1] + vj[2] * vj[2]); prefactor = vmag * voli * dr; + vshift[j][0] -= prefactor * dx[0]; vshift[j][1] -= prefactor * dx[1]; vshift[j][2] -= prefactor * dx[2]; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 0c74b2bad1..beba940174 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -164,7 +164,7 @@ void FixRHEO::post_constructor() compute_kernel->fix_rheo = this; std::string cmd = "rheo_grad all RHEO/GRAD velocity rho viscosity"; - if (thermal_flag) cmd += " temperature"; + if (thermal_flag) cmd += " energy"; compute_grad = dynamic_cast(modify->add_compute(cmd)); compute_grad->fix_rheo = this; @@ -401,6 +401,7 @@ void FixRHEO::pre_force(int /*vflag*/) compute_rhosum->compute_peratom(); compute_kernel->compute_peratom(); + if (interface_flag) { // Note on first setup, have no forces for pressure to reference compute_interface->compute_peratom(); diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index e6c598418b..7b61b9821e 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -47,7 +47,8 @@ enum {NONE, CONSTANT}; FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), fix_rheo(nullptr), compute_grad(nullptr), compute_vshift(nullptr), - Tc(nullptr), kappa(nullptr), cv(nullptr), Tc_style(nullptr), kappa_style(nullptr), cv_style(nullptr), + Tc(nullptr), kappa(nullptr), cv(nullptr), L(nullptr), + Tc_style(nullptr), kappa_style(nullptr), cv_style(nullptr), L_style(nullptr), fix_update_special_bonds(nullptr) { if (narg < 4) error->all(FLERR,"Illegal fix command"); @@ -62,13 +63,22 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : int i, nlo, nhi; int n = atom->ntypes; + memory->create(Tc_style, n + 1, "rheo:Tc_style"); memory->create(kappa_style, n + 1, "rheo:kappa_style"); memory->create(cv_style, n + 1, "rheo:cv_style"); + memory->create(L_style, n + 1, "rheo:L_style"); + + memory->create(Tc, n + 1, "rheo:Tc"); + memory->create(kappa, n + 1, "rheo:kappa"); + memory->create(cv, n + 1, "rheo:cv"); + memory->create(L, n + 1, "rheo:L"); + for (i = 1; i <= n; i++) { Tc_style[i] = NONE; kappa_style[i] = NONE; cv_style[i] = NONE; + L_style[i] = NONE; } int iarg = 3; @@ -81,9 +91,9 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg + 2], "constant") == 0) { if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal conductivity constant", error); - double kappa_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + double kappa_one = utils::numeric(FLERR, arg[iarg + 3], false, lmp); if (kappa_one < 0.0) error->all(FLERR, "The conductivity must be positive"); - iarg += 1; + iarg += 2; for (i = nlo; i <= nhi; i++) { kappa_style[i] = CONSTANT; @@ -102,9 +112,9 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg + 2], "constant") == 0) { if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal specific/heat constant", error); - double cv_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + double cv_one = utils::numeric(FLERR, arg[iarg + 3], false, lmp); if (cv_one < 0.0) error->all(FLERR, "The specific heat must be positive"); - iarg += 1; + iarg += 2; for (i = nlo; i <= nhi; i++) { cv_style[i] = CONSTANT; @@ -124,8 +134,8 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg + 2], "constant") == 0) { if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal Tfreeze constant", error); - double Tc_one = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - iarg += 1; + double Tc_one = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 2; for (i = nlo; i <= nhi; i++) { Tc_style[i] = CONSTANT; @@ -136,6 +146,28 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR, "Illegal fix command, {}", arg[iarg + 2]); } + iarg += 2; + } else if (strcmp(arg[iarg], "latent/heat") == 0) { + if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal latent/heat", error); + utils::bounds(FLERR, arg[iarg + 1], 1, n, nlo, nhi, error); + + // Cv arguments + if (strcmp(arg[iarg + 2], "constant") == 0) { + if (iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal latent/heat constant", error); + + double L_one = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (L_one < 0.0) error->all(FLERR, "The latent heat must be positive"); + iarg += 2; + + for (i = nlo; i <= nhi; i++) { + L_style[i] = CONSTANT; + L[i] = L_one; + } + + } else { + error->all(FLERR,"Illegal fix command, {}", arg[iarg + 2]); + } + iarg += 2; } else if (strcmp(arg[iarg], "react") == 0) { if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal react", error); @@ -155,9 +187,11 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : for (i = 1; i <= n; i++) { if (cv_style[i] == NONE) - error->all(FLERR,"Must specify specific/heat for atom type {} in fix/rheo/thermal", i); + error->all(FLERR, "Must specify specific/heat for atom type {} in fix/rheo/thermal", i); if (kappa_style[i] == NONE) - error->all(FLERR,"Must specify conductivity for atom type {} in fix/rheo/thermal", i); + error->all(FLERR, "Must specify conductivity for atom type {} in fix/rheo/thermal", i); + if (Tc_style[i] == NONE && L_style[i] != NONE) + error->all(FLERR, "Must specify critical temperature for atom type {} to use latent heat in fix rheo/thermal", i); } } @@ -173,9 +207,11 @@ FixRHEOThermal::~FixRHEOThermal() memory->destroy(cv_style); memory->destroy(Tc_style); memory->destroy(kappa_style); + memory->destroy(L_style); memory->destroy(cv); memory->destroy(Tc); memory->destroy(kappa); + memory->destroy(L); } /* ---------------------------------------------------------------------- */ @@ -210,6 +246,8 @@ void FixRHEOThermal::init() dtf = 0.5 * update->dt * force->ftm2v; + if (atom->esph_flag != 1) + error->all(FLERR,"fix rheo/thermal command requires atom property esph"); if (atom->temperature_flag != 1) error->all(FLERR,"fix rheo/thermal command requires atom property temperature"); if (atom->heatflow_flag != 1) @@ -267,9 +305,9 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) int i, a; int *status = atom->status; - double *temperature = atom->temperature; - double **gradt = compute_grad->gradt; - double **vshift = compute_vshift->array_atom; + double *energy = atom->esph; + double **grade = compute_grad->grade; + double **vshift = compute_vshift->vshift; int nlocal = atom->nlocal; int dim = domain->dimension; @@ -279,9 +317,8 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) for (i = 0; i < nlocal; i++) { if (status[i] & STATUS_NO_SHIFT) continue; - for (a = 0; a < dim; a++) - temperature[i] += dtv * vshift[i][a] * gradt[i][a]; + energy[i] += dtv * vshift[i][a] * grade[i][a]; } } @@ -290,29 +327,34 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) void FixRHEOThermal::post_integrate() { int i, itype; - double cvi, Tci, Ti; + double cvi, Tci, Ti, Li; int *status = atom->status; + double *energy = atom->esph; double *temperature = atom->temperature; double *heatflow = atom->heatflow; - double *rho = atom->rho; int *type = atom->type; int n_melt = 0; int n_freeze = 0; - //Integrate temperature and check status + //Integrate energy and check status for (i = 0; i < atom->nlocal; i++) { if (status[i] & STATUS_NO_INTEGRATION) continue; itype = type[i]; - cvi = calc_cv(i, type[i]); - temperature[i] += dtf * heatflow[i] / cvi; + cvi = calc_cv(i, itype); + energy[i] += dtf * heatflow[i]; + temperature[i] = energy[i] / cvi; if (Tc_style[itype] != NONE) { Ti = temperature[i]; - if (Tc_style[itype] == CONSTANT) { - Tci = Tc[itype]; + Tci = calc_Tc(i, itype); + + if (L_style[itype] != NONE) { + Li = calc_L(i, itype); + if (Ti > Tci) Ti = MAX(Tci, (energy[i] - Li) / cvi); + temperature[i] = Ti; } if (Ti > Tci) { @@ -370,11 +412,39 @@ void FixRHEOThermal::post_neighbor() } /* ---------------------------------------------------------------------- + Calculate temperature In the future, update & forward evolving conductivity styles every timestep ------------------------------------------------------------------------- */ void FixRHEOThermal::pre_force(int /*vflag*/) { + int i, itype; + double cvi, Tci, Ti, Li; + + double *energy = atom->esph; + double *temperature = atom->temperature; + int *type = atom->type; + + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + // Calculate temperature + for (i = 0; i < nall; i++) { + itype = type[i]; + cvi = calc_cv(i, itype); + temperature[i] = energy[i] / cvi; + + if (Tc_style[itype] != NONE) { + Ti = temperature[i]; + Tci = calc_Tc(i, itype); + + if (L_style[itype] != NONE) { + Li = calc_L(i, itype); + if (Ti > Tci) Ti = MAX(Tci, (energy[i] - Li) / cvi); + temperature[i] = Ti; + } + } + } } /* ---------------------------------------------------------------------- */ @@ -382,17 +452,13 @@ void FixRHEOThermal::pre_force(int /*vflag*/) void FixRHEOThermal::final_integrate() { int *status = atom->status; - int *type = atom->type; - double *temperature = atom->temperature; + double *energy = atom->esph; double *heatflow = atom->heatflow; - double cvi; - //Integrate temperature and check status + //Integrate energy for (int i = 0; i < atom->nlocal; i++) { if (status[i] & STATUS_NO_INTEGRATION) continue; - - cvi = calc_cv(i, type[i]); - temperature[i] += dtf * heatflow[i] / cvi; + energy[i] += dtf * heatflow[i]; } } @@ -535,6 +601,23 @@ double FixRHEOThermal::calc_cv(int i, int itype) } } +/* ---------------------------------------------------------------------- */ + +double FixRHEOThermal::calc_Tc(int i, int itype) +{ + if (Tc_style[itype] == CONSTANT) { + return Tc[itype]; + } +} + +/* ---------------------------------------------------------------------- */ + +double FixRHEOThermal::calc_L(int i, int itype) +{ + if (L_style[itype] == CONSTANT) { + return L[itype]; + } +} /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index dc412d20b9..c4c26eef6a 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -43,12 +43,14 @@ class FixRHEOThermal : public Fix { void unpack_forward_comm(int, int, double *) override; void reset_dt() override; double calc_cv(int, int); + double calc_Tc(int, int); + double calc_L(int, int); private: - double *cv, *Tc, *kappa; + double *cv, *Tc, *kappa, *L; double dtf, dtv; double cut_kernel, cut_bond, cutsq_bond; - int *cv_style, *Tc_style, *kappa_style; + int *cv_style, *Tc_style, *kappa_style, *L_style; int btype; class NeighList *list; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 4ef0066e93..b07e914af1 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -96,7 +96,6 @@ void PairRHEO::compute(int eflag, int vflag) ev_init(eflag, vflag); double **gradv = compute_grad->gradv; - double **gradt = compute_grad->gradt; double **gradr = compute_grad->gradr; double **v = atom->v; double **x = atom->x; diff --git a/src/RHEO/pair_rheo_solid.cpp b/src/RHEO/pair_rheo_solid.cpp new file mode 100644 index 0000000000..1068e9b329 --- /dev/null +++ b/src/RHEO/pair_rheo_solid.cpp @@ -0,0 +1,351 @@ +/* ---------------------------------------------------------------------- + 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 "pair_rheo_solid.h" + +#include "atom.h" +#include "comm.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "memory.h" +#include "neigh_list.h" +#include "neighbor.h" + +#include + +using namespace LAMMPS_NS; +using namespace RHEO_NS; + +/* ---------------------------------------------------------------------- */ + +PairRHEOSolid::PairRHEOSolid(LAMMPS *_lmp) : Pair(_lmp) +{ + writedata = 1; +} + +/* ---------------------------------------------------------------------- */ + +PairRHEOSolid::~PairRHEOSolid() +{ + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + + memory->destroy(k); + memory->destroy(cut); + memory->destroy(gamma); + } +} + +/* ---------------------------------------------------------------------- */ + +void PairRHEOSolid::compute(int eflag, int vflag) +{ + int i, j, ii, jj, inum, jnum, itype, jtype; + double xtmp, ytmp, ztmp, delx, dely, delz, evdwl, fpair; + double r, rsq, rinv, factor_lj; + int *ilist, *jlist, *numneigh, **firstneigh; + double vxtmp, vytmp, vztmp, delvx, delvy, delvz, dot, smooth; + + evdwl = 0.0; + if (eflag || vflag) + ev_setup(eflag, vflag); + else + evflag = vflag_fdotr = 0; + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + int *type = atom->type; + int *status = atom->status; + int nlocal = atom->nlocal; + int newton_pair = force->newton_pair; + double *special_lj = force->special_lj; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + if (!(status[i] & STATUS_SOLID)) continue; + + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + vxtmp = v[i][0]; + vytmp = v[i][1]; + vztmp = v[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + if (!(status[j] & STATUS_SOLID)) continue; + + factor_lj = special_lj[sbmask(j)]; + + if (factor_lj == 0) continue; + + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + jtype = type[j]; + + if (rsq < cutsq[itype][jtype]) { + r = sqrt(rsq); + + rinv = 1.0 / r; + fpair = k[itype][jtype] * (cut[itype][jtype] - r); + + smooth = rsq / cutsq[itype][jtype]; + smooth *= smooth; + smooth *= smooth; + smooth = 1.0 - smooth; + delvx = vxtmp - v[j][0]; + delvy = vytmp - v[j][1]; + delvz = vztmp - v[j][2]; + dot = delx * delvx + dely * delvy + delz * delvz; + fpair -= gamma[itype][jtype] * dot * smooth * rinv; + + fpair *= factor_lj * rinv; + if (eflag) evdwl = 0.0; + + f[i][0] += delx * fpair; + f[i][1] += dely * fpair; + f[i][2] += delz * fpair; + + if (newton_pair || j < nlocal) { + f[j][0] -= delx * fpair; + f[j][1] -= dely * fpair; + f[j][2] -= delz * fpair; + } + + if (evflag) ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, fpair, delx, dely, delz); + } + } + } + + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairRHEOSolid::allocate() +{ + allocated = 1; + const int np1 = atom->ntypes + 1; + + memory->create(setflag, np1, np1, "pair:setflag"); + for (int i = 1; i < np1; i++) + for (int j = i; j < np1; j++) setflag[i][j] = 0; + + memory->create(cutsq, np1, np1, "pair:cutsq"); + + memory->create(k, np1, np1, "pair:k"); + memory->create(cut, np1, np1, "pair:cut"); + memory->create(gamma, np1, np1, "pair:gamma"); +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairRHEOSolid::settings(int narg, char ** /*arg*/) +{ + if (narg != 0) error->all(FLERR, "Illegal pair_style command"); +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairRHEOSolid::coeff(int narg, char **arg) +{ + if (narg != 5) error->all(FLERR, "Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo, ihi, jlo, jhi; + utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi, error); + utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi, error); + + double k_one = utils::numeric(FLERR, arg[2], false, lmp); + double cut_one = utils::numeric(FLERR, arg[3], false, lmp); + double gamma_one = utils::numeric(FLERR, arg[4], false, lmp); + + if (cut_one <= 0.0) error->all(FLERR, "Incorrect args for pair coefficients"); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo, i); j <= jhi; j++) { + k[i][j] = k_one; + cut[i][j] = cut_one; + gamma[i][j] = gamma_one; + + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR, "Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairRHEOSolid::init_style() +{ + if (comm->ghost_velocity == 0) + error->all(FLERR,"Pair rheo/solid requires ghost atoms store velocity"); + + if (!atom->status_flag) + error->all(FLERR,"Pair rheo/solid requires atom_style rheo"); + + neighbor->add_request(this); +} + + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairRHEOSolid::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + cut[i][j] = mix_distance(cut[i][i], cut[j][j]); + k[i][j] = mix_energy(k[i][i], k[j][j], cut[i][i], cut[j][j]); + gamma[i][j] = mix_energy(gamma[i][i], gamma[j][j], cut[i][i], cut[j][j]); + } + + cut[j][i] = cut[i][j]; + k[j][i] = k[i][j]; + gamma[j][i] = gamma[i][j]; + + return cut[i][j]; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairRHEOSolid::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i, j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j], sizeof(int), 1, fp); + if (setflag[i][j]) { + fwrite(&k[i][j], sizeof(double), 1, fp); + fwrite(&cut[i][j], sizeof(double), 1, fp); + fwrite(&gamma[i][j], sizeof(double), 1, fp); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairRHEOSolid::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i, j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) utils::sfread(FLERR, &setflag[i][j], sizeof(int), 1, fp, nullptr, error); + MPI_Bcast(&setflag[i][j], 1, MPI_INT, 0, world); + if (setflag[i][j]) { + if (me == 0) { + utils::sfread(FLERR, &k[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &cut[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &gamma[i][j], sizeof(double), 1, fp, nullptr, error); + } + MPI_Bcast(&k[i][j], 1, MPI_DOUBLE, 0, world); + MPI_Bcast(&cut[i][j], 1, MPI_DOUBLE, 0, world); + MPI_Bcast(&gamma[i][j], 1, MPI_DOUBLE, 0, world); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to data file +------------------------------------------------------------------------- */ + +void PairRHEOSolid::write_data(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) + fprintf(fp, "%d %g %g %g\n", i, k[i][i], cut[i][i], gamma[i][i]); +} + +/* ---------------------------------------------------------------------- + proc 0 writes all pairs to data file +------------------------------------------------------------------------- */ + +void PairRHEOSolid::write_data_all(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) + for (int j = i; j <= atom->ntypes; j++) + fprintf(fp, "%d %d %g %g %g\n", i, j, k[i][j], cut[i][j], gamma[i][j]); +} + +/* ---------------------------------------------------------------------- */ + +double PairRHEOSolid::single(int i, int j, int itype, int jtype, double rsq, double /*factor_coul*/, + double factor_lj, double &fforce) +{ + double fpair, r, rinv; + double delx, dely, delz, delvx, delvy, delvz, dot, smooth; + + if (rsq > cutsq[itype][jtype]) return 0.0; + + double **x = atom->x; + double **v = atom->v; + + r = sqrt(rsq); + rinv = 1.0 / r; + + fpair = k[itype][jtype] * (cut[itype][jtype] - r); + + smooth = rsq / cutsq[itype][jtype]; + smooth *= smooth; + smooth = 1.0 - smooth; + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + delvx = v[i][0] - v[j][0]; + delvy = v[i][1] - v[j][1]; + delvz = v[i][2] - v[j][2]; + dot = delx * delvx + dely * delvy + delz * delvz; + fpair -= gamma[itype][jtype] * dot * rinv * smooth; + + fpair *= factor_lj; + fforce = fpair; + + return 0.0; +} diff --git a/src/RHEO/pair_rheo_solid.h b/src/RHEO/pair_rheo_solid.h new file mode 100644 index 0000000000..66c2ac4bf1 --- /dev/null +++ b/src/RHEO/pair_rheo_solid.h @@ -0,0 +1,51 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS +// clang-format off +PairStyle(rheo/solid,PairRHEOSolid); +// clang-format on +#else + +#ifndef LMP_PAIR_RHEO_SOLID_H +#define LMP_PAIR_RHEO_SOLID_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairRHEOSolid : public Pair { + public: + PairRHEOSolid(class LAMMPS *); + ~PairRHEOSolid() override; + void compute(int, int) override; + void settings(int, char **) override; + void coeff(int, char **) override; + void init_style() override; + double init_one(int, int) override; + void write_restart(FILE *) override; + void read_restart(FILE *) override; + void write_data(FILE *) override; + void write_data_all(FILE *) override; + double single(int, int, int, int, double, double, double, double &) override; + + protected: + double **k, **cut, **gamma; + + void allocate(); +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/set.cpp b/src/set.cpp index 3e1058b048..e0d20f1dc7 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -901,7 +901,7 @@ void Set::set(int keyword) } else if (keyword == RHEO_STATUS) { - if (ivalue != 0 && ivalue !=2) + if (ivalue != 0 && ivalue != 2) error->one(FLERR,"Invalid value {} in set command for rheo/status", ivalue); atom->status[i] = ivalue; } From 3f677f798ad965e2a875f85f940ee23122e59c10 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 22 Dec 2023 17:04:56 -0700 Subject: [PATCH 065/385] Fleshing out tension model --- src/RHEO/fix_rheo_tension.cpp | 322 ++++++++++++++++++++++++++-------- src/RHEO/fix_rheo_tension.h | 11 +- 2 files changed, 258 insertions(+), 75 deletions(-) diff --git a/src/RHEO/fix_rheo_tension.cpp b/src/RHEO/fix_rheo_tension.cpp index 8b79fcebd6..8d00c8b988 100644 --- a/src/RHEO/fix_rheo_tension.cpp +++ b/src/RHEO/fix_rheo_tension.cpp @@ -13,15 +13,21 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL) ----------------------------------------------------------------------- */ +// Todo: +// add citations +// remove (or fix) pairwise forces on undercoordinated atoms +// add option for vacuum tension (Frustenau 2020?) + #include "fix_rheo_tension.h" #include "atom.h" #include "comm.h" #include "compute_rheo_kernel.h" #include "compute_rheo_interface.h" +#include "compute_rheo_vshift.h" #include "domain.h" #include "error.h" #include "fix_rheo.h" @@ -44,12 +50,14 @@ using namespace FixConst; /* ---------------------------------------------------------------------- */ FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), compute_kernel(nullptr), compute_interface(nullptr), fix_rheo(nullptr) + Fix(lmp, narg, arg), compute_kernel(nullptr), compute_interface(nullptr), compute_vshift(nullptr), fix_rheo(nullptr), rho0(nullptr) { - if (narg != 6) error->all(FLERR,"Illegal fix command"); + if (narg != 8) error->all(FLERR,"Illegal fix command"); alpha = utils::numeric(FLERR, arg[3], false, lmp); - alpha = utils::numeric(FLERR, arg[4], false, lmp); + beta = utils::numeric(FLERR, arg[4], false, lmp); wmin = utils::numeric(FLERR, arg[5], false, lmp); + cmin = utils::numeric(FLERR, arg[6], false, lmp); + vshift_strength = utils::numeric(FLERR, arg[7], false, lmp); comm_forward = 3; comm_reverse = 3; @@ -60,6 +68,10 @@ FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : // For norm, create a local array since they are unlikely to be printed int tmp1, tmp2; + index_ct = atom->find_custom("c_rheo_tension", tmp1, tmp2); + if (index_ct == -1) index_ct = atom->add_custom("c_rheo_tension", 1, 0); + ct = atom->dvector[index_ct]; + index_cgradt = atom->find_custom("cgrad_rheo_tension", tmp1, tmp2); if (index_cgradt == -1) index_cgradt = atom->add_custom("cgrad_rheo_tension", 1, 3); cgradt = atom->darray[index_cgradt]; @@ -72,12 +84,15 @@ FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : if (index_divnt == -1) index_divnt = atom->add_custom("divn_rheo_tension", 1, 0); divnt = atom->dvector[index_divnt]; + index_wsame = atom->find_custom("wsame_rheo_tension", tmp1, tmp2); + if (index_wsame == -1) index_wsame = atom->add_custom("wsame_rheo_tension", 1, 0); + wsame = atom->dvector[index_wsame]; + index_ft = atom->find_custom("f_rheo_tension", tmp1, tmp2); if (index_ft == -1) index_ft = atom->add_custom("f_rheo_tension", 1, 3); ft = atom->darray[index_ft]; norm = nullptr; - wsame = nullptr; nmax_store = 0; } @@ -88,6 +103,9 @@ FixRHEOTension::~FixRHEOTension() // Remove custom property if it exists int tmp1, tmp2, index; + index = atom->find_custom("c_rheo_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 0); + index = atom->find_custom("cgrad_rheo_tension", tmp1, tmp2); if (index != -1) atom->remove_custom(index, 1, 3); @@ -97,11 +115,13 @@ FixRHEOTension::~FixRHEOTension() index = atom->find_custom("divn_rheo_tension", tmp1, tmp2); if (index != -1) atom->remove_custom(index, 1, 0); + index = atom->find_custom("wsame_rheo_tension", tmp1, tmp2); + if (index != -1) atom->remove_custom(index, 1, 0); + index = atom->find_custom("f_rheo_tension", tmp1, tmp2); if (index != -1) atom->remove_custom(index, 1, 3); memory->destroy(norm); - memory->destroy(wsame); } /* ---------------------------------------------------------------------- */ @@ -109,7 +129,7 @@ FixRHEOTension::~FixRHEOTension() int FixRHEOTension::setmask() { int mask = 0; - mask |= POST_FORCE; + mask |= PRE_FORCE; return mask; } @@ -123,7 +143,9 @@ void FixRHEOTension::init() compute_kernel = fix_rheo->compute_kernel; compute_interface = fix_rheo->compute_interface; + compute_vshift = fix_rheo->compute_vshift; interface_flag = fix_rheo->interface_flag; + shift_flag = fix_rheo->shift_flag; h = fix_rheo->h; rho0 = fix_rheo->rho0; @@ -144,19 +166,29 @@ void FixRHEOTension::init_list(int /*id*/, NeighList *ptr) void FixRHEOTension::setup(int vflag) { - // Grow and populate arrays - post_force(vflag); + // Grow and populate arrays for dump files + if (nmax_store <= atom->nmax) + grow_arrays(atom->nmax); + + size_t nbytes = nmax_store * sizeof(double); + memset(&ct[0], 0, nbytes); + memset(&norm[0], 0, nbytes); + memset(&wsame[0], 0, nbytes); + memset(&divnt[0], 0, nbytes); + memset(&cgradt[0][0], 0, 3 * nbytes); + memset(&ft[0][0], 0, 3 * nbytes); + memset(&nt[0][0], 0, 3 * nbytes); } /* ---------------------------------------------------------------------- Calculate and apply tension forces ------------------------------------------------------------------------- */ -void FixRHEOTension::post_force(int vflag) +void FixRHEOTension::pre_force(int vflag) { int i, j, a, ii, jj, inum, jnum, itype, jtype; int fluidi, fluidj; - double xtmp, ytmp, ztmp, w, wp, c; + double xtmp, ytmp, ztmp, w, wp, ctmp; double rhoi, rhoj, Voli, Volj; double *dWij, *dWji; double dx[3]; @@ -187,10 +219,73 @@ void FixRHEOTension::post_force(int vflag) grow_arrays(atom->nmax); size_t nbytes = nmax_store * sizeof(double); + memset(&ct[0], 0, nbytes); memset(&norm[0], 0, nbytes); memset(&wsame[0], 0, nbytes); memset(&divnt[0], 0, nbytes); memset(&cgradt[0][0], 0, 3 * nbytes); + memset(&ft[0][0], 0, 3 * nbytes); + + // Calculate color gradient + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + fluidi = !(status[i] & PHASECHECK); + jlist = firstneigh[i]; + jnum = numneigh[i]; + imass = mass[itype]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + + rsq = lensq3(dx); + + if (rsq > hsq) continue; + + fluidj = !(status[j] & PHASECHECK); + jtype = type[j]; + r = sqrt(rsq); + + rhoi = rho[i]; + rhoj = rho[j]; + + // Add corrections for walls + if (interface_flag) { + if (fluidi && (!fluidj)) { + rhoj = compute_interface->correct_rho(j, i); + } else if ((!fluidi) && fluidj) { + rhoi = compute_interface->correct_rho(i, j); + } else if ((!fluidi) && (!fluidj)) { + rhoi = rho0[itype]; + rhoj = rho0[jtype]; + } + } + + Voli = mass[itype] / rhoi; + Volj = mass[jtype] / rhoj; + + w = compute_kernel->calc_w(i, j, dx[0], dx[1], dx[2], r); + + if (itype != jtype) ctmp = 1; + else ctmp = 0; + + ct[i] += ctmp * Volj * w; + if (newton || j < nlocal) + ct[j] += ctmp * Voli * w; + } + } + + comm_stage = 0; + comm_reverse = 1; + if (newton) comm->reverse_comm(this); // Calculate color gradient for (ii = 0; ii < inum; ii++) { @@ -218,7 +313,6 @@ void FixRHEOTension::post_force(int vflag) fluidj = !(status[j] & PHASECHECK); jtype = type[j]; r = sqrt(rsq); - rinv = 1 / r; rhoi = rho[i]; rhoj = rho[j]; @@ -230,45 +324,50 @@ void FixRHEOTension::post_force(int vflag) } else if ((!fluidi) && fluidj) { rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0; - rhoj = rho0; + rhoi = rho0[itype]; + rhoj = rho0[jtype]; } } Voli = mass[itype] / rhoi; Volj = mass[jtype] / rhoj; - wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2],r); + wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2], r); dWij = compute_kernel->dWij; dWji = compute_kernel->dWji; - c = 0; - if (itype != jtype) c += rhoi; - c /= (rhoi + rhoj); + //c = 0; + //if (itype != jtype) c += rhoi; + //c /= (rhoi + rhoj); - for (a = 0; a < 3; a++) { - cgradt[i][a] -= c * Volj * dWij[a]; + if (itype != jtype) ctmp = 1; + else ctmp = 0; + + for (a = 0; a < dim; a++) { + cgradt[i][a] -= ctmp * Volj * dWij[a]; if (newton || j < nlocal) - cgradt[j][a] -= c * Voli * dWji[a]; + cgradt[j][a] -= ctmp * Voli * dWji[a]; } } } - comm_stage = 0; + comm_stage = 1; comm_reverse = 3; if (newton) comm->reverse_comm(this); // Calculate normal direction double minv; for (i = 0; i < nlocal; i++) { - minv = sqrt(cgradt[i][0] * cgradt[i][0] + cgradt[i][1] * cgradt[i][1] + cgradt[i][2] * cgradt[i][2]); - + minv = cgradt[i][0] * cgradt[i][0] + cgradt[i][1] * cgradt[i][1]; + if (dim == 3) minv += cgradt[i][2] * cgradt[i][2]; + minv = sqrt(minv); if (minv != 0) minv = 1 / minv; - for (a = 0; a < 3; a++) + for (a = 0; a < dim; a++) nt[i][a] = cgradt[i][a] * minv; } + comm_forward = 3; comm->forward_comm(this); // Calculate divergence @@ -309,33 +408,33 @@ void FixRHEOTension::post_force(int vflag) } else if ((!fluidi) && fluidj) { rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0; - rhoj = rho0; + rhoi = rho0[itype]; + rhoj = rho0[jtype]; } } Voli = mass[itype] / rhoi; Volj = mass[jtype] / rhoj; - w = compute_kernel->calc_w(i, j, dx[0], dx[1], dx[2],r); - wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2],r); + w = compute_kernel->calc_w(i, j, dx[0], dx[1], dx[2], r); + wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2], r); dWij = compute_kernel->dWij; dWji = compute_kernel->dWji; - for (a = 0; a < 3; a++) { - if (itype != jtype) - divnt[i] -= (nt[i][a]+nt[j][a]) * Volj * dWij[a]; - else { - divnt[i] -= (nt[i][a]-nt[j][a]) * Volj * dWij[a]; - wsame[i] += w; + for (a = 0; a < dim; a++) { + if (itype != jtype) { + divnt[i] -= (nt[i][a] + nt[j][a]) * Volj * dWij[a]; + } else { + divnt[i] -= (nt[i][a] - nt[j][a]) * Volj * dWij[a]; + wsame[i] += w * r; } norm[i] -= dx[a] * Volj * dWij[a]; if (newton || j < nlocal) { - if (itype != jtype) - divnt[j] -= (nt[j][a]+nt[i][a]) * Voli * dWji[a]; - else { - divnt[j] -= (nt[j][a]-nt[i][a]) * Voli * dWji[a]; - wsame[j] += w; + if (itype != jtype) { + divnt[j] -= (nt[j][a] + nt[i][a]) * Voli * dWji[a]; + } else { + divnt[j] -= (nt[j][a] - nt[i][a]) * Voli * dWji[a]; + wsame[j] += w * r; } norm[j] += dx[a] * Voli * dWji[a]; } @@ -343,21 +442,32 @@ void FixRHEOTension::post_force(int vflag) } } - comm_stage = 1; + comm_stage = 2; comm_reverse = 3; if (newton) comm->reverse_comm(this); + comm_forward = 1; + comm->forward_comm(this); + // Skip forces if it's setup if (update->setupflag) return; - // apply force - double weight, prefactor, unwrap[3], v[6]; - double wmin_inv = 1.0 / wmin; + // apply force, remove normal vshift + + double **vshift; + if (shift_flag) + vshift = compute_vshift->vshift; + double nx, ny, nz, vx, vy, vz, dot; + double wmin_inv, weight, prefactor, unwrap[3], v[6]; + + if (wmin > 0) wmin_inv = 1.0 / wmin; + else wmin_inv = 0.0; + for (i = 0; i < nlocal; i++) { - weight = MAX(1.0, (wsame[i] - wmin) * wmin_inv); - //if (wsame[i] < wmin) continue; + if (wsame[i] < wmin) continue; + weight = MAX(1.0, wsame[i] * wmin_inv); itype = type[i]; if (norm[i] != 0) @@ -365,10 +475,38 @@ void FixRHEOTension::post_force(int vflag) else divnt[i] = 0.0; + // Tension force from Adami, Hu, Adams 2010 prefactor = -alpha * divnt[i] * weight; - for (a = 0; a < 3; a++) { + for (a = 0; a < dim; a++) { f[i][a] += prefactor * cgradt[i][a]; - ft[i][a] = prefactor * cgradt[i][a]; + ft[i][a] += prefactor * cgradt[i][a]; + } + + // remove normal shifting component for interfacial particles + // Based on Yang, Rakhsha, Hu, & Negrut 2022 + if (shift_flag && (vshift_strength != 1.0)) { + if (ct[i] > cmin) { + nx = nt[i][0]; + ny = nt[i][1]; + vx = vshift[i][0]; + vy = vshift[i][1]; + + dot = nx * vx + ny * vy; + if (dim == 3) { + nz = nt[i][2]; + vz = vshift[i][2]; + dot += nz * vz; + } + + // Allowing shifting into the bulk + //if (dot > 0.0) continue; + + vshift[i][0] -= (1.0 - vshift_strength) * nx * dot; + vshift[i][1] -= (1.0 - vshift_strength) * ny * dot; + if (dim == 3) { + vshift[i][2] -= (1.0 - vshift_strength) * nz * dot; + } + } } if (evflag) { @@ -384,11 +522,16 @@ void FixRHEOTension::post_force(int vflag) } // If there is no lower limit, apply optional pairwise forces - if (wmin == 0 || beta == 0.0) return; + // This is totally ad hoc, needs some work + // Attempts to deal with stray single particles + if (wmin <= 0 || beta == 0.0) return; + int newton_pair = force->newton_pair; double fpair, wi, wj; double cut_two_thirds = 2.0 * h / 3.0; - double h_third_squared = (h / 3.0) * (h / 3.0); + double cut_five_sixths = 5.0 * h / 6.0; + double cut_sixth_sq = (h / 6.0) * (h / 6.0); + double cut_third_sq = (h / 3.0) * (h / 3.0); for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; @@ -397,9 +540,8 @@ void FixRHEOTension::post_force(int vflag) itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; - imass = mass[itype]; - wi = MIN(1.0, (wsame[i] - wmin) * wmin_inv); + wi = MAX(MIN(1.0, (wmin - wsame[i]) * wmin_inv), 0.0); for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -414,20 +556,38 @@ void FixRHEOTension::post_force(int vflag) if (rsq > hsq) continue; - wj = MIN(1.0, (wsame[j] - wmin) * wmin_inv); r = sqrt(rsq); - rinv = 1.0 / r; + jtype = type[j]; - fpair = (r - cut_two_thirds); - fpair *= fpair; - fpair -= h_third_squared; - fpair *= wi * wj * beta * rinv; + if (itype == jtype) { + fpair = (r - cut_two_thirds); + fpair *= fpair; + fpair -= cut_third_sq; + } else { + //fpair = 0.0; + + if (r > (0.5*cut_two_thirds)) continue; + fpair = (r - cut_two_thirds); + fpair *= fpair; + fpair -= cut_third_sq; + + //if (r > cut_two_thirds) continue; + //fpair = (r - cut_five_sixths); + //fpair *= fpair; + //fpair -= cut_sixth_sq; + + //fpair = (h - r) * 0.66666666666666; + } + + wj = MAX(MIN(1.0, (wmin - wsame[j]) * wmin_inv), 0.0); + rinv = 1.0 / r; + fpair *= MAX(wi, wj) * beta * rinv; f[i][0] += dx[0] * fpair; f[i][1] += dx[1] * fpair; f[i][2] += dx[2] * fpair; - if (newton || j < nlocal) { + if (newton_pair || j < nlocal) { f[j][0] -= dx[0] * fpair; f[j][1] -= dx[1] * fpair; f[j][2] -= dx[2] * fpair; @@ -448,11 +608,18 @@ int FixRHEOTension::pack_forward_comm(int n, int *list, double *buf, int /*pbc_f int i, j, a, m; m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - for (a = 0; a < 3; a++) - buf[m++] = nt[j][a]; - } + if (comm_stage == 1) + for (i = 0; i < n; i++) { + j = list[i]; + for (a = 0; a < 3; a++) + buf[m++] = nt[j][a]; + } + else if (comm_stage == 2) + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = wsame[j]; + } + return m; } @@ -464,9 +631,13 @@ void FixRHEOTension::unpack_forward_comm(int n, int first, double *buf) m = 0; last = first + n; - for (i = first; i < last; i++) - for (a = 0; a < 3; a++) - nt[i][a] = buf[m++]; + if (comm_stage == 1) + for (i = first; i < last; i++) + for (a = 0; a < 3; a++) + nt[i][a] = buf[m++]; + else if (comm_stage == 2) + for (i = first; i < last; i++) + wsame[i] = buf[m++]; } @@ -479,10 +650,13 @@ int FixRHEOTension::pack_reverse_comm(int n, int first, double *buf) m = 0; last = first + n; if (comm_stage == 0) + for (i = first; i < last; i++) + buf[m++] = ct[i]; + else if (comm_stage == 1) for (i = first; i < last; i++) for (a = 0; a < 3; a++) buf[m++] = cgradt[i][a]; - else + else if (comm_stage == 2) for (i = first; i < last; i++) { buf[m++] = norm[i]; buf[m++] = divnt[i]; @@ -499,12 +673,17 @@ void FixRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) m = 0; if (comm_stage == 0) + for (i = 0; i < n; i++) { + j = list[i]; + ct[j] += buf[m++]; + } + else if (comm_stage == 1) for (i = 0; i < n; i++) { j = list[i]; for (a = 0; a < 3; a++) cgradt[j][a] += buf[m++]; } - else + else if (comm_stage == 2) for (i = 0; i < n; i++) { j = list[i]; norm[j] += buf[m++]; @@ -518,19 +697,22 @@ void FixRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) void FixRHEOTension::grow_arrays(int nmax) { // Grow atom variables and reassign pointers + memory->grow(atom->dvector[index_ct], nmax, "atom:rheo_ct"); memory->grow(atom->darray[index_cgradt], nmax, 3, "atom:rheo_cgradt"); memory->grow(atom->darray[index_nt], nmax, 3, "atom:rheo_nt"); memory->grow(atom->dvector[index_divnt], nmax, "atom:rheo_divnt"); + memory->grow(atom->dvector[index_wsame], nmax, "atom:rheo_wsame"); memory->grow(atom->darray[index_ft], nmax, 3, "atom:rheo_ft"); + ct = atom->dvector[index_ct]; cgradt = atom->darray[index_cgradt]; nt = atom->darray[index_nt]; divnt = atom->dvector[index_divnt]; + wsame = atom->dvector[index_wsame]; ft = atom->darray[index_ft]; // Grow local variables memory->grow(norm, nmax, "rheo/tension:norm"); - memory->grow(wsame, nmax, "rheo/tension:wsame"); nmax_store = atom->nmax; } \ No newline at end of file diff --git a/src/RHEO/fix_rheo_tension.h b/src/RHEO/fix_rheo_tension.h index f56a61e688..52d368531f 100644 --- a/src/RHEO/fix_rheo_tension.h +++ b/src/RHEO/fix_rheo_tension.h @@ -32,7 +32,7 @@ class FixRHEOTension : public Fix { void init() override; void init_list(int, class NeighList *) override; void setup(int) override; - void post_force(int) override; + void pre_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; int pack_reverse_comm(int, int, double *) override; @@ -40,14 +40,15 @@ class FixRHEOTension : public Fix { void grow_arrays(int) override; private: - int nmax_store, comm_stage, interface_flag; - int index_nt, index_cgradt, index_divnt, index_ft; + int nmax_store, comm_stage, interface_flag, shift_flag; + int index_ct, index_nt, index_cgradt, index_divnt, index_ft, index_wsame; - double **nt, **cgradt, *divnt, *norm, **ft, *wsame; - double alpha, beta, wmin, h, hsq, hinv, hinv3, rho0; + double *ct, **nt, **cgradt, *divnt, *norm, **ft, *wsame; + double alpha, beta, wmin, cmin, vshift_strength, h, hsq, hinv, hinv3, *rho0; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOInterface *compute_interface; + class ComputeRHEOVShift *compute_vshift; class FixRHEO *fix_rheo; class NeighList *list; }; From a0cf5191c28054354fd9de7613771d267568d7ca Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 12 Jan 2024 17:00:12 -0700 Subject: [PATCH 066/385] Adding nonzero starting rhos --- src/RHEO/atom_vec_rheo.cpp | 9 +++++++++ src/RHEO/atom_vec_rheo.h | 1 + src/RHEO/atom_vec_rheo_thermal.cpp | 9 +++++++++ src/RHEO/atom_vec_rheo_thermal.h | 1 + 4 files changed, 20 insertions(+) diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp index ea9e2a3c10..ec44a230ec 100644 --- a/src/RHEO/atom_vec_rheo.cpp +++ b/src/RHEO/atom_vec_rheo.cpp @@ -82,6 +82,15 @@ void AtomVecRHEO::force_clear(int n, size_t nbytes) memset(&drho[n], 0, nbytes); } +/* ---------------------------------------------------------------------- + initialize non-zero atom quantities +------------------------------------------------------------------------- */ + +void AtomVecRHEO::create_atom_post(int ilocal) +{ + rho[ilocal] = 1.0; +} + /* ---------------------------------------------------------------------- modify what AtomVec::data_atom() just unpacked or initialize other atom quantities diff --git a/src/RHEO/atom_vec_rheo.h b/src/RHEO/atom_vec_rheo.h index 68cc224ba5..62a7b1a630 100644 --- a/src/RHEO/atom_vec_rheo.h +++ b/src/RHEO/atom_vec_rheo.h @@ -30,6 +30,7 @@ class AtomVecRHEO : virtual public AtomVec { void grow_pointers() override; void force_clear(int, size_t) override; + void create_atom_post(int) override; void data_atom_post(int) override; int property_atom(const std::string &) override; void pack_property_atom(int, double *, int, int) override; diff --git a/src/RHEO/atom_vec_rheo_thermal.cpp b/src/RHEO/atom_vec_rheo_thermal.cpp index 4ecb7136a8..26394c9175 100644 --- a/src/RHEO/atom_vec_rheo_thermal.cpp +++ b/src/RHEO/atom_vec_rheo_thermal.cpp @@ -91,6 +91,15 @@ void AtomVecRHEOThermal::force_clear(int n, size_t nbytes) memset(&heatflow[n], 0, nbytes); } +/* ---------------------------------------------------------------------- + initialize non-zero atom quantities +------------------------------------------------------------------------- */ + +void AtomVecRHEOThermal::create_atom_post(int ilocal) +{ + rho[ilocal] = 1.0; +} + /* ---------------------------------------------------------------------- modify what AtomVec::data_atom() just unpacked or initialize other atom quantities diff --git a/src/RHEO/atom_vec_rheo_thermal.h b/src/RHEO/atom_vec_rheo_thermal.h index ad467f9de7..29a764bea9 100644 --- a/src/RHEO/atom_vec_rheo_thermal.h +++ b/src/RHEO/atom_vec_rheo_thermal.h @@ -30,6 +30,7 @@ class AtomVecRHEOThermal : virtual public AtomVec { void grow_pointers() override; void force_clear(int, size_t) override; + void create_atom_post(int) override; void data_atom_post(int) override; int property_atom(const std::string &) override; void pack_property_atom(int, double *, int, int) override; From 67f06097ee1d71babd2a3edd5654dcd8a3cc6108 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 15 Jan 2024 22:04:26 -0700 Subject: [PATCH 067/385] Updating utils functions for pair rheo/react --- src/RHEO/pair_rheo_react.cpp | 47 +++++++++++++++--------------------- src/RHEO/pair_rheo_react.h | 2 +- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/RHEO/pair_rheo_react.cpp b/src/RHEO/pair_rheo_react.cpp index 1d54208792..4709ea169e 100644 --- a/src/RHEO/pair_rheo_react.cpp +++ b/src/RHEO/pair_rheo_react.cpp @@ -89,7 +89,6 @@ PairRHEOReact::~PairRHEOReact() memory->destroy(cutsq); memory->destroy(cutbsq); - memory->destroy(cut); memory->destroy(cutbond); memory->destroy(k); memory->destroy(eps); @@ -301,10 +300,9 @@ void PairRHEOReact::allocate() for (int j = i; j <= n; j++) setflag[i][j] = 0; - memory->create(cut, n + 1, n + 1, "pair:cut"); memory->create(cutbond, n + 1, n + 1, "pair:cutbond"); - memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); memory->create(cutbsq, n + 1, n + 1, "pair:cutbsq"); + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); memory->create(k, n + 1, n + 1, "pair:k"); memory->create(eps, n + 1, n + 1, "pair:eps"); memory->create(gamma, n + 1, n + 1, "pair:gamma"); @@ -333,24 +331,21 @@ void PairRHEOReact::coeff(int narg, char **arg) utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); - double cut_one = utils::numeric(FLERR, arg[2], false, lmp); + double k_one = utils::numeric(FLERR, arg[2], false, lmp); double cutb_one = utils::numeric(FLERR, arg[3], false, lmp); - double k_one = utils::numeric(FLERR, arg[4], false, lmp); - double eps_one = utils::numeric(FLERR, arg[5], false, lmp); - double gamma_one = utils::numeric(FLERR, arg[6], false, lmp); - double t_form_one = utils::numeric(FLERR, arg[7], false, lmp); - double rlimit_one = utils::numeric(FLERR, arg[8], false, lmp); + double eps_one = utils::numeric(FLERR, arg[4], false, lmp); + double gamma_one = utils::numeric(FLERR, arg[5], false, lmp); + double t_form_one = utils::numeric(FLERR, arg[6], false, lmp); + double rlimit_one = utils::numeric(FLERR, arg[7], false, lmp); - if (k_one < 0.0 || eps_one < 0.0 || - t_form_one < 0.0 || (1.0 + eps_one) * cutb_one > cut_one) + if (k_one < 0.0 || eps_one < 0.0 || t_form_one < 0.0) error->all(FLERR, "Illegal pair_style command"); int count = 0; for (int i = ilo; i <= ihi; i++) { for (int j = MAX(jlo,i); j <= jhi; j++) { - cut[i][j] = cut_one; - cutbond[i][j] = cutb_one; k[i][j] = k_one; + cutbond[i][j] = cutb_one; eps[i][j] = eps_one; gamma[i][j] = gamma_one; t_form[i][j] = t_form_one; @@ -411,7 +406,6 @@ double PairRHEOReact::init_one(int i, int j) cutbsq[i][j] = cutbond[i][j] * cutbond[i][j]; cutbsq[j][i] = cutbsq[i][j]; - cut[j][i] = cut[i][j]; cutbond[j][i] = cutbond[i][j]; k[j][i] = k[i][j]; eps[j][i] = eps[i][j]; @@ -419,7 +413,9 @@ double PairRHEOReact::init_one(int i, int j) t_form[j][i] = t_form[i][j]; rlimit[j][i] = rlimit[i][j]; - return cut[i][j]; + double cut = cutbond[i][j] * (1.0 + eps[i][j]); + + return cut; } /* ---------------------------------------------------------------------- @@ -435,9 +431,8 @@ void PairRHEOReact::write_restart(FILE *fp) for (j = i; j <= atom->ntypes; j++) fwrite(&setflag[i][j], sizeof(int), 1, fp); if (setflag[i][j]) { - fwrite(&cut[i][j], sizeof(double), 1, fp); - fwrite(&cutbond[i][j], sizeof(double), 1, fp); fwrite(&k[i][j], sizeof(double), 1, fp); + fwrite(&cutbond[i][j], sizeof(double), 1, fp); fwrite(&eps[i][j], sizeof(double), 1, fp); fwrite(&gamma[i][j], sizeof(double), 1, fp); fwrite(&t_form[i][j], sizeof(double), 1, fp); @@ -458,21 +453,19 @@ void PairRHEOReact::read_restart(FILE *fp) int me = comm->me; for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { - if (me == 0) fread(&setflag[i][j], sizeof(int), 1, fp); + if (me == 0) utils::sfread(FLERR, &setflag[i][j], sizeof(int), 1, fp, nullptr, error); MPI_Bcast(&setflag[i][j], 1, MPI_INT, 0, world); if (setflag[i][j]) { if (me == 0) { - fread(&cut[i][j], sizeof(double), 1, fp); - fread(&cutbond[i][j], sizeof(double), 1, fp); - fread(&k[i][j], sizeof(double), 1, fp); - fread(&eps[i][j], sizeof(double), 1, fp); - fread(&gamma[i][j], sizeof(double), 1, fp); - fread(&t_form[i][j], sizeof(double), 1, fp); - fread(&rlimit[i][j], sizeof(double), 1, fp); + utils::sfread(FLERR, &k[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &cutbond[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &eps[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &gamma[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &t_form[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &rlimit[i][j], sizeof(double), 1, fp, nullptr, error); } - MPI_Bcast(&cut[i][j], 1,MPI_DOUBLE, 0, world); - MPI_Bcast(&cutbond[i][j], 1,MPI_DOUBLE, 0, world); MPI_Bcast(&k[i][j], 1,MPI_DOUBLE, 0, world); + MPI_Bcast(&cutbond[i][j], 1,MPI_DOUBLE, 0, world); MPI_Bcast(&eps[i][j], 1,MPI_DOUBLE, 0, world); MPI_Bcast(&gamma[i][j], 1,MPI_DOUBLE, 0, world); MPI_Bcast(&t_form[i][j], 1,MPI_DOUBLE, 0, world); diff --git a/src/RHEO/pair_rheo_react.h b/src/RHEO/pair_rheo_react.h index 144859e68b..88d5dbeb0e 100644 --- a/src/RHEO/pair_rheo_react.h +++ b/src/RHEO/pair_rheo_react.h @@ -40,7 +40,7 @@ class PairRHEOReact : public Pair { void unpack_reverse_comm(int, int *, double *) override; protected: - double **cut, **cutbond, **cutbsq, **k, **eps, **gamma, **t_form, **rlimit; + double **cutbond, **cutbsq, **k, **eps, **gamma, **t_form, **rlimit; void allocate(); void transfer_history(double*, double*); From 80861fe1ff0f6ce4e1a00acd2dd3a0b1603fae05 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 19 Jan 2024 21:24:27 -0700 Subject: [PATCH 068/385] New syntax in doc files --- doc/src/compute_rheo_property_atom.rst | 19 +++++--- doc/src/fix_rheo.rst | 3 +- doc/src/fix_rheo_pressure.rst | 9 ++-- doc/src/fix_rheo_thermal.rst | 47 ++++++++++++------ doc/src/fix_rheo_viscosity.rst | 12 ++--- doc/src/pair_rheo.rst | 9 ++-- doc/src/pair_rheo_react.rst | 67 ++++++++++++++++++++++++++ doc/src/pair_rheo_solid.rst | 58 ++++++++++++++++++++++ 8 files changed, 187 insertions(+), 37 deletions(-) create mode 100644 doc/src/pair_rheo_react.rst create mode 100644 doc/src/pair_rheo_solid.rst diff --git a/doc/src/compute_rheo_property_atom.rst b/doc/src/compute_rheo_property_atom.rst index 5476f7f709..7f5de17c3b 100644 --- a/doc/src/compute_rheo_property_atom.rst +++ b/doc/src/compute_rheo_property_atom.rst @@ -17,11 +17,13 @@ Syntax .. parsed-literal:: possible attributes = phase, chi, surface, surface/r, - surface/divr, surface/nx, surface/ny, - surface/nz, coordination, cv, shift/vx, - shift/vy, shift/vz, temperature, heatflow, - conductivity, viscosity, pressure, status, - rho + surface/divr, surface/n/x, surface/n/y, + surface/n/z, coordination, cv, shift/v/x, + shift/v/y, shift/v/z, energy, temperature, heatflow, + conductivity, cv, viscosity, pressure, + status, rho, grad/v/xx, grad/v/xy, grad/v/xz, + grad/v/yx, grad/v/yy/, grad/v/yz, grad/v/zx, + grad/v/zy, grad/v/zz .. parsed-literal:: @@ -30,16 +32,19 @@ Syntax *surface* = atom surface status *surface/r* = atom distance from the surface *surface/divr* = divergence of position at atom position - *surface/nx, surface/ny, surface/nz* = surface normal vector + *surface/n/\** = surface normal vector *coordination* = coordination number - *shift/vx, shift/vy, shift/vz* = atom shifting velocity + *shift/v/\** = atom shifting velocity + *energy* = atom energy *temperature* = atom temperature *heatflow* = atom heat flow *conductivity* = atom conductivity + *cv* = atom specific heat *viscosity* = atom viscosity *pressure* = atom pressure *status* = atom full status *rho* = atom density + *grad/v/\** = atom velocity gradient Examples """""""" diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 25e171a1b9..c61d1939db 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -14,7 +14,8 @@ Syntax * rheo = style name of this fix command * cut = *quintic* or *RK0* or *RK1* or *RK2* * zero or more keyword/value pairs may be appended to args -* keyword = *shift* or *thermal* or *surface/detection* or *interface/reconstruction* or *rho/sum* or *density* or *sound/squared* +* keyword = *shift* or *thermal* or *surface/detection* or *interface/reconstruction* or + *rho/sum* or *density* or *sound/squared* .. parsed-literal:: diff --git a/doc/src/fix_rheo_pressure.rst b/doc/src/fix_rheo_pressure.rst index ceb402501a..d31c305c20 100644 --- a/doc/src/fix_rheo_pressure.rst +++ b/doc/src/fix_rheo_pressure.rst @@ -8,11 +8,12 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo/pressure pstyle args + fix ID group-ID rheo/pressure style args * ID, group-ID are documented in :doc:`fix ` command * rheo/pressure = style name of this fix command -* pstyle = *linear* or *taitwater* or *cubic* +* types = lists of types (see below) +* style = *linear* or *taitwater* or *cubic* .. parsed-literal:: @@ -25,8 +26,8 @@ Examples .. code-block:: LAMMPS - fix 1 all rheo/pressure linear - fix 1 all rheo/pressure cubic 10.0 + fix 1 all rheo/pressure * linear + fix 1 all rheo/pressure 1 linear 2 cubic 10.0 Description """"""""""" diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index 01b4820a39..b73aeb248e 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -8,42 +8,59 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo/thermal keyword values ... + fix ID group-ID rheo/thermal attribute values ... * ID, group-ID are documented in :doc:`fix ` command -* rheo/viscosity = style name of this fix command +* rheo/thermal = style name of this fix command * one or more attributes may be appended -* attribute = *conductivity* or *specific/heat* or *Tfreeze* +* attribute = *conductivity* or *specific/heat* or *latent/heat* or *Tfreeze* or *react* .. parsed-literal:: - *conductivity* args = style param - style = *constant* or *type* + *conductivity* args = types style args + types = lists of types (see below) + style = *constant* *constant* arg = conductivity (power/temperature) - *type* args = list of conductivity values, one per type (power/temperature) - *specific/heat* args = style param - style = *constant* or *type* + *specific/heat* args = types style args + types = lists of types (see below) + style = *constant* *constant* arg = specific heat (energy/(mass*temperature)) - *type* args = list of specific heat values, one per atom type (energy/(mass*temperature)) - *Tfreeze* args = style param - style = *constant* or *type* + *latent/heat* args = types style args + types = lists of types (see below) + style = *constant* + *constant* arg = latent heat (energy/mass) + *Tfreeze* args = types style args + types = lists of types (see below) + style = *constant* *constant* arg = freezing temperature (temperature) - *type* args = list of freezing temperature values, one per type (temperature) + *react* args = cut type + cut = maximum bond distance + type = bond type Examples """""""" .. code-block:: LAMMPS - fix 1 all rheo/thermal conductivity constant 1.0 specific/heat constant 1.0 Tfreeze constant 1.0 - fix 1 all rheo/pressure conductivity constant 1.0 specific/heat type 1.0 2.0 + fix 1 all rheo/thermal conductivity * constant 1.0 specific/heat * constant 1.0 Tfreeze * constant 1.0 + fix 1 all rheo/pressure conductivity 1*2 constant 1.0 conductivity 3*4 constant 2.0 specific/heat * constant 1.0 Description """"""""""" This fix... -While the *Tfreeze* keyword is optional, the *conducitivity* and +Each list consists of a series of type +ranges separated by commas. The range can be specified as a +single numeric value, or a wildcard asterisk can be used to specify a range +of values. This takes the form "\*" or "\*n" or "n\*" or "m\*n". For +example, if M = the number of atom types, then an asterisk with no numeric +values means all types from 1 to M. A leading asterisk means all types +from 1 to n (inclusive). A trailing asterisk means all types from n to M +(inclusive). A middle asterisk means all types from m to n (inclusive). +Note that all atom types must be included in exactly one of the N collections. + +While the *Tfreeze* keyword is optional, the *conductivity* and *specific/heat* keywords are mandatory. Multiple instances of this fix may be defined to apply different diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst index 278c621216..379b002de1 100644 --- a/doc/src/fix_rheo_viscosity.rst +++ b/doc/src/fix_rheo_viscosity.rst @@ -8,16 +8,16 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo/viscosity vstyle args + fix ID group-ID rheo/viscosity types style args ... * ID, group-ID are documented in :doc:`fix ` command * rheo/viscosity = style name of this fix command -* vstyle = *constant* or *type* or *power* +* types = lists of types (see below) +* style = *constant* or *power* .. parsed-literal:: - *constant* arg = viscosity (mass/(length*time)) - *type* args = list of viscosity values, one per atom type (mass/(length*time)) + *constant* args = viscosity (mass/(length*time)) *power* args = *eta* *gd0* *K* *npow* *tau0* *eta* = (units) *gd0* = (units) @@ -30,8 +30,8 @@ Examples .. code-block:: LAMMPS - fix 1 all rheo/viscosity constant 1.0 - fix 1 all rheo/viscosity power 0.1 1e-2 0.5 0.01 + fix 1 all rheo/viscosity * constant 1.0 + fix 1 all rheo/viscosity 1 constant 1.0 2 power 0.1 1e-2 0.5 0.01 Description """"""""""" diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst index d168f79785..6f706a77ac 100644 --- a/doc/src/pair_rheo.rst +++ b/doc/src/pair_rheo.rst @@ -8,16 +8,17 @@ Syntax .. code-block:: LAMMPS - pair_style rheo cut keyword values + pair_style rheo cutoff keyword values -* cut = *quintic* or *CRK0* or *CRK1* or *CRK2* +* cutoff = global cutoff for kernel (distance units) * zero or more keyword/value pairs may be appended to args -* keyword = *rho/damp* or *artificial/visc* +* keyword = *rho/damp* or *artificial/visc* or *harmonic/means* .. parsed-literal:: *rho/damp* args = density damping prefactor :math:`\xi` (units?) *artificial/visc* args = artificial viscosity prefactor :math:`\zeta` (units?) + *harmonic/means* args = none Examples """""""" @@ -67,4 +68,4 @@ Related commands Default """"""" -No density damping or artificial viscous forces are calculated. +Density damping and artificial viscous forces are not calculated. Arithmetic means are used for mixing particle properties. diff --git a/doc/src/pair_rheo_react.rst b/doc/src/pair_rheo_react.rst new file mode 100644 index 0000000000..6e7eb49c9d --- /dev/null +++ b/doc/src/pair_rheo_react.rst @@ -0,0 +1,67 @@ +.. index:: pair_style rheo/react + +pair_style rheo/react command +========================= + +Syntax +"""""" + +.. code-block:: LAMMPS + + pair_style rheo/react + +Examples +"""""""" + +.. code-block:: LAMMPS + + pair_style rheo/react + pair_coeff * * 1.0 1.5 1.0 0.05 1.0 100 2.0 + +Description +""""""""""" + +pair style... + +The following coefficients must be defined for each pair of atom types +via the :doc:`pair_coeff ` command as in the example above, +or in the data file or restart files read by the +:doc:`read_data ` or :doc:`read_restart ` +commands, or by mixing as described below: + +* :math:`k` (force/distance units) +* :math:`r_max` (distance units) +* :math:`\epsilon` (unitless) +* :math:`\gamma` (force/velocity units) +* :math:`t_form` (time units) +* :math:`r_from_surface` (distance units) + +---------- + +Mixing, shift, table, tail correction, restart, rRESPA info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +This style does not support the :doc:`pair_modify ` +shift, table, and tail options. + +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. + +This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, *middle*, *outer* keywords. + +Restrictions +"""""""""""" + +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`fix rheo `, +:doc:`compute rheo/property/atom ` + +Default +""""""" + +none diff --git a/doc/src/pair_rheo_solid.rst b/doc/src/pair_rheo_solid.rst new file mode 100644 index 0000000000..b6ff6d809d --- /dev/null +++ b/doc/src/pair_rheo_solid.rst @@ -0,0 +1,58 @@ +.. index:: pair_style rheo/solid + +pair_style rheo/solid command +========================= + +Syntax +"""""" + +.. code-block:: LAMMPS + + pair_style rheo/solid + +Examples +"""""""" + +.. code-block:: LAMMPS + + pair_style rheo/solid + pair_coeff * * 1.0 1.5 1.0 + +Description +""""""""""" + +pair style... + +* :math:`k` (force/distance units) +* :math:`\sigma` (distance units) +* :math:`\gamma` (force/velocity units) + +---------- + +Mixing, shift, table, tail correction, restart, rRESPA info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +This style does not support the :doc:`pair_modify ` +shift, table, and tail options. + +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. + +This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, *middle*, *outer* keywords. + +Restrictions +"""""""""""" + +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`fix rheo `, +:doc:`pair bpm/spring `, + +Default +""""""" + +none From 574ccc64ebb03a3a13b648a05b8f3e637b0eb7e9 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 23 Jan 2024 14:04:10 -0700 Subject: [PATCH 069/385] Fixing bugs for solid particles --- src/RHEO/pair_rheo_solid.cpp | 6 ++---- src/set.cpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/RHEO/pair_rheo_solid.cpp b/src/RHEO/pair_rheo_solid.cpp index 1068e9b329..d0a68d5230 100644 --- a/src/RHEO/pair_rheo_solid.cpp +++ b/src/RHEO/pair_rheo_solid.cpp @@ -96,14 +96,12 @@ void PairRHEOSolid::compute(int eflag, int vflag) for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - if (!(status[j] & STATUS_SOLID)) continue; - factor_lj = special_lj[sbmask(j)]; - if (factor_lj == 0) continue; - j &= NEIGHMASK; + if (!(status[j] & STATUS_SOLID)) continue; + delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; diff --git a/src/set.cpp b/src/set.cpp index 735d3bc831..cf2a053fab 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -923,7 +923,7 @@ void Set::set(int keyword) } else if (keyword == RHEO_STATUS) { - if (ivalue != 0 && ivalue != 2) + if (ivalue != 0 && ivalue != 1) error->one(FLERR,"Invalid value {} in set command for rheo/status", ivalue); atom->status[i] = ivalue; } From 70ea1dd3525e1decbb1430b65267a2d71a2abffa Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 23 Jan 2024 14:58:31 -0700 Subject: [PATCH 070/385] Refreshing no shift flag for solid particles --- src/RHEO/fix_rheo.cpp | 6 ++++++ src/RHEO/fix_rheo_thermal.cpp | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index beba940174..3a999e12dd 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -422,6 +422,12 @@ void FixRHEO::pre_force(int /*vflag*/) if (mask[i] & groupbit) status[i] &= OPTIONSMASK; + // Reinstate temporary options + for (int i = 0; i < nall; i++) + if (mask[i] & groupbit) + if (status[i] & STATUS_SOLID) + status[i] |= STATUS_NO_SHIFT; + // Calculate surfaces, update status if (surface_flag) { compute_surface->compute_peratom(); diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 7b61b9821e..635cf78c85 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -374,7 +374,6 @@ void FixRHEOThermal::post_integrate() } } } - } int n_melt_all, n_freeze_all; @@ -558,7 +557,7 @@ void FixRHEOThermal::create_bonds() for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; - j &= SPECIALMASK; + j &= NEIGHMASK; if (!(status[j] & STATUS_SOLID)) continue; if (!(status[i] & STATUS_FREEZING) && !(status[j] & STATUS_FREEZING)) continue; From b3de75da971382b79d8c5b585bb58ace365d48ee Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 23 Feb 2024 13:26:28 -0700 Subject: [PATCH 071/385] Cleaning up math, fixing tension bug, patching bond creation --- src/RHEO/compute_rheo_interface.cpp | 54 ++++++++++--------- src/RHEO/fix_rheo.cpp | 6 --- src/RHEO/fix_rheo_tension.cpp | 2 +- src/RHEO/fix_rheo_thermal.cpp | 80 +++++++++++++++++++++++------ 4 files changed, 90 insertions(+), 52 deletions(-) diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 001f15a472..3cb2fcf058 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -26,6 +26,7 @@ #include "force.h" #include "fix_rheo.h" #include "fix_rheo_pressure.h" +#include "math_extra.h" #include "memory.h" #include "modify.h" #include "neighbor.h" @@ -36,6 +37,7 @@ using namespace LAMMPS_NS; using namespace RHEO_NS; +using namespace MathExtra; static constexpr double EPSILON = 1e-1; @@ -107,8 +109,8 @@ void ComputeRHEOInterface::init_list(int /*id*/, NeighList *ptr) void ComputeRHEOInterface::compute_peratom() { - int i, j, ii, jj, jnum, itype, jtype, fluidi, fluidj, status_match; - double xtmp, ytmp, ztmp, delx, dely, delz, rsq, w, dot; + int a, i, j, ii, jj, jnum, itype, jtype, fluidi, fluidj, status_match; + double xtmp, ytmp, ztmp, rsq, w, dot, dx[3]; int inum, *ilist, *jlist, *numneigh, **firstneigh; int nlocal = atom->nlocal; @@ -153,15 +155,15 @@ void ComputeRHEOInterface::compute_peratom() j = jlist[jj]; j &= NEIGHMASK; - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx * delx + dely * dely + delz * delz; + dx[0] = xtmp - x[j][0]; + dx[1] = ytmp - x[j][1]; + dx[2] = ztmp - x[j][2]; + rsq = lensq3(dx); if (rsq < cutsq) { jtype = type[j]; fluidj = !(status[j] & PHASECHECK); - w = compute_kernel->calc_w_quintic(i, j, delx, dely, delz, sqrt(rsq)); + w = compute_kernel->calc_w_quintic(i, j, dx[0], dx[1], dx[2], sqrt(rsq)); status_match = 0; norm[i] += w; @@ -172,9 +174,9 @@ void ComputeRHEOInterface::compute_peratom() chi[i] += w; } else { if (!fluidi) { - dot = (-fp_store[j][0] + fp_store[i][0]) * delx; - dot += (-fp_store[j][1] + fp_store[i][1]) * dely; - dot += (-fp_store[j][2] + fp_store[i][2]) * delz; + dot = 0; + for (a = 0; a < 3; a++) + dot += (-fp_store[j][a] + fp_store[i][a]) * dx[a]; rho[i] += w * (fix_pressure->calc_pressure(rho[j], jtype) - rho[j] * dot); normwf[i] += w; @@ -187,9 +189,9 @@ void ComputeRHEOInterface::compute_peratom() chi[j] += w; } else { if (!fluidj) { - dot = (-fp_store[i][0] + fp_store[j][0]) * delx; - dot += (-fp_store[i][1] + fp_store[j][1]) * dely; - dot += (-fp_store[i][2] + fp_store[j][2]) * delz; + dot = 0; + for (a = 0; a < 3; a++) + dot += (-fp_store[i][a] + fp_store[j][a]) * dx[a]; rho[j] += w * (fix_pressure->calc_pressure(rho[i], itype) + rho[i] * dot); normwf[j] += w; @@ -225,7 +227,7 @@ void ComputeRHEOInterface::compute_peratom() int ComputeRHEOInterface::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { - int i,j,k,m; + int i, j, k, m; m = 0; double *rho = atom->rho; @@ -267,7 +269,7 @@ void ComputeRHEOInterface::unpack_forward_comm(int n, int first, double *buf) int ComputeRHEOInterface::pack_reverse_comm(int n, int first, double *buf) { - int i,k,m,last; + int i, k, m, last; double *rho = atom->rho; m = 0; @@ -285,7 +287,7 @@ int ComputeRHEOInterface::pack_reverse_comm(int n, int first, double *buf) void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) { - int i,k,j,m; + int i, k, j, m; double *rho = atom->rho; int *status = atom->status; m = 0; @@ -350,23 +352,19 @@ void ComputeRHEOInterface::store_forces() for (const auto &fix : fixlist) { for (int i = 0; i < atom->nlocal; i++) { minv = 1.0 / mass[type[i]]; - if (mask[i] & fix->groupbit) { - fp_store[i][0] = f[i][0] * minv; - fp_store[i][1] = f[i][1] * minv; - fp_store[i][2] = f[i][2] * minv; - } else { - fp_store[i][0] = (f[i][0] - fp_store[i][0]) * minv; - fp_store[i][1] = (f[i][1] - fp_store[i][1]) * minv; - fp_store[i][2] = (f[i][2] - fp_store[i][2]) * minv; - } + if (mask[i] & fix->groupbit) + for (int a = 0; a < 3; a++) + fp_store[i][a] = f[i][a] * minv; + else + for (int a = 0; a < 3; a++) + fp_store[i][a] = (f[i][a] - fp_store[i][a]) * minv; } } } else { for (int i = 0; i < atom->nlocal; i++) { minv = 1.0 / mass[type[i]]; - fp_store[i][0] = (f[i][0] - fp_store[i][0]) * minv; - fp_store[i][1] = (f[i][1] - fp_store[i][1]) * minv; - fp_store[i][2] = (f[i][2] - fp_store[i][2]) * minv; + for (int a = 0; a < 3; a++) + fp_store[i][a] = (f[i][a] - fp_store[i][a]) * minv; } } diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 3a999e12dd..beba940174 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -422,12 +422,6 @@ void FixRHEO::pre_force(int /*vflag*/) if (mask[i] & groupbit) status[i] &= OPTIONSMASK; - // Reinstate temporary options - for (int i = 0; i < nall; i++) - if (mask[i] & groupbit) - if (status[i] & STATUS_SOLID) - status[i] |= STATUS_NO_SHIFT; - // Calculate surfaces, update status if (surface_flag) { compute_surface->compute_peratom(); diff --git a/src/RHEO/fix_rheo_tension.cpp b/src/RHEO/fix_rheo_tension.cpp index 8d00c8b988..388b574365 100644 --- a/src/RHEO/fix_rheo_tension.cpp +++ b/src/RHEO/fix_rheo_tension.cpp @@ -467,7 +467,7 @@ void FixRHEOTension::pre_force(int vflag) if (wsame[i] < wmin) continue; - weight = MAX(1.0, wsame[i] * wmin_inv); + weight = MIN(1.0, wsame[i] * wmin_inv); //MAX -> MIN 2/14/24 itype = type[i]; if (norm[i] != 0) diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 635cf78c85..0640dd6827 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -423,6 +423,7 @@ void FixRHEOThermal::pre_force(int /*vflag*/) double *energy = atom->esph; double *temperature = atom->temperature; int *type = atom->type; + int *status = atom->status; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; @@ -444,6 +445,11 @@ void FixRHEOThermal::pre_force(int /*vflag*/) } } } + + // Add temporary options, wiped by preceding fix rheo preforce + for (int i = 0; i < nall; i++) + if (status[i] & STATUS_SOLID) + status[i] |= STATUS_NO_SHIFT; } /* ---------------------------------------------------------------------- */ @@ -481,39 +487,79 @@ void FixRHEOThermal::break_bonds() tagint **bond_atom = atom->bond_atom; int *num_bond = atom->num_bond; - int nlocal = atom->nlocal; + int **bondlist = neighbor->bondlist; + int nbondlist = neighbor->nbondlist; + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + // Rapidly delete all bonds for local atoms that melt (no shifting) for (int i = 0; i < nlocal; i++) { + if (!(status[i] & STATUS_MELTING)) continue; for (m = 0; m < num_bond[i]; m++) { j = atom->map(bond_atom[i][m]); - if (!(status[i] & STATUS_MELTING) && !(status[j] & STATUS_MELTING)) continue; + bond_type[i][m] = 0; if (n_histories > 0) for (auto &ihistory: histories) - dynamic_cast(ihistory)->delete_history(i, num_bond[i] - 1); + dynamic_cast(ihistory)->delete_history(i, m); - if (fix_update_special_bonds) fix_update_special_bonds->add_broken_bond(i, j); + if (fix_update_special_bonds) + fix_update_special_bonds->add_broken_bond(i, j); + } + num_bond[i] = 0; + } - // For non-melting neighbors, selectively delete bond if necessary - if (j >= nlocal || (status[j] & STATUS_MELTING)) continue; - for (n = 0; n < num_bond[j]; n++) { - if (bond_atom[j][n] == tag[i]) { - bond_type[j][n] = 0; - nmax = num_bond[j] - 1; - bond_type[j][n] = bond_type[j][nmax]; - bond_atom[j][n] = bond_atom[j][nmax]; - if (n_histories > 0) { + // Update bond list and break solid-melted bonds + for (n = 0; n < nbondlist; n++) { + + // skip bond if already broken + if (bondlist[n][2] <= 0) continue; + i = bondlist[n][0]; + j = bondlist[n][1]; + + if (!(status[i] & STATUS_MELTING) && !(status[j] & STATUS_MELTING)) continue; + + bondlist[n][2] = 0; + + // Delete bonds for non-melted local atoms (shifting) + if (i < nlocal) { + for (m = 0; m < num_bond[i]; m++) { + if (bond_atom[i][m] == tag[j]) { + nmax = num_bond[i] - 1; + bond_type[i][m] = bond_type[i][nmax]; + bond_atom[i][m] = bond_atom[i][nmax]; + if (n_histories > 0) for (auto &ihistory: histories) { - dynamic_cast(ihistory)->shift_history(j, n, nmax); - dynamic_cast(ihistory)->delete_history(j, nmax); + auto fix_bond_history = dynamic_cast (ihistory); + fix_bond_history->shift_history(i, m, nmax); + fix_bond_history->delete_history(i, nmax); } - } + bond_type[i][nmax] = 0; + num_bond[i]--; + break; + } + } + } + + if (j < nlocal) { + for (m = 0; m < num_bond[j]; m++) { + if (bond_atom[j][m] == tag[i]) { + nmax = num_bond[j] - 1; + bond_type[j][m] = bond_type[j][nmax]; + bond_atom[j][m] = bond_atom[j][nmax]; + if (n_histories > 0) + for (auto &ihistory: histories) { + auto fix_bond_history = dynamic_cast (ihistory); + fix_bond_history->shift_history(j, m, nmax); + fix_bond_history->delete_history(j, nmax); + } + bond_type[j][nmax] = 0; num_bond[j]--; break; } } } - num_bond[i] = 0; } } From 010a4c076bf72e5e546d7e9ffc11a62bbaa1b2bb Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 28 Mar 2024 11:31:21 -0600 Subject: [PATCH 072/385] Prototyping oxidation --- doc/src/Commands_bond.rst | 1 + doc/src/Commands_compute.rst | 1 + doc/src/Commands_fix.rst | 5 + doc/src/Commands_pair.rst | 2 + doc/src/bond_rheo_shell.rst | 226 +++++++++++++ doc/src/fix_rheo_oxidation.rst | 81 +++++ src/BPM/bond_bpm.cpp | 4 +- src/RHEO/bond_rheo_shell.cpp | 507 ++++++++++++++++++++++++++++ src/RHEO/bond_rheo_shell.h | 55 +++ src/RHEO/compute_rheo_interface.cpp | 3 +- src/RHEO/fix_rheo_oxidation.cpp | 190 +++++++++++ src/RHEO/fix_rheo_oxidation.h | 49 +++ src/RHEO/fix_rheo_thermal.cpp | 11 + src/bond_hybrid.cpp | 5 + 14 files changed, 1137 insertions(+), 3 deletions(-) create mode 100644 doc/src/bond_rheo_shell.rst create mode 100644 doc/src/fix_rheo_oxidation.rst create mode 100644 src/RHEO/bond_rheo_shell.cpp create mode 100644 src/RHEO/bond_rheo_shell.h create mode 100644 src/RHEO/fix_rheo_oxidation.cpp create mode 100644 src/RHEO/fix_rheo_oxidation.h diff --git a/doc/src/Commands_bond.rst b/doc/src/Commands_bond.rst index aaf706b5df..ee03b7e245 100644 --- a/doc/src/Commands_bond.rst +++ b/doc/src/Commands_bond.rst @@ -54,6 +54,7 @@ OPT. * :doc:`oxdna2/fene ` * :doc:`oxrna2/fene ` * :doc:`quartic (o) ` + * :doc:`rheo/shell ` * :doc:`special ` * :doc:`table (o) ` diff --git a/doc/src/Commands_compute.rst b/doc/src/Commands_compute.rst index 0352ad5374..394a5bee3a 100644 --- a/doc/src/Commands_compute.rst +++ b/doc/src/Commands_compute.rst @@ -122,6 +122,7 @@ KOKKOS, o = OPENMP, t = OPT. * :doc:`reduce ` * :doc:`reduce/chunk ` * :doc:`reduce/region ` + * :doc:`rheo/property/atom ` * :doc:`rigid/local ` * :doc:`saed ` * :doc:`slcsa/atom ` diff --git a/doc/src/Commands_fix.rst b/doc/src/Commands_fix.rst index e89e302673..7053c4809a 100644 --- a/doc/src/Commands_fix.rst +++ b/doc/src/Commands_fix.rst @@ -203,6 +203,11 @@ OPT. * :doc:`reaxff/species (k) ` * :doc:`recenter ` * :doc:`restrain ` + * :doc:`rheo ` + * :doc:`rheo/oxidation ` + * :doc:`rheo/pressure ` + * :doc:`rheo/thermal ` + * :doc:`rheo/viscosity ` * :doc:`rhok ` * :doc:`rigid (o) ` * :doc:`rigid/meso ` diff --git a/doc/src/Commands_pair.rst b/doc/src/Commands_pair.rst index e7761e7bee..9b56e92819 100644 --- a/doc/src/Commands_pair.rst +++ b/doc/src/Commands_pair.rst @@ -257,6 +257,8 @@ OPT. * :doc:`reaxff (ko) ` * :doc:`rebo (io) ` * :doc:`resquared (go) ` + * :doc:`rheo ` + * :doc:`rheo/solid ` * :doc:`saip/metal (t) ` * :doc:`sdpd/taitwater/isothermal ` * :doc:`smatb ` diff --git a/doc/src/bond_rheo_shell.rst b/doc/src/bond_rheo_shell.rst new file mode 100644 index 0000000000..7f6bab1eab --- /dev/null +++ b/doc/src/bond_rheo_shell.rst @@ -0,0 +1,226 @@ +.. index:: bond_style rheo/shell + +bond_style rheo/shell command +============================= + +Syntax +"""""" + +.. code-block:: LAMMPS + + bond_style rheo/shell keyword value attribute1 attribute2 ... + +* optional keyword = *overlay/pair* or *store/local* or *smooth* or *break* + + .. parsed-literal:: + + *store/local* values = fix_ID N attributes ... + * fix_ID = ID of associated internal fix to store data + * N = prepare data for output every this many timesteps + * attributes = zero or more of the below attributes may be appended + + *id1, id2* = IDs of 2 atoms in the bond + *time* = the timestep the bond broke + *x, y, z* = the center of mass position of the 2 atoms when the bond broke (distance units) + *x/ref, y/ref, z/ref* = the initial center of mass position of the 2 atoms (distance units) + + *overlay/pair* value = *yes* or *no* + bonded particles will still interact with pair forces + + *smooth* value = *yes* or *no* + smooths bond forces near the breaking point + + *normalize* value = *yes* or *no* + normalizes bond forces by the reference length + + *break* value = *yes* or *no* + indicates whether bonds break during a run + +Examples +"""""""" + +.. code-block:: LAMMPS + + bond_style bpm/spring + bond_coeff 1 1.0 0.05 0.1 + + bond_style bpm/spring myfix 1000 time id1 id2 + dump 1 all local 1000 dump.broken f_myfix[1] f_myfix[2] f_myfix[3] + dump_modify 1 write_header no + +Description +""""""""""" + +.. versionadded:: 4May2022 + +The *bpm/spring* bond style computes forces based on +deviations from the initial reference state of the two atoms. The +reference state is stored by each bond when it is first computed in +the setup of a run. Data is then preserved across run commands and is +written to :doc:`binary restart files ` such that restarting +the system will not reset the reference state of a bond. + +This bond style only applies central-body forces which conserve the +translational and rotational degrees of freedom of a bonded set of +particles based on a model described by Clemmer and Robbins +:ref:`(Clemmer) `. The force has a magnitude of + +.. math:: + + F = k (r - r_0) w + +where :math:`k` is a stiffness, :math:`r` is the current distance +and :math:`r_0` is the initial distance between the two particles, and +:math:`w` is an optional smoothing factor discussed below. Bonds will +break at a strain of :math:`\epsilon_c`. This is done by setting +the bond type to 0 such that forces are no longer computed. + +An additional damping force is applied to the bonded +particles. This forces is proportional to the difference in the +normal velocity of particles using a similar construction as +dissipative particle dynamics :ref:`(Groot) `: + +.. math:: + + F_D = - \gamma w (\hat{r} \bullet \vec{v}) + +where :math:`\gamma` is the damping strength, :math:`\hat{r}` is the +radial normal vector, and :math:`\vec{v}` is the velocity difference +between the two particles. + +The smoothing factor :math:`w` can be added or removed by setting the +*smooth* keyword to *yes* or *no*, respectively. It is constructed such +that forces smoothly go to zero, avoiding discontinuities, as bonds +approach the critical strain + +.. math:: + + w = 1.0 - \left( \frac{r - r_0}{r_0 \epsilon_c} \right)^8 . + +The following coefficients must be defined for each bond type via the +:doc:`bond_coeff ` command as in the example above, or in +the data file or restart files read by the :doc:`read_data +` or :doc:`read_restart ` commands: + +* :math:`k` (force/distance units) +* :math:`\epsilon_c` (unit less) +* :math:`\gamma` (force/velocity units) + +If the *normalize* keyword is set to *yes*, the elastic bond force will be +normalized by :math:`r_0` such that :math:`k` must be given in force units. + +By default, pair forces are not calculated between bonded particles. +Pair forces can alternatively be overlaid on top of bond forces by setting +the *overlay/pair* keyword to *yes*. These settings require specific +:doc:`special_bonds ` settings described in the +restrictions. Further details can be found in the :doc:`how to ` +page on BPMs. + +.. versionadded:: 28Mar2023 + +If the *break* keyword is set to *no*, LAMMPS assumes bonds should not break +during a simulation run. This will prevent some unnecessary calculation. +However, if a bond reaches a strain greater than :math:`\epsilon_c`, +it will trigger an error. + +If the *store/local* keyword is used, an internal fix will track bonds that +break during the simulation. Whenever a bond breaks, data is processed +and transferred to an internal fix labeled *fix_ID*. This allows the +local data to be accessed by other LAMMPS commands. Following this optional +keyword, a list of one or more attributes is specified. These include the +IDs of the two atoms in the bond. The other attributes for the two atoms +include the timestep during which the bond broke and the current/initial +center of mass position of the two atoms. + +Data is continuously accumulated over intervals of *N* +timesteps. At the end of each interval, all of the saved accumulated +data is deleted to make room for new data. Individual datum may +therefore persist anywhere between *1* to *N* timesteps depending on +when they are saved. This data can be accessed using the *fix_ID* and a +:doc:`dump local ` command. To ensure all data is output, +the dump frequency should correspond to the same interval of *N* +timesteps. A dump frequency of an integer multiple of *N* can be used +to regularly output a sample of the accumulated data. + +Note that when unbroken bonds are dumped to a file via the +:doc:`dump local ` command, bonds with type 0 (broken bonds) +are not included. +The :doc:`delete_bonds ` command can also be used to +query the status of broken bonds or permanently delete them, e.g.: + +.. code-block:: LAMMPS + + delete_bonds all stats + delete_bonds all bond 0 remove + +---------- + +Restart and other info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +This bond style writes the reference state of each bond to +:doc:`binary restart files `. Loading a restart +file will properly restore bonds. However, the reference state is NOT +written to data files. Therefore reading a data file will not +restore bonds and will cause their reference states to be redefined. + +If the *store/local* option is used, an internal fix will calculate +a local vector or local array depending on the number of input values. +The length of the vector or number of rows in the array is the number +of recorded, broken bonds. If a single input is specified, a local +vector is produced. If two or more inputs are specified, a local array +is produced where the number of columns = the number of inputs. The +vector or array can be accessed by any command that uses local values +from a compute as input. See the :doc:`Howto output ` page +for an overview of LAMMPS output options. + +The vector or array will be floating point values that correspond to +the specified attribute. + +The single() function of this bond style returns 0.0 for the energy +of a bonded interaction, since energy is not conserved in these +dissipative potentials. The single() function also calculates an +extra bond quantity, the initial distance :math:`r_0`. This +extra quantity can be accessed by the +:doc:`compute bond/local ` command as *b1*\ . + +Restrictions +"""""""""""" + +This bond style is part of the BPM package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package +` page for more info. + +By default if pair interactions between bonded atoms are to be disabled, +this bond style requires setting + +.. code-block:: LAMMPS + + special_bonds lj 0 1 1 coul 1 1 1 + +and :doc:`newton ` must be set to bond off. If the *overlay/pair* +keyword is set to *yes*, this bond style alternatively requires setting + +.. code-block:: LAMMPS + + special_bonds lj/coul 1 1 1 + +Related commands +"""""""""""""""" + +:doc:`bond_coeff `, :doc:`pair bpm/spring ` + +Default +""""""" + +The option defaults are *overlay/pair* = *no*, *smooth* = *yes*, *normalize* = *no*, and *break* = *yes* + +---------- + +.. _fragment-Clemmer: + +**(Clemmer)** Clemmer and Robbins, Phys. Rev. Lett. (2022). + +.. _Groot4: + +**(Groot)** Groot and Warren, J Chem Phys, 107, 4423-35 (1997). diff --git a/doc/src/fix_rheo_oxidation.rst b/doc/src/fix_rheo_oxidation.rst new file mode 100644 index 0000000000..a747ec582f --- /dev/null +++ b/doc/src/fix_rheo_oxidation.rst @@ -0,0 +1,81 @@ +.. index:: fix rheo/oxidation + +fix rheo/oxidation command +========================== + +Syntax +"""""" + +.. parsed-literal:: + + fix ID group-ID rheo/oxidation cut btype + +* ID, group-ID are documented in :doc:`fix ` command +* rheo/oxidation = style name of this fix command +* cut = maximum bond length (distance units) +* btype = type of bonds created + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix 1 all rheo/oxidation 1.5 2 + +Description +""""""""""" + +This fix... + +Each list consists of a series of type +ranges separated by commas. The range can be specified as a +single numeric value, or a wildcard asterisk can be used to specify a range +of values. This takes the form "\*" or "\*n" or "n\*" or "m\*n". For +example, if M = the number of atom types, then an asterisk with no numeric +values means all types from 1 to M. A leading asterisk means all types +from 1 to n (inclusive). A trailing asterisk means all types from n to M +(inclusive). A middle asterisk means all types from m to n (inclusive). +Note that all atom types must be included in exactly one of the N collections. + +While the *Tfreeze* keyword is optional, the *conductivity* and +*specific/heat* keywords are mandatory. + +Multiple instances of this fix may be defined to apply different +properties to different groups. However, the union of fix groups +across all instances of fix rheo/thermal must cover all atoms. +If there are multiple instances of this fix, any intersections in +the fix groups will lead to incorrect thermal integration. + +Restart, fix_modify, output, run start/stop, minimize info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +are relevant to this fix. No global or per-atom quantities are stored +by this fix for access by various :doc:`output commands `. +No parameter of this fix can be used with the *start/stop* keywords of +the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. + +Restrictions +"""""""""""" + +This fix must be used with an atom style that includes temperature, +heatflow, and conductivity such as atom_tyle rheo/thermal This fix +must be used in conjuction with :doc:`fix rheo ` with the +*thermal* setting. + +This fix is part of the RHEO package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`fix rheo `, +:doc:`fix rheo/viscosity `, +:doc:`fix rheo/pressure `, +:doc:`pair rheo `, +:doc:`compute rheo/property/atom ` + +Default +""""""" + +none diff --git a/src/BPM/bond_bpm.cpp b/src/BPM/bond_bpm.cpp index b484df7fab..34554497ad 100644 --- a/src/BPM/bond_bpm.cpp +++ b/src/BPM/bond_bpm.cpp @@ -50,10 +50,10 @@ BondBPM::BondBPM(LAMMPS *_lmp) : // this is so final order of Modify:fix will conform to input script // BondHistory technically only needs this if updateflag = 1 - id_fix_dummy = utils::strdup("BPM_DUMMY"); + id_fix_dummy = utils::strdup(fmt::format("BPM_DUMMY_{}", instance_total)); modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy)); - id_fix_dummy2 = utils::strdup("BPM_DUMMY2"); + id_fix_dummy2 = utils::strdup(fmt::format("BPM_DUMMY2_{}", instance_total)); modify->add_fix(fmt::format("{} all DUMMY ", id_fix_dummy2)); } diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp new file mode 100644 index 0000000000..6a9f99d8b1 --- /dev/null +++ b/src/RHEO/bond_rheo_shell.cpp @@ -0,0 +1,507 @@ +/* ---------------------------------------------------------------------- + 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 "bond_rheo_shell.h" + +#include "atom.h" +#include "comm.h" +#include "domain.h" +#include "error.h" +#include "fix_bond_history.h" +#include "fix_rheo.h" +#include "fix_store_local.h" +#include "force.h" +#include "memory.h" +#include "modify.h" +#include "neighbor.h" +#include "update.h" + +#include +#include + +#define EPSILON 1e-10 + +using namespace LAMMPS_NS; +using namespace RHEO_NS; + +/* ---------------------------------------------------------------------- */ + +BondRHEOShell::BondRHEOShell(LAMMPS *_lmp) : + BondBPM(_lmp), k(nullptr), ecrit(nullptr), gamma(nullptr) +{ + partial_flag = 1; + + tform = rmax = -1; + + single_extra = 1; + svector = new double[1]; +} + +/* ---------------------------------------------------------------------- */ + +BondRHEOShell::~BondRHEOShell() +{ + delete[] svector; + + if (allocated) { + memory->destroy(setflag); + memory->destroy(k); + memory->destroy(ecrit); + memory->destroy(gamma); + } +} + +/* ---------------------------------------------------------------------- + Store data for a single bond - if bond added after LAMMPS init (e.g. pour) +------------------------------------------------------------------------- */ + +double BondRHEOShell::store_bond(int n, int i, int j) +{ + double **bondstore = fix_bond_history->bondstore; + tagint *tag = atom->tag; + + bondstore[n][0] = 0.0; + bondstore[n][1] = 0.0; + + if (i < atom->nlocal) { + for (int m = 0; m < atom->num_bond[i]; m++) { + if (atom->bond_atom[i][m] == tag[j]) { + fix_bond_history->update_atom_value(i, m, 0, 0.0); + fix_bond_history->update_atom_value(i, m, 1, 0.0); + } + } + } + + if (j < atom->nlocal) { + for (int m = 0; m < atom->num_bond[j]; m++) { + if (atom->bond_atom[j][m] == tag[i]) { + fix_bond_history->update_atom_value(j, m, 0, 0.0); + fix_bond_history->update_atom_value(j, m, 1, 0.0); + } + } + } + + return 0.0; +} + +/* ---------------------------------------------------------------------- + Store data for all bonds called once +------------------------------------------------------------------------- */ + +void BondRHEOShell::store_data() +{ + int i, j, m, type; + int **bond_type = atom->bond_type; + + for (i = 0; i < atom->nlocal; i++) { + for (m = 0; m < atom->num_bond[i]; m++) { + type = bond_type[i][m]; + + //Skip if bond was turned off + if (type < 0) continue; + + // map to find index n + j = atom->map(atom->bond_atom[i][m]); + if (j == -1) error->one(FLERR, "Atom missing in BPM bond"); + + fix_bond_history->update_atom_value(i, m, 0, 0.0); + fix_bond_history->update_atom_value(i, m, 1, 0.0); + } + } + + fix_bond_history->post_neighbor(); +} + +/* ---------------------------------------------------------------------- */ + +void BondRHEOShell::compute(int eflag, int vflag) +{ + + if (!fix_bond_history->stored_flag) { + fix_bond_history->stored_flag = true; + store_data(); + } + + int i1, i2, itmp, n, type; + double delx, dely, delz, delvx, delvy, delvz; + double e, rsq, r, r0, rinv, dr, fbond, dot, t; + double dt = update->dt; + + ev_init(eflag, vflag); + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + tagint *tag = atom->tag; + int *status = atom->status; + int **bondlist = neighbor->bondlist; + int nbondlist = neighbor->nbondlist; + int nlocal = atom->nlocal; + int newton_bond = force->newton_bond; + + double **bondstore = fix_bond_history->bondstore; + + for (n = 0; n < nbondlist; n++) { + + // skip bond if already broken + if (bondlist[n][2] <= 0) continue; + + i1 = bondlist[n][0]; + i2 = bondlist[n][1]; + type = bondlist[n][2]; + r0 = bondstore[n][0]; + t = bondstore[n][1]; + + // Ensure pair is always ordered to ensure numerical operations + // are identical to minimize the possibility that a bond straddling + // an mpi grid (newton off) doesn't break on one proc but not the other + if (tag[i2] < tag[i1]) { + itmp = i1; + i1 = i2; + i2 = itmp; + } + + // If bond hasn't been set - set timer to zero + if (t < EPSILON || std::isnan(t)) r0 = store_bond(n, i1, i2); + + delx = x[i1][0] - x[i2][0]; + dely = x[i1][1] - x[i2][1]; + delz = x[i1][2] - x[i2][2]; + + rsq = delx * delx + dely * dely + delz * delz; + r = sqrt(rsq); + + // Bond has not yet formed, check if in range + update timer + if (t < tform) { + + // Check if eligible + if (r > rmax || !(status[i1] & STATUS_SURFACE) || !(status[i2] & STATUS_SURFACE)) { + bondlist[n][2] = 0; + process_ineligibility(i1, i2); + continue; + } + + // Check ellapsed time + bondstore[n][1] += dt; + if (bondstore[n][1] >= tform) { + bondstore[n][0] = r; + r0 = r; + } else { + continue; + } + } + + e = (r - r0) / r0; + if (fabs(e) > ecrit[type]) { + bondlist[n][2] = 0; + process_broken(i1, i2); + continue; + } + + rinv = 1.0 / r; + dr = r - r0; + fbond = 2 * k[type] * (-dr + dr * dr * dr / (r0 * r0 * ecrit[type] * ecrit[type])); + + delvx = v[i1][0] - v[i2][0]; + delvy = v[i1][1] - v[i2][1]; + delvz = v[i1][2] - v[i2][2]; + dot = delx * delvx + dely * delvy + delz * delvz; + fbond -= gamma[type] * dot * rinv; + fbond *= rinv; + + if (newton_bond || i1 < nlocal) { + f[i1][0] += delx * fbond; + f[i1][1] += dely * fbond; + f[i1][2] += delz * fbond; + } + + if (newton_bond || i2 < nlocal) { + f[i2][0] -= delx * fbond; + f[i2][1] -= dely * fbond; + f[i2][2] -= delz * fbond; + } + + if (evflag) ev_tally(i1, i2, nlocal, newton_bond, 0.0, fbond, delx, dely, delz); + } +} + +/* ---------------------------------------------------------------------- */ + +void BondRHEOShell::allocate() +{ + allocated = 1; + const int np1 = atom->nbondtypes + 1; + + memory->create(k, np1, "bond:k"); + memory->create(ecrit, np1, "bond:ecrit"); + memory->create(gamma, np1, "bond:gamma"); + + memory->create(setflag, np1, "bond:setflag"); + for (int i = 1; i < np1; i++) setflag[i] = 0; +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more types +------------------------------------------------------------------------- */ + +void BondRHEOShell::coeff(int narg, char **arg) +{ + if (narg != 4) error->all(FLERR, "Incorrect args for bond coefficients"); + if (!allocated) allocate(); + + int ilo, ihi; + utils::bounds(FLERR, arg[0], 1, atom->nbondtypes, ilo, ihi, error); + + double k_one = utils::numeric(FLERR, arg[1], false, lmp); + double ecrit_one = utils::numeric(FLERR, arg[2], false, lmp); + double gamma_one = utils::numeric(FLERR, arg[3], false, lmp); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + k[i] = k_one; + ecrit[i] = ecrit_one; + gamma[i] = gamma_one; + setflag[i] = 1; + count++; + + if (1.0 + ecrit[i] > max_stretch) max_stretch = 1.0 + ecrit[i]; + } + + if (count == 0) error->all(FLERR, "Incorrect args for bond coefficients"); +} + +/* ---------------------------------------------------------------------- + check for correct settings and create fix +------------------------------------------------------------------------- */ + +void BondRHEOShell::init_style() +{ + if (comm->ghost_velocity == 0) + error->all(FLERR, "Bond rheo/shell requires ghost atoms store velocity"); + + if (!id_fix_bond_history) { + id_fix_bond_history = utils::strdup("HISTORY_RHEO_SHELL"); + fix_bond_history = dynamic_cast(modify->replace_fix( + id_fix_dummy2, fmt::format("{} all BOND_HISTORY 1 2", id_fix_bond_history), 1)); + delete[] id_fix_dummy2; + id_fix_dummy2 = nullptr; + } + + // Reproduce standard functions of BondBPM, removing special restrictions + // Since this bond is intended to be created by fix rheo/oxidation, it + // ignores special statuses + + if (id_fix_store_local) { + auto ifix = modify->get_fix_by_id(id_fix_store_local); + if (!ifix) error->all(FLERR, "Cannot find fix STORE/LOCAL id {}", id_fix_store_local); + if (strcmp(ifix->style, "STORE/LOCAL") != 0) + error->all(FLERR, "Incorrect fix style matched, not STORE/LOCAL: {}", ifix->style); + fix_store_local = dynamic_cast(ifix); + fix_store_local->nvalues = nvalues; + } + + id_fix_update = nullptr; + + if (force->angle || force->dihedral || force->improper) + error->all(FLERR, "Bond style rheo/shell cannot be used with 3,4-body interactions"); + if (atom->molecular == 2) + error->all(FLERR, "Bond style rheo/shell cannot be used with atom style template"); +} + +/* ---------------------------------------------------------------------- */ + +void BondRHEOShell::settings(int narg, char **arg) +{ + BondBPM::settings(narg, arg); + + int iarg; + for (std::size_t i = 0; i < leftover_iarg.size(); i++) { + iarg = leftover_iarg[i]; + if (strcmp(arg[iarg], "t/form") == 0) { + if (iarg + 1 > narg) error->all(FLERR, "Illegal bond rheo/shell command, missing option for t/form"); + tform = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + if (tform < 0.0) error->all(FLERR, "Illegal bond rheo/shell value for t/form, {}", tform); + i += 1; + } else if (strcmp(arg[iarg], "r/max") == 0) { + if (iarg + 1 > narg) error->all(FLERR, "Illegal bond rheo/shell command, missing option for r/max"); + rmax = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + if (rmax < 0.0) error->all(FLERR, "Illegal bond rheo/shell value for r/max, {}", rmax); + i += 1; + } else { + error->all(FLERR, "Illegal bond rheo/shell command, invalid argument {}", arg[iarg]); + } + } + + if (tform < 0.0) + error->all(FLERR, "Illegal bond rheo/shell command, must specify t/form"); + if (rmax < 0.0) + error->all(FLERR, "Illegal bond rheo/shell command, must specify r/max"); +} + + +/* ---------------------------------------------------------------------- + used to check bond communiction cutoff - not perfect, estimates based on local-local only +------------------------------------------------------------------------- */ + +double BondRHEOShell::equilibrium_distance(int /*i*/) +{ + // Divide out heuristic prefactor added in comm class + return max_stretch * rmax / 1.5; +} + +/* ---------------------------------------------------------------------- + proc 0 writes out coeffs to restart file +------------------------------------------------------------------------- */ + +void BondRHEOShell::write_restart(FILE *fp) +{ + BondBPM::write_restart(fp); + write_restart_settings(fp); + + fwrite(&k[1], sizeof(double), atom->nbondtypes, fp); + fwrite(&ecrit[1], sizeof(double), atom->nbondtypes, fp); + fwrite(&gamma[1], sizeof(double), atom->nbondtypes, fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads coeffs from restart file, bcasts them +------------------------------------------------------------------------- */ + +void BondRHEOShell::read_restart(FILE *fp) +{ + BondBPM::read_restart(fp); + read_restart_settings(fp); + allocate(); + + if (comm->me == 0) { + utils::sfread(FLERR, &k[1], sizeof(double), atom->nbondtypes, fp, nullptr, error); + utils::sfread(FLERR, &ecrit[1], sizeof(double), atom->nbondtypes, fp, nullptr, error); + utils::sfread(FLERR, &gamma[1], sizeof(double), atom->nbondtypes, fp, nullptr, error); + } + MPI_Bcast(&k[1], atom->nbondtypes, MPI_DOUBLE, 0, world); + MPI_Bcast(&ecrit[1], atom->nbondtypes, MPI_DOUBLE, 0, world); + MPI_Bcast(&gamma[1], atom->nbondtypes, MPI_DOUBLE, 0, world); + + for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file + ------------------------------------------------------------------------- */ + +void BondRHEOShell::write_restart_settings(FILE *fp) +{ + fwrite(&tform, sizeof(double), 1, fp); + fwrite(&rmax, sizeof(double), 1, fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts + ------------------------------------------------------------------------- */ + +void BondRHEOShell::read_restart_settings(FILE *fp) +{ + if (comm->me == 0) { + utils::sfread(FLERR, &tform, sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &rmax, sizeof(double), 1, fp, nullptr, error); + } + MPI_Bcast(&tform, 1, MPI_DOUBLE, 0, world); + MPI_Bcast(&rmax, 1, MPI_DOUBLE, 0, world); +} + +/* ---------------------------------------------------------------------- */ + +double BondRHEOShell::single(int type, double rsq, int i, int j, double &fforce) +{ + if (type <= 0) return 0.0; + + double r0, t; + for (int n = 0; n < atom->num_bond[i]; n++) { + if (atom->bond_atom[i][n] == atom->tag[j]) { + r0 = fix_bond_history->get_atom_value(i, n, 0); + t = fix_bond_history->get_atom_value(i, n, 1); + } + } + + svector[1] = t; + if (t < tform) return 0.0; + + double r = sqrt(rsq); + double rinv = 1.0 / r; + double dr = r0 - r; + fforce = 2 * k[type] * (dr + dr * dr * dr / (r0 * r0 * ecrit[type] * ecrit[type])); + + double **x = atom->x; + double **v = atom->v; + double delx = x[i][0] - x[j][0]; + double dely = x[i][1] - x[j][1]; + double delz = x[i][2] - x[j][2]; + double delvx = v[i][0] - v[j][0]; + double delvy = v[i][1] - v[j][1]; + double delvz = v[i][2] - v[j][2]; + double dot = delx * delvx + dely * delvy + delz * delvz; + fforce -= gamma[type] * dot * rinv; + fforce *= rinv; + + // set single_extra quantities + + svector[0] = r0; + + return 0.0; +} + +/* ---------------------------------------------------------------------- + Similar to BondBPM->process_broken(), but don't send to FixStoreLocal + ------------------------------------------------------------------------- */ + +void BondRHEOShell::process_ineligibility(int i, int j) +{ + // Manually search and remove from atom arrays + int m, n; + int nlocal = atom->nlocal; + + tagint *tag = atom->tag; + tagint **bond_atom = atom->bond_atom; + int **bond_type = atom->bond_type; + int *num_bond = atom->num_bond; + + if (i < nlocal) { + for (m = 0; m < num_bond[i]; m++) { + if (bond_atom[i][m] == tag[j]) { + bond_type[i][m] = 0; + n = num_bond[i]; + bond_type[i][m] = bond_type[i][n - 1]; + bond_atom[i][m] = bond_atom[i][n - 1]; + fix_bond_history->shift_history(i, m, n - 1); + fix_bond_history->delete_history(i, n - 1); + num_bond[i]--; + break; + } + } + } + + if (j < nlocal) { + for (m = 0; m < num_bond[j]; m++) { + if (bond_atom[j][m] == tag[i]) { + bond_type[j][m] = 0; + n = num_bond[j]; + bond_type[j][m] = bond_type[j][n - 1]; + bond_atom[j][m] = bond_atom[j][n - 1]; + fix_bond_history->shift_history(j, m, n - 1); + fix_bond_history->delete_history(j, n - 1); + num_bond[j]--; + break; + } + } + } +} diff --git a/src/RHEO/bond_rheo_shell.h b/src/RHEO/bond_rheo_shell.h new file mode 100644 index 0000000000..562be6d9a6 --- /dev/null +++ b/src/RHEO/bond_rheo_shell.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef BOND_CLASS +// clang-format off +BondStyle(rheo/shell,BondRHEOShell); +// clang-format on +#else + +#ifndef LMP_BOND_RHEO_SHELL_H +#define LMP_BOND_RHEO_SHELL_H + +#include "bond_bpm.h" + +namespace LAMMPS_NS { + +class BondRHEOShell : public BondBPM { + public: + BondRHEOShell(class LAMMPS *); + ~BondRHEOShell() override; + void compute(int, int) override; + void coeff(int, char **) override; + void init_style() override; + void settings(int, char **) override; + double equilibrium_distance(int) override; + void write_restart(FILE *) override; + void read_restart(FILE *) override; + void write_restart_settings(FILE *) override; + void read_restart_settings(FILE *) override; + double single(int, double, int, int, double &) override; + + protected: + double *k, *ecrit, *gamma; + double tform, rmax; + + void process_ineligibility(int, int); + void allocate(); + void store_data(); + double store_bond(int, int, int); +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 3cb2fcf058..31930d655d 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -329,7 +329,8 @@ double ComputeRHEOInterface::correct_rho(int i, int j) { // i is wall, j is fluid //In future may depend on atom type j's pressure equation - return atom->rho[i]; + int itype = atom->type[i]; + return MAX(rho0[itype], atom->rho[i]); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp new file mode 100644 index 0000000000..bd7babedbb --- /dev/null +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -0,0 +1,190 @@ +/* ---------------------------------------------------------------------- + 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. + ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL) +----------------------------------------------------------------------- */ + +#include "fix_rheo_oxidation.h" + +#include "atom.h" +#include "atom_vec.h" +#include "error.h" +#include "fix_rheo.h" +#include "force.h" +#include "modify.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" + +using namespace LAMMPS_NS; +using namespace RHEO_NS; +using namespace FixConst; +enum {NONE, CONSTANT}; + +/* ---------------------------------------------------------------------- */ + +FixRHEOOxidation::FixRHEOOxidation(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) //, fix_bond_history(nullptr) +{ + if (narg != 5) error->all(FLERR,"Illegal fix command"); + + cut = utils::numeric(FLERR, arg[3], false, lmp); + if (cut <= 0.0) error->all(FLERR, "Illegal bond cutoff {} in fix rheo/oxidation", cut); + + btype = utils::inumeric(FLERR, arg[4], false, lmp); + if (btype < 1 || btype > atom->nbondtypes) error->all(FLERR, "Illegal value {} for bond type in fix rheo/oxidation", btype); + + cutsq = cut * cut; +} + +/* ---------------------------------------------------------------------- */ + +FixRHEOOxidation::~FixRHEOOxidation() +{ +} + +/* ---------------------------------------------------------------------- */ + +int FixRHEOOxidation::setmask() +{ + int mask = 0; + mask |= POST_INTEGRATE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOOxidation::init() +{ + auto fixes = modify->get_fix_by_style("^rheo$"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/oxidation"); + class FixRHEO *fix_rheo = dynamic_cast(fixes[0]); + double cut_kernel = fix_rheo->h; + + if (cut > cut_kernel) + error->all(FLERR, "Bonding length exceeds kernel cutoff"); + + if (!force->bond) error->all(FLERR, "Must define a bond style with fix rheo/oxidation"); + if (!atom->avec->bonds_allow) error->all(FLERR, "Fix rheo/oxidation requires atom bonds"); + + //// find instances of bond history to delete data + //histories = modify->get_fix_by_style("BOND_HISTORY"); + //for (auto &ihistory: histories) + // if (strcmp(histories[i]->id, "HISTORY_RHEO_SHELL") == 0) + // fix_bond_history = dynamic_cast(ihistory); +// + //if (!fix_bond_history) + // error->all(FLERR, "Must define bond style rheo/shell to use fix rheo/oxidation"); + + // need a half neighbor list + auto req = neighbor->add_request(this, NeighConst::REQ_DEFAULT); + req->set_cutoff(cut); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOOxidation::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOOxidation::post_integrate() +{ + int i, j, n, ii, jj, inum, jnum, bflag; + int *ilist, *jlist, *numneigh, **firstneigh; + double xtmp, ytmp, ztmp, delx, dely, delz, rsq; + tagint tagi, tagj; + + int nlocal = atom->nlocal; + int newton_bond = force->newton_bond; + + tagint *tag = atom->tag; + tagint **bond_atom = atom->bond_atom; + int *status = atom->status; + int **bond_type = atom->bond_type; + int *num_bond = atom->num_bond; + double **x = atom->x; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // loop over neighbors of my atoms + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + if (!(status[i] & STATUS_SURFACE)) continue; + + tagi = tag[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + + jlist = firstneigh[i]; + jnum = numneigh[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + if (!(status[j] & STATUS_SURFACE)) continue; + + tagj = tag[j]; + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + if (rsq > cutsq) continue; + + // Check if already have an oxide bond + bflag = 0; + for (n = 0; n < num_bond[i]; n++) { + if (bond_type[i][n] == btype && bond_atom[i][n] == tagj) { + bflag = 1; + break; + } + } + if (bflag) continue; + + for (n = 0; n < num_bond[j]; n++) { + if (bond_type[j][n] == btype && bond_atom[j][n] == tagi) { + bflag = 1; + break; + } + } + if (bflag) continue; + + // Add bonds to owned atoms + // If newton bond, add to both, otherwise add to whichever has a smaller tag + if (i < nlocal && (!newton_bond || tagi < tagj)) { + if (num_bond[i] == atom->bond_per_atom) + error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/oxidation for atom {}", tagi); + bond_type[i][num_bond[i]] = btype; + bond_atom[i][num_bond[i]] = tagj; + num_bond[i]++; + } + + if (j < nlocal && (!newton_bond || tagj < tagi)) { + if (num_bond[j] == atom->bond_per_atom) + error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/oxidation for atom {}", tagj); + bond_type[j][num_bond[j]] = btype; + bond_atom[j][num_bond[j]] = tagi; + num_bond[j]++; + } + } + } +} diff --git a/src/RHEO/fix_rheo_oxidation.h b/src/RHEO/fix_rheo_oxidation.h new file mode 100644 index 0000000000..4c81605611 --- /dev/null +++ b/src/RHEO/fix_rheo_oxidation.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS +// clang-format off +FixStyle(rheo/oxidation,FixRHEOOxidation) +// clang-format on +#else + +#ifndef LMP_FIX_RHEO_OXIDATION_H +#define LMP_FIX_RHEO_OXIDATION_H + +#include "fix.h" + +#include + +namespace LAMMPS_NS { + +class FixRHEOOxidation : public Fix { + public: + FixRHEOOxidation(class LAMMPS *, int, char **); + ~FixRHEOOxidation() override; + int setmask() override; + void init() override; + void init_list(int, class NeighList *) override; + void post_integrate() override; + + private: + int btype; + double cut, cutsq; + class NeighList *list; + + //class FixBondHistory *fix_bond_history; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 0640dd6827..c6d10bcc79 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -271,7 +271,12 @@ void FixRHEOThermal::init() req->set_cutoff(cut_kernel); // find instances of bond history to delete data + // skip history for shell, only exception histories = modify->get_fix_by_style("BOND_HISTORY"); + if (n_histories > 0) + for (int i = 0; i < histories.size(); i++) + if (strcmp(histories[i]->id, "HISTORY_RHEO_SHELL") == 0) + histories.erase(histories.begin() + i); n_histories = histories.size(); } } @@ -644,6 +649,8 @@ double FixRHEOThermal::calc_cv(int i, int itype) if (cv_style[itype] == CONSTANT) { return cv[itype]; } + + return 0.0; } /* ---------------------------------------------------------------------- */ @@ -653,6 +660,8 @@ double FixRHEOThermal::calc_Tc(int i, int itype) if (Tc_style[itype] == CONSTANT) { return Tc[itype]; } + + return 0.0; } /* ---------------------------------------------------------------------- */ @@ -662,6 +671,8 @@ double FixRHEOThermal::calc_L(int i, int itype) if (L_style[itype] == CONSTANT) { return L[itype]; } + + return 0.0; } /* ---------------------------------------------------------------------- */ diff --git a/src/bond_hybrid.cpp b/src/bond_hybrid.cpp index 4e477ab3a6..5f84db1886 100644 --- a/src/bond_hybrid.cpp +++ b/src/bond_hybrid.cpp @@ -259,8 +259,13 @@ void BondHybrid::flags() if (styles[m]) comm_forward = MAX(comm_forward, styles[m]->comm_forward); if (styles[m]) comm_reverse = MAX(comm_reverse, styles[m]->comm_reverse); if (styles[m]) comm_reverse_off = MAX(comm_reverse_off, styles[m]->comm_reverse_off); + if (styles[m]) partial_flag = MAX(partial_flag, styles[m]->partial_flag); } + for (m = 0; m < nstyles; m++) + if (styles[m]->partial_flag != partial_flag) + error->all(FLERR, "Cannot hybridize bond styles with different topology settings"); + init_svector(); } From 7ea0dc3996db3e9315d06fae83162ec2990ad114 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 29 Mar 2024 19:00:14 -0600 Subject: [PATCH 073/385] Adding more oxidation features + doc pages --- doc/src/Howto_rheo.rst | 99 +++++++++++++++++++++- doc/src/Packages_details.rst | 36 ++++++++ doc/src/Packages_list.rst | 5 ++ doc/src/fix_rheo.rst | 108 ++++++++++++++++++++---- doc/src/pair_rheo.rst | 26 +++++- src/RHEO/atom_vec_rheo.cpp | 2 +- src/RHEO/atom_vec_rheo_thermal.cpp | 2 +- src/RHEO/bond_rheo_shell.cpp | 80 ++++++++++++++++++ src/RHEO/bond_rheo_shell.h | 6 ++ src/RHEO/compute_rheo_grad.cpp | 2 +- src/RHEO/compute_rheo_kernel.cpp | 2 +- src/RHEO/compute_rheo_property_atom.cpp | 7 +- src/RHEO/compute_rheo_property_atom.h | 3 +- src/RHEO/compute_rheo_rho_sum.cpp | 5 ++ src/RHEO/compute_rheo_vshift.cpp | 2 + src/RHEO/fix_rheo.cpp | 2 +- src/RHEO/fix_rheo.h | 1 + src/RHEO/fix_rheo_oxidation.cpp | 29 ++++++- src/RHEO/fix_rheo_oxidation.h | 3 + src/RHEO/fix_rheo_pressure.cpp | 2 +- src/RHEO/fix_rheo_thermal.cpp | 35 +++++--- src/RHEO/fix_rheo_viscosity.cpp | 2 +- src/RHEO/pair_rheo.cpp | 2 +- src/RHEO/pair_rheo_solid.cpp | 5 ++ 24 files changed, 423 insertions(+), 43 deletions(-) diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index c55631455b..146716ba18 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -1,4 +1,99 @@ Reproducing hydrodynamics and elastic objects (RHEO) -====================== +==================================================== -Text +The RHEO package is built around an implementation of smoothed particle +hydrodynamics (SPH) coupled to the :doc:`BPM package ` to model +solid elements of a system. The SPH solver supports many advanced options +including reproducing kernels, particle shifting, free surface identification, +and solid surface reconstruction. To model fluid-solid systems, the status of +particles can dynamically change between a fluid and solid state, e.g. during +melting/solidification, which determines how they interact and their physical +behavior. The package is designed with modularity in mind, so one can easily +turn various features on/off, adjust physical details of the system, or +develop new capabilities. Additional numerical details can be found in +:ref:`(Palermo) ` and :ref:`(Clemmer) `. + +---------- + +At the core of the package is :doc:`fix rheo ` which integrates +particle trajectories and controls many optional features (e.g. the use +of reproducing kernels). In conjunction to fix rheo, one must specify an +instance of :doc:`fix rheo/pressure ` and +:doc:`fix rheo/viscosity ` to define a pressure equation +of state and viscosity model, respectively. Optionally, one can model +a heat equation with :doc:`fix rheo/thermal`, which also allows the user +to specify equations for a particle's thermal conductivity, specific heat, +latent heat, and melting temperature. Fix rheo must be defined prior to all +other RHEO fixes. + +Typically, RHEO requires atom style rheo. In addition to typical atom +properties like positions and forces, particles store a local density, +viscosity, pressure, and status. If thermal evolution is modeled, one must +use atom style rheo/thermal which also include a local temperature and +conductivity. The status variable uses bitmasking to track various +properties of a particle such as its current phase (fluid or solid) and its +location relative to a surface. Many of these properties (and others) can +be easily accessed using +:doc:`compute rheo/property/atom `. + +Fluid interactions, including pressure forces, viscous forces, and heat exchange, +are calculated using :doc:`pair rheo `. Unlike typical pair styles, +pair rheo ignores the :doc:`special bond ` settings. Instead, +it determines whether to calculate forces based on the status of particles: +hydrodynamic forces are only calculated if a fluid particle is involved. + +---------- + +To model elastic objects, there are current two mechanisms in RHEO, one designed +for bulk solid bodies and the other for thin shells. Both mechanisms rely on +overlaying bonds and therefore require a hybrid of atom style bond and rheo +(or rheo/thermal). + +To create an elastic solid body, one has to (a) change the status of constituent +particles to solid (e.g. with the :doc:`set ` command), (b) create bpm +bonds between the particles (see the :doc:`bpm howto ` page for +more details), and (c) use :doc:`pair rheo/solid ` to +apply repulsive contact forces between distinct solid bodies. Akin to pair rheo, +looks at a particles fluid/solid status to determine whether to apply forces. +However, unlike pair rheo, pair rheo/solid does obey special bond settings such +that contact forces do not have to be calculated between two bonded solid particles +in the same elastic body. + +In systems with thermal evolution, fix rheo/thermal can optionally set a +melting/solidification temperature allowing particles to dynamically swap their +state between fluid and solid. Using the *react* option, one can specify a maximum +bond length and a bond type. Then, when solidifying, particles will search their +local neighbors and automatically create bonds with any neighboring solid particles +in range. For BPM bond styles, bonds will then use the immediate position of the two +particles to calculate a reference state. When melting, particles will then delete +any bonds of the specified type when reverting to a fluid state. Special bonds are +updated as bonds are created/broken. + +The other option for elastic objects is an elastic shell that is nominally much +thinner than a particle diameter, e.g. a oxide skin which gradually forms over time +on the surface of a fluid. Currently, this is implemented using +:doc:`fix rheo/oxidaton ` and bond style +:doc:`rheo/shell `. Essentially, fix rheo/oxidaton creates candidate +bonds of a specified type between surface fluid particles within a specified distance. +a newly created rheo/shell bond will then start a timer. While the timer is counting +down, the bond will delete itself if particles move too far apart or move away from the +surface. However, if the timer reaches a user-defined threshold, then the bond will +activate and apply additional forces to the fluid particles. Bond style rheo/shell +then operates very similarly to a BPM bond style, storing a reference length and +breaking if stretched too far. Unlike the above method, this option does not remove +the underlying fluid interactions (although particle shifting is turned off) and does +not modify special bond settings of particles. + +While these two options are not expected to be appropriate for every multiphase system, +either framework can be modified to create more suitable models (e.g. by changing the +criteria for creating/deleting a bond or altering force calculations). + +---------- + +.. _howto-howto_rheo_palermo: + +**(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. + +.. _howto-howto_rheo_clemmer: + +**(Clemmer)** Clemmer, Pierce, O'Connor, Nevins, Jones, Lechman, Tencer, Appl. Math. Model., 130, 310-326 (2024). diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index a3d65d9d65..39a9deef63 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -101,6 +101,7 @@ page gives those details. * :ref:`QEQ ` * :ref:`QMMM ` * :ref:`QTB ` + * :ref:`RHEO ` * :ref:`REACTION ` * :ref:`REAXFF ` * :ref:`REPLICA ` @@ -2571,6 +2572,41 @@ another set. ---------- +.. _PKG-RHEO: + +RHEO package +------------ + +**Contents:** + +Pair styles, bond styles, fixes, and computes for reproducing +hydrodynamics and elastic objects. See the +:doc:`Howto rheo ` page for an overview. + +**Authors:** Joel T. Clemmer (Sandia National Labs), +Thomas C. O'Connor (Carnegie Mellon University) + +.. versionadded:: TBD + +**Supporting info:** + +* src/RHEO filenames -> commands +* :doc:`Howto_rheo ` +* :doc:`atom_style rheo ` +* :doc:`atom_style rheo/thermal ` +* :doc:`bond_style rheo/shell ` +* :doc:`compute rheo/property/atom ` +* :doc:`fix rheo ` +* :doc:`fix rheo/oxidation ` +* :doc:`fix rheo/pressure ` +* :doc:`fix rheo/thermal ` +* :doc:`fix rheo/viscosity ` +* :doc:`pair_style rheo ` +* :doc:`pair_style rheo/solid ` +* examples/rheo + +---------- + .. _PKG-RIGID: RIGID package diff --git a/doc/src/Packages_list.rst b/doc/src/Packages_list.rst index c0a1164513..4e1d32385f 100644 --- a/doc/src/Packages_list.rst +++ b/doc/src/Packages_list.rst @@ -403,6 +403,11 @@ whether an extra library is needed to build and use the package: - :doc:`fix qtb ` :doc:`fix qbmsst ` - qtb - no + * - :ref:`RHEO ` + - reproducing hydrodynamics and elastic objects + - :doc:`Howto rheo ` + - rheo + - no * - :ref:`REACTION ` - chemical reactions in classical MD - :doc:`fix bond/react ` diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index c61d1939db..76d4ae3972 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -8,40 +8,107 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo cut kstyle keyword values... + fix ID group-ID rheo cut kstyle zmin keyword values... * ID, group-ID are documented in :doc:`fix ` command * rheo = style name of this fix command -* cut = *quintic* or *RK0* or *RK1* or *RK2* +* cut = cutoff for the kernel (distance) +* kstyle = *quintic* or *RK0* or *RK1* or *RK2* +* zmin = minimal number of neighbors for reproducing kernels * zero or more keyword/value pairs may be appended to args -* keyword = *shift* or *thermal* or *surface/detection* or *interface/reconstruction* or - *rho/sum* or *density* or *sound/squared* +* keyword = *thermal* or *interface/reconstruct* or *surface/detection* or + *shift* or *rho/sum* or *density* or *speed/sound* .. parsed-literal:: - *shift* values = none, turns on velocity shifting *thermal* values = none, turns on thermal evolution + *interface/reconstruct* values = none, reconstructs interfaces with solid particles *surface/detection* values = *sdstyle* *limit* *limit/splash* *sdstyle* = *coordination* or *divergence* - *limit* = threshold for surface particles (unitless) - *limit/splash* = threshold for splash particles (unitless) - *interface/reconstruct* values = none, reconstructs interfaces with solid particles + *limit* = threshold for surface particles + *limit/splash* = threshold for splash particles + *shift* values = none, turns on velocity shifting *rho/sum* values = none, uses the kernel to compute the density of particles - *density* values = *rho0* (density) - *sound/squared* values = *csq* (velocity\^2) + *density* values = *rho01*, ... *rho0N* (density) + *speed/sound* values = *cs0*, ... *csN* (velocity) Examples """""""" .. code-block:: LAMMPS - fix 1 all rheo 1.0 quintic thermal density 0.1 sound/squared 10.0 + fix 1 all rheo 1.0 quintic thermal density 0.1 speed/sound 10.0 fix 1 all rheo 1.0 RK1 shift surface/detection coordination 40 Description """"""""""" -Fix description... +Perform time integration for RHEO particles, updating positions, velocities, +and densities. For a detailed breakdown of the integration timestep and +numerical details, see :ref:`(Palermo) `. For an +overview of other features available in the RHEO package, see +:doc:`the RHEO howto `. + +The type of kernel is specified using *kstyle* and the cutoff is *cut*. Four +kernels are currently available. The *quintic* kernel is a standard quintic +spline function commonly used in SPH. The other options, *RK0*, *RK1*, and +*RK2*, are zeroth, first, and second order reproducing. To generate a reproducing kernel, a particle must have sufficient neighbors inside the +kernel cutoff distance (a coordination number) to accurately calculate +moments. This threshold is set by *zmin*. If reproducing kernels are +requested but a particle has fewer neighbors, then it will revert to a +non-reproducing quintic kernel until it gains more neighbors. + +To model temperature evolution, one must specify the *thermal* keyword, +define a separate instance of :doc:`fix rheo/thermal `, +and use atom style rheo/thermal. + +By default, the density of solid RHEO particles does not evolve and forces +with fluid particles are calculated using the current velocity of the solid +particle. If the *interface/reconstruct* keyword is used, then the density +and velocity of solid particles are alternatively reconstructed for every +fluid-solid interaction to ensure no-slip and pressure-balanced boundaries. +This is done by estimating the location of the fluid-solid interface and +extrapolating fluid particle properties across the interface to calculate a +temporary apparent density and velocity for a solid particle. The numerical +details are the same as those described in +:ref:`(Palermo) ` except there is an additional +restriction that the reconstructed solid density cannot be less than the +equilibrium density. This prevents fluid particles from sticking to solid +surfaces. + +A modified form of Fickian particle shifting can be enabled with the +*shift* keyword. This effectively shifts particle positions to generate a +more uniform spatial distribution. In systems with free surfaces, the +*surface/detection* keyword can be used to classify the location of +particles as being within the bulk fluid, on a free surface, or isolated +from other particles in a splash or droplet. Shifting is then disabled in +the direction away from the free surface to prevent it from diffusing +particles away from the bulk fluid. Surface detection can also be used +to control surface-nucleated effects like oxidation when used in combination +with :doc:`fix rheo/oxidation `. + +The *surface/detection* keyword takes three arguments: *sdstyle*, *limit*, +and *limi/splash*. The first, *sdstyle*, specifies whether surface particles +are identified using a coordination number (*coordination*) or the divergence +of the local particle positions (*divergence*). The threshold value for a +surface particle for either of these criteria is set by the numerical value +of *limit*. Additionally, if a particle's coordination number is too low, +i.e. if it has separated off from the bulk in a droplet, it is not possible +to define surfaces and a particle is classified as a splash. The coordination +threshold for this classification is set by the numerical value of +*limit/splash*. + +By default, RHEO integrates particles' densities using a mass diffusion +equation. Alternatively, one can update densities every timestep by performing +a kernel summation of the masses of neighboring particles by specifying the *rho/sum* keyword. + +The *density* is used to specify the equilbrium density of each of the N +particle types. It must be followed by N numerical values specifying each +type's equilibrium density *rho0*. + +The *density* is used to specify the speed of sound of each of the N particle +types. It must be followed by N numerical values specifying each type's speed +of sound *cs*. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -55,13 +122,14 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" -This fix must be used with an atom style that includes density -such as atom_style rheo or rheo/thermal. This fix must be used in -conjuction with :doc:`fix rheo/pressure `. and +This fix must be used with atom style rheo or rheo/thermal. +This fix must be used in conjuction with +:doc:`fix rheo/pressure `. and :doc:`fix rheo/viscosity `, If the *thermal* setting is used, there must also be an instance of :doc:`fix rheo/thermal `. The fix group must be -set to all. +set to all. Only one instance of fix rheo may be defined and it +must be defined prior to all other RHEO fixes. This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. @@ -78,4 +146,10 @@ Related commands Default """"""" -*rho0* and *csq* are set to 1.0. +*rho0* and *cs* are set to 1.0 for all atom types. + +---------- + +.. _howto-howto_rheo_palermo: + +**(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst index 6f706a77ac..f6c3d9e3ba 100644 --- a/doc/src/pair_rheo.rst +++ b/doc/src/pair_rheo.rst @@ -16,8 +16,8 @@ Syntax .. parsed-literal:: - *rho/damp* args = density damping prefactor :math:`\xi` (units?) - *artificial/visc* args = artificial viscosity prefactor :math:`\zeta` (units?) + *rho/damp* args = density damping prefactor :math:`\xi` + *artificial/visc* args = artificial viscosity prefactor :math:`\zeta` *harmonic/means* args = none Examples @@ -31,7 +31,27 @@ Examples Description """"""""""" -pair style... +Pair style *rheo* computes pressure and viscous forces between particles +in the :doc:`rheo package `. If thermal evolution is turned +on in :doc:`fix rheo `, then the pair style also calculates +heat exchanged between particles. + +The *artificial/viscosity* keyword is used to specify the magnitude +:math:`\zeta` of an optional artificial viscosity contribution to forces. +This factor can help stabilize simulations by smoothing out small length +scale variations in velocity fields. + +The *rho/damp* keyword is used to specify the magnitude :math:`\xi` of +an optional pairwise damping term between the density of particles. This +factor can help stabilize simulations by smoothing out small length +scale variations in density fields. + +If particles have different viscosities or conductivities, the +*harmonic/means* keyword changes how they are averaged before calculating +pairwise forces or heat exchanges. By default, an arithmetic averaged is +used, however, a harmonic mean may improve stability in multiphase systems +with large disparities in viscosities. This keyword has no effect on +results if viscosities and conductivities are constant. No coefficients are defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp index ec44a230ec..843269a717 100644 --- a/src/RHEO/atom_vec_rheo.cpp +++ b/src/RHEO/atom_vec_rheo.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL) ----------------------------------------------------------------------- */ #include "atom_vec_rheo.h" diff --git a/src/RHEO/atom_vec_rheo_thermal.cpp b/src/RHEO/atom_vec_rheo_thermal.cpp index 26394c9175..7174d4cb66 100644 --- a/src/RHEO/atom_vec_rheo_thermal.cpp +++ b/src/RHEO/atom_vec_rheo_thermal.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL) ----------------------------------------------------------------------- */ #include "atom_vec_rheo_thermal.h" diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index 6a9f99d8b1..6a71136d9d 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL) +----------------------------------------------------------------------- */ + #include "bond_rheo_shell.h" #include "atom.h" @@ -40,17 +45,38 @@ BondRHEOShell::BondRHEOShell(LAMMPS *_lmp) : BondBPM(_lmp), k(nullptr), ecrit(nullptr), gamma(nullptr) { partial_flag = 1; + comm_reverse = 1; tform = rmax = -1; single_extra = 1; svector = new double[1]; + + // For nbond, create an instance of fix property atom + // Need restarts + exchanging with neighbors since it needs to persist + // between timesteps (fix property atom will handle callbacks) + + int tmp1, tmp2; + index_nb = atom->find_custom("shell_nbond", tmp1, tmp2); + if (index_nb == -1) { + id_fix = utils::strdup("bond_rheo_shell_fix_property_atom"); + modify->add_fix(fmt::format("{} all property/atom i_shell_nbond", id_fix)); + index_nb = atom->find_custom("shell_nbond", tmp1, tmp2); + } + nbond = atom->ivector[index_nb]; + + //Store non-persistent per atom quantities, intermediate + + nmax_store = atom->nmax; + memory->create(dbond, nmax_store, "rheo/react:dbond"); } /* ---------------------------------------------------------------------- */ BondRHEOShell::~BondRHEOShell() { + if (modify->nfix) modify->delete_fix(id_fix); + delete[] id_fix; delete[] svector; if (allocated) { @@ -59,6 +85,8 @@ BondRHEOShell::~BondRHEOShell() memory->destroy(ecrit); memory->destroy(gamma); } + + memory->destroy(dbond); } /* ---------------------------------------------------------------------- @@ -151,6 +179,15 @@ void BondRHEOShell::compute(int eflag, int vflag) double **bondstore = fix_bond_history->bondstore; + if (atom->nmax > nmax_store){ + nmax_store = atom->nmax; + memory->destroy(dbond); + memory->create(dbond, nmax_store, "rheo/shell:dbond"); + } + + size_t nbytes = nmax_store * sizeof(int); + memset(&dbond[0], 0, nbytes); + for (n = 0; n < nbondlist; n++) { // skip bond if already broken @@ -196,6 +233,8 @@ void BondRHEOShell::compute(int eflag, int vflag) if (bondstore[n][1] >= tform) { bondstore[n][0] = r; r0 = r; + if (newton_bond || i1 < nlocal) dbond[i1] ++; + if (newton_bond || i2 < nlocal) dbond[i2] ++; } else { continue; } @@ -205,6 +244,8 @@ void BondRHEOShell::compute(int eflag, int vflag) if (fabs(e) > ecrit[type]) { bondlist[n][2] = 0; process_broken(i1, i2); + if (newton_bond || i1 < nlocal) dbond[i1] --; + if (newton_bond || i2 < nlocal) dbond[i2] --; continue; } @@ -233,6 +274,17 @@ void BondRHEOShell::compute(int eflag, int vflag) if (evflag) ev_tally(i1, i2, nlocal, newton_bond, 0.0, fbond, delx, dely, delz); } + + + // Communicate changes in nbond + if (newton_bond) comm->reverse_comm(this); + + for(i = 0; i < nlocal; i++) { + nbond[i] += dbond[i]; + + // If it has bonds, no shifting + if (nbond[i] != 0) status[i] |= STATUS_NO_SHIFT; + } } /* ---------------------------------------------------------------------- */ @@ -419,6 +471,34 @@ void BondRHEOShell::read_restart_settings(FILE *fp) MPI_Bcast(&rmax, 1, MPI_DOUBLE, 0, world); } + +/* ---------------------------------------------------------------------- */ + +int BondRHEOShell::pack_reverse_comm(int n, int first, double *buf) +{ + int i, m, last; + m = 0; + last = first + n; + + for (i = first; i < last; i++) { + buf[m++] = dbond[i]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void BondRHEOShell::unpack_reverse_comm(int n, int *list, double *buf) +{ + int i, j, m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + dbond[j] += buf[m++]; + } +} + /* ---------------------------------------------------------------------- */ double BondRHEOShell::single(int type, double rsq, int i, int j, double &fforce) diff --git a/src/RHEO/bond_rheo_shell.h b/src/RHEO/bond_rheo_shell.h index 562be6d9a6..513d481eeb 100644 --- a/src/RHEO/bond_rheo_shell.h +++ b/src/RHEO/bond_rheo_shell.h @@ -37,12 +37,18 @@ class BondRHEOShell : public BondBPM { void read_restart(FILE *) override; void write_restart_settings(FILE *) override; void read_restart_settings(FILE *) override; + int pack_reverse_comm(int, int, double *) override; + void unpack_reverse_comm(int, int *, double *) override; double single(int, double, int, int, double &) override; protected: double *k, *ecrit, *gamma; double tform, rmax; + int *dbond, *nbond; + int index_nb, nmax_store; + char *id_fix; + void process_ineligibility(int, int); void allocate(); void store_data(); diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index acfc01d793..5ed43a421a 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL), Thomas O'Connor (CMU) ----------------------------------------------------------------------- */ #include "compute_rheo_grad.h" diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 6f58d79243..bd16a89b6a 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL), Thomas O'Connor (CMU) ----------------------------------------------------------------------- */ #include "compute_rheo_kernel.h" diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 380ff398d8..2d6ff1e55a 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -56,7 +56,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; - pressure_flag = thermal_flag = interface_flag = surface_flag = shift_flag = 0; + pressure_flag = thermal_flag = interface_flag = surface_flag = shift_flag = shell_flag = 0; // parse input values // customize a new keyword by adding to if statement @@ -112,6 +112,9 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a arg[iarg], atom->get_style()); pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; thermal_flag = 1; + } else if (strcmp(arg[iarg],"nbond/shell") == 0) { + shell_flag = 1; + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_nbond_shell; } else { avec_index[i] = atom->avec->property_atom(arg[iarg]); if (avec_index[i] < 0) @@ -156,6 +159,8 @@ void ComputeRHEOPropertyAtom::init() error->all(FLERR, "Cannot request velocity shifting property without corresponding option in fix rheo"); if (thermal_flag && !(fix_rheo->thermal_flag)) error->all(FLERR, "Cannot request thermal property without fix rheo/thermal"); + if (shell_flag && !(fix_rheo->oxidation_flag)) + error->all(FLERR, "Cannot request number of shell bonds without fix rheo/oxidation"); compute_interface = fix_rheo->compute_interface; compute_kernel = fix_rheo->compute_kernel; diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index f3596fbbf9..fd73b5883f 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -34,7 +34,7 @@ class ComputeRHEOPropertyAtom : public Compute { private: int nvalues, nmax; - int pressure_flag, thermal_flag, interface_flag, surface_flag, shift_flag; + int pressure_flag, thermal_flag, interface_flag, surface_flag, shift_flag, shell_flag; int *avec_index; int *col_index; double *buf; @@ -54,6 +54,7 @@ class ComputeRHEOPropertyAtom : public Compute { void pack_shift_v(int); void pack_gradv(int); void pack_pressure(int); + void pack_nbond_shell(int); void pack_atom_style(int); int get_vector_index(char*); diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp index 82d3aa4bc6..8322ad4ad4 100644 --- a/src/RHEO/compute_rheo_rho_sum.cpp +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL) +----------------------------------------------------------------------- */ + #include "compute_rheo_rho_sum.h" #include "atom.h" diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 569c8569f7..533287911a 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -147,6 +147,8 @@ void ComputeRHEOVShift::compute_peratom() fluidj = !(status[j] & PHASECHECK); if ((!fluidi) && (!fluidj)) continue; + + // Will skip shifting in FixRHEO initial integrate, but also skip here to save time if ((status[i] & STATUS_NO_SHIFT) && (status[j] & STATUS_NO_SHIFT)) continue; dx[0] = xtmp - x[j][0]; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index beba940174..b0cb1513fc 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -221,7 +221,7 @@ void FixRHEO::setup_pre_force(int /*vflag*/) { // Check to confirm accessory fixes do not preceed FixRHEO // Note: fixes set this flag in setup_pre_force() - if (viscosity_fix_defined || pressure_fix_defined || thermal_fix_defined) + if (viscosity_fix_defined || pressure_fix_defined || thermal_fix_defined || oxidation_fix_defined) error->all(FLERR, "Fix RHEO must be defined before all other RHEO fixes"); // Calculate surfaces diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 8ec28c7d0e..33fd0084db 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -55,6 +55,7 @@ class FixRHEO : public Fix { int viscosity_fix_defined; int pressure_fix_defined; int thermal_fix_defined; + int oxidation_fix_defined; class ComputeRHEOGrad *compute_grad; class ComputeRHEOKernel *compute_kernel; diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index bd7babedbb..1628cef13f 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -60,6 +60,7 @@ FixRHEOOxidation::~FixRHEOOxidation() int FixRHEOOxidation::setmask() { int mask = 0; + mask |= PRE_FORCE; mask |= POST_INTEGRATE; return mask; } @@ -70,7 +71,7 @@ void FixRHEOOxidation::init() { auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/oxidation"); - class FixRHEO *fix_rheo = dynamic_cast(fixes[0]); + fix_rheo = dynamic_cast(fixes[0]); double cut_kernel = fix_rheo->h; if (cut > cut_kernel) @@ -102,6 +103,26 @@ void FixRHEOOxidation::init_list(int /*id*/, NeighList *ptr) /* ---------------------------------------------------------------------- */ +void FixRHEOOxidation::setup_pre_force(int /*vflag*/) +{ + // Not strictly required that this fix be after FixRHEO, + // but enforce to be consistent with other RHEO fixes + fix_rheo->oxidation_fix_defined = 1; + + if (!fix_rheo->surface_flag) error->all(FLERR, + "fix rheo/oxidation requires surface calculation in fix rheo"); + + pre_force(0); +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOThermal::pre_force(int /*vflag*/) +{ +} + +/* ---------------------------------------------------------------------- */ + void FixRHEOOxidation::post_integrate() { int i, j, n, ii, jj, inum, jnum, bflag; @@ -187,4 +208,10 @@ void FixRHEOOxidation::post_integrate() } } } + + //todo: + // allow option to create near-surface bonds + // extract # of bonds in property/atom + // check bond style shell used, get index to bonds, share with compute property atom + // add type option to compute nbond/atom } diff --git a/src/RHEO/fix_rheo_oxidation.h b/src/RHEO/fix_rheo_oxidation.h index 4c81605611..ca36a6fdf9 100644 --- a/src/RHEO/fix_rheo_oxidation.h +++ b/src/RHEO/fix_rheo_oxidation.h @@ -33,6 +33,8 @@ class FixRHEOOxidation : public Fix { int setmask() override; void init() override; void init_list(int, class NeighList *) override; + void setup_pre_force(int) override; + void pre_force(int) override; void post_integrate() override; private: @@ -40,6 +42,7 @@ class FixRHEOOxidation : public Fix { double cut, cutsq; class NeighList *list; + class FixRHEO *fix_rheo; //class FixBondHistory *fix_bond_history; }; diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index 8c523b2b35..d6dea8aa1a 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL), Thomas O'Connor (CMU) ----------------------------------------------------------------------- */ #include "fix_rheo_pressure.h" diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index c6d10bcc79..7d9aff5424 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -498,21 +498,36 @@ void FixRHEOThermal::break_bonds() int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - // Rapidly delete all bonds for local atoms that melt (no shifting) + // Rapidly delete all bonds for local atoms that melt of a given type for (int i = 0; i < nlocal; i++) { if (!(status[i] & STATUS_MELTING)) continue; - for (m = 0; m < num_bond[i]; m++) { - j = atom->map(bond_atom[i][m]); - bond_type[i][m] = 0; + for (m = (num_bond[i] - 1); m >= 0; m--) { + if (bond_type[i][m] != btype) continue; - if (n_histories > 0) - for (auto &ihistory: histories) - dynamic_cast(ihistory)->delete_history(i, m); + j = atom->map(bond_atom[i][m]); + + nmax = num_bond[i] - 1; + if (m == nmax) { + if (n_histories > 0) + for (auto &ihistory: histories) + dynamic_cast(ihistory)->delete_history(i, m); + } else { + bond_type[i][m] = bond_type[i][nmax]; + bond_atom[i][m] = bond_atom[i][nmax]; + if (n_histories > 0) { + for (auto &ihistory: histories) { + auto fix_bond_history = dynamic_cast (ihistory); + fix_bond_history->shift_history(i, m, nmax); + fix_bond_history->delete_history(i, nmax); + } + } + } + bond_type[i][nmax] = 0; + num_bond[i]--; if (fix_update_special_bonds) fix_update_special_bonds->add_broken_bond(i, j); } - num_bond[i] = 0; } // Update bond list and break solid-melted bonds @@ -530,7 +545,7 @@ void FixRHEOThermal::break_bonds() // Delete bonds for non-melted local atoms (shifting) if (i < nlocal) { for (m = 0; m < num_bond[i]; m++) { - if (bond_atom[i][m] == tag[j]) { + if (bond_atom[i][m] == tag[j] && bond_type[i][m] == btype) { nmax = num_bond[i] - 1; bond_type[i][m] = bond_type[i][nmax]; bond_atom[i][m] = bond_atom[i][nmax]; @@ -549,7 +564,7 @@ void FixRHEOThermal::break_bonds() if (j < nlocal) { for (m = 0; m < num_bond[j]; m++) { - if (bond_atom[j][m] == tag[i]) { + if (bond_atom[j][m] == tag[i] && bond_type[j][m] == btype) { nmax = num_bond[j] - 1; bond_type[j][m] = bond_type[j][nmax]; bond_atom[j][m] = bond_atom[j][nmax]; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 2fffa8b29c..abaa55ca70 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL), Thomas O'Connor (CMU) ----------------------------------------------------------------------- */ #include "fix_rheo_viscosity.h" diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index b07e914af1..fe5a1d6dec 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: - Joel Clemmer (SNL), Thomas O'Connor (CMU), Eric Palermo (CMU) + Joel Clemmer (SNL), Thomas O'Connor (CMU) ----------------------------------------------------------------------- */ #include "pair_rheo.h" diff --git a/src/RHEO/pair_rheo_solid.cpp b/src/RHEO/pair_rheo_solid.cpp index d0a68d5230..f6dcd95879 100644 --- a/src/RHEO/pair_rheo_solid.cpp +++ b/src/RHEO/pair_rheo_solid.cpp @@ -11,6 +11,11 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Joel Clemmer (SNL) +----------------------------------------------------------------------- */ + #include "pair_rheo_solid.h" #include "atom.h" From 08db64c27fbe30b5dd2ab342f5606cdfeb73697b Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 31 Mar 2024 21:40:34 -0600 Subject: [PATCH 074/385] More updates for oxidation, more doc pages --- doc/src/compute_nbond_atom.rst | 13 ++++++- doc/src/fix_rheo_pressure.rst | 45 ++++++++++++++++++---- doc/src/fix_rheo_thermal.rst | 51 +++++++++++++++---------- doc/src/fix_rheo_viscosity.rst | 44 +++++++++++---------- src/BPM/compute_nbond_atom.cpp | 16 +++++++- src/BPM/compute_nbond_atom.h | 2 +- src/RHEO/bond_rheo_shell.cpp | 17 ++++++++- src/RHEO/bond_rheo_shell.h | 2 + src/RHEO/compute_rheo_property_atom.cpp | 23 ++++++++++- src/RHEO/compute_rheo_property_atom.h | 1 + src/RHEO/fix_rheo.cpp | 3 ++ src/RHEO/fix_rheo.h | 1 + src/RHEO/fix_rheo_oxidation.cpp | 42 ++++++++++---------- src/RHEO/fix_rheo_oxidation.h | 7 ++-- 14 files changed, 188 insertions(+), 79 deletions(-) diff --git a/doc/src/compute_nbond_atom.rst b/doc/src/compute_nbond_atom.rst index f438836534..274d958a10 100644 --- a/doc/src/compute_nbond_atom.rst +++ b/doc/src/compute_nbond_atom.rst @@ -8,10 +8,17 @@ Syntax .. code-block:: LAMMPS - compute ID group-ID nbond/atom + compute ID group-ID nbond/atom keyword value * ID, group-ID are documented in :doc:`compute ` command * nbond/atom = style name of this compute command +* zero or more keyword/value pairs may be appended +* keyword = *bond/type* + + .. parsed-literal:: + + *bond/type* value = *btype* + *btype* = bond type included in count Examples """""""" @@ -19,6 +26,7 @@ Examples .. code-block:: LAMMPS compute 1 all nbond/atom + compute 1 all nbond/atom bond/type 2 Description """"""""""" @@ -31,6 +39,9 @@ the :doc:`Howto broken bonds ` page for more information. The number of bonds will be zero for atoms not in the specified compute group. This compute does not depend on Newton bond settings. +If the keyword *bond/type* is specified, only bonds of *btype* are +counted. + Output info """"""""""" diff --git a/doc/src/fix_rheo_pressure.rst b/doc/src/fix_rheo_pressure.rst index d31c305c20..2edd703299 100644 --- a/doc/src/fix_rheo_pressure.rst +++ b/doc/src/fix_rheo_pressure.rst @@ -8,12 +8,13 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo/pressure style args + fix ID group-ID rheo/pressure type1 pstyle1 args1 ... typeN pstyleN argsN * ID, group-ID are documented in :doc:`fix ` command * rheo/pressure = style name of this fix command +* one or more types and pressure styles must be appended * types = lists of types (see below) -* style = *linear* or *taitwater* or *cubic* +* pstyle = *linear* or *taitwater* or *cubic* .. parsed-literal:: @@ -32,10 +33,41 @@ Examples Description """"""""""" -This fix... +This fix defines a pressure equation of state for RHEO particles. One can +define different equations of state for different atom types, but an +equation must be specified for every atom type. -Only one instance of fix rheo/pressure can be defined and the fix group must be set to all. +One first defines the atom *types*. A wild-card asterisk can be used in place +of or in conjunction with the *types* argument to set the coefficients for +multiple pairs of atom types. This takes the form "\*" or "\*n" or "m\*" +or "m\*n". If :math:`N` is the number of atom types, then an asterisk with +no numeric values means all types from 1 to :math:`N`. A leading asterisk +means all types from 1 to n (inclusive). A trailing asterisk means all types +from m to :math:`N` (inclusive). A middle asterisk means all types from m to n +(inclusive). +The *types* definition is followed by the pressure style, *pstyle*. Current +options *linear*, *taitwater*, and *cubic*. Style *linear* is a linear +equation of state with a particle pressure :math:`P` calculated as + +.. math:: + + P = c (\rho - \rho_0) + +where :math:`c` is the speed of sound, :math:`\rho_0` is the equilibrium density, +and :math:`\rho` is the current density of a particle. The numerical values of +:math:`c` and :math:`\rho_0` are set in :doc:`fix rheo `. Style *cubic* +is a cubic equation of state which has an extra argument :math:`A_3`, + +.. math:: + + P = c ((\rho - \rho_0) + A_3 (\rho - \rho_0)^3) . + +Style *taitwater* is Tait's equation of state: + +.. math:: + + P = \frac{c^2 \rho_0}{7} \biggl[\left(\frac{\rho}{\rho_0}\right)^{7} - 1\biggr]. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -52,7 +84,7 @@ Restrictions This fix must be used with an atom style that includes density such as atom_style rheo or rheo/thermal. This fix must be used in conjuction with :doc:`fix rheo `. The fix group must be -set to all. +set to all. Only one instance of fix rheo/pressure can be defined. This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. @@ -60,8 +92,7 @@ LAMMPS was built with that package. See the :doc:`Build package Related commands """""""""""""""" -:doc:`fix rheo/viscosity `, -:doc:`fix rheo/thermal `, +:doc:`fix rheo `, :doc:`pair rheo `, :doc:`compute rheo/property/atom ` diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index b73aeb248e..2ece5521bc 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -48,26 +48,38 @@ Examples Description """"""""""" -This fix... +This fix performs time integration of temperature evolution for atom style +rheo/thermal. In addition, it defines multiple thermal properties of +particles and handles melting/solidification, if applicable. For more details +on phase transitions in RHEO, see :doc:`the RHEO howto `. -Each list consists of a series of type -ranges separated by commas. The range can be specified as a -single numeric value, or a wildcard asterisk can be used to specify a range -of values. This takes the form "\*" or "\*n" or "n\*" or "m\*n". For -example, if M = the number of atom types, then an asterisk with no numeric -values means all types from 1 to M. A leading asterisk means all types -from 1 to n (inclusive). A trailing asterisk means all types from n to M -(inclusive). A middle asterisk means all types from m to n (inclusive). -Note that all atom types must be included in exactly one of the N collections. +For each atom type, one can define attributes for the *conductivity*, +*specific/heat*, *latent/heat*, and critical temperature (*Tfreeze*). +The conductivity and specific heat must be defined for all atom types. +The latent heat and critical temperature are optional. However, a +critical temperature must be defined to specify a latent heat. -While the *Tfreeze* keyword is optional, the *conductivity* and -*specific/heat* keywords are mandatory. +For each property, one must first define a list of atom types. A wild-card +asterisk can be used in place of or in conjunction with the *types* argument +to set the coefficients for multiple pairs of atom types. This takes the +form "\*" or "\*n" or "m\*" or "m\*n". If :math:`N` is the number of atom +types, then an asterisk with no numeric values means all types from 1 to +:math:`N`. A leading asterisk means all types from 1 to n (inclusive). +A trailing asterisk means all types from m to :math:`N` (inclusive). A +middle asterisk means all types from m to n (inclusive). -Multiple instances of this fix may be defined to apply different -properties to different groups. However, the union of fix groups -across all instances of fix rheo/thermal must cover all atoms. -If there are multiple instances of this fix, any intersections in -the fix groups will lead to incorrect thermal integration. +The *types* definition for each property is followed by the style. Currently, +the only option is *constant*. Style *constant* simply applies a constant value +of respective property to each particle of the assigned type. + +The *react* keyword controls whether bonds are created/deleted when particles +transition between a fluid and solid state. This option only applies to atom +types that have a defined value of *Tfreeze*. When a fluid particle's +temperature drops below *Tfreeze*, bonds of type *btype* are created between +nearby solid particles within a distance of *cut*. The particle's status also +swaps to a solid state. When a solid particle's temperature rises above +*Tfreeze*, all bonds of type *btype* are broken and the particle's tatus swaps +to a fluid state. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -84,7 +96,8 @@ Restrictions This fix must be used with an atom style that includes temperature, heatflow, and conductivity such as atom_tyle rheo/thermal This fix must be used in conjuction with :doc:`fix rheo ` with the -*thermal* setting. +*thermal* setting. The fix group must be set to all. Only one +instance of fix rheo/pressure can be defined. This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. @@ -93,8 +106,6 @@ Related commands """""""""""""""" :doc:`fix rheo `, -:doc:`fix rheo/viscosity `, -:doc:`fix rheo/pressure `, :doc:`pair rheo `, :doc:`compute rheo/property/atom ` diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst index 379b002de1..64c6539acc 100644 --- a/doc/src/fix_rheo_viscosity.rst +++ b/doc/src/fix_rheo_viscosity.rst @@ -8,22 +8,18 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo/viscosity types style args ... + fix ID group-ID rheo/viscosity type1 pstyle1 args1 ... typeN pstyleN argsN * ID, group-ID are documented in :doc:`fix ` command * rheo/viscosity = style name of this fix command +* one or more types and viscosity styles must be appended * types = lists of types (see below) -* style = *constant* or *power* +* vstyle = *constant* .. parsed-literal:: - *constant* args = viscosity (mass/(length*time)) - *power* args = *eta* *gd0* *K* *npow* *tau0* - *eta* = (units) - *gd0* = (units) - *K* = (units) - *npow* = (units) - *tau0* = (units) + *constant* args = *eta* + *eta* = viscosity Examples """""""" @@ -31,20 +27,27 @@ Examples .. code-block:: LAMMPS fix 1 all rheo/viscosity * constant 1.0 - fix 1 all rheo/viscosity 1 constant 1.0 2 power 0.1 1e-2 0.5 0.01 + fix 1 all rheo/viscosity 1 constant 1.0 2 constant 2.0 Description """"""""""" -This fix... +This fix defines a viscosity for RHEO particles. One can define different +viscosities for different atom types, but a viscosity must be specified for +every atom type. -Multiple instances of this fix may be defined to apply different -properties to different groups. However, the union of fix groups -across all instances of fix rheo/viscosity must cover all atoms. -If there are multiple instances of this fix, any intersection -between fix groups will cause the viscosity for the affected atoms -to be calculated multiple times. Any such affected atoms will enabled -up with a viscosity calculated by the latest defined fix. +One first defines the atom *types*. A wild-card asterisk can be used in place +of or in conjunction with the *types* argument to set the coefficients for +multiple pairs of atom types. This takes the form "\*" or "\*n" or "m\*" +or "m\*n". If :math:`N` is the number of atom types, then an asterisk with +no numeric values means all types from 1 to :math:`N`. A leading asterisk +means all types from 1 to n (inclusive). A trailing asterisk means all types +from m to :math:`N` (inclusive). A middle asterisk means all types from m to n +(inclusive). + +The *types* definition is followed by the viscosity style, *vstyle*. Currently, +the only option is *constant*. Style *constant* simply applies a constant value +of the viscosity *eta* to each particle of the assigned type. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -60,7 +63,8 @@ Restrictions This fix must be used with an atom style that includes viscosity such as atom_style rheo or rheo/thermal. This fix must be used in -conjuction with :doc:`fix rheo `. +conjuction with :doc:`fix rheo `. The fix group must be +set to all. Only one instance of fix rheo/viscosity can be defined. This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. @@ -69,8 +73,6 @@ Related commands """""""""""""""" :doc:`fix rheo `, -:doc:`fix rheo/pressure `, -:doc:`fix rheo/thermal `, :doc:`pair rheo `, :doc:`compute rheo/property/atom ` diff --git a/src/BPM/compute_nbond_atom.cpp b/src/BPM/compute_nbond_atom.cpp index 4f0fc4c3f0..af1cc2b9bc 100644 --- a/src/BPM/compute_nbond_atom.cpp +++ b/src/BPM/compute_nbond_atom.cpp @@ -25,7 +25,20 @@ using namespace LAMMPS_NS; ComputeNBondAtom::ComputeNBondAtom(LAMMPS *_lmp, int narg, char **arg) : Compute(_lmp, narg, arg), nbond(nullptr) { - if (narg < 3) utils::missing_cmd_args(FLERR, "compute nbond/atom", error); + if (narg < 4) utils::missing_cmd_args(FLERR, "compute nbond/atom", error); + + btype = -1; + + iarg = 3; + while (iarg < narg) { + if (strcmp(arg[iarg], "bond/type") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "compute nbond/atom bond/type", error); + btype = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else { + error->all(FLERR, "Unknown compute nbond/type command {}", arg[iarg]); + } + } peratom_flag = 1; size_peratom_cols = 0; @@ -78,6 +91,7 @@ void ComputeNBondAtom::compute_peratom() for (i = 0; i < nlocal; i++) { for (j = 0; j < num_bond[i]; j++) { if (bond_type[i][j] <= 0) continue; + if (btype != -1 && bond_type[i][j] != btype) continue; k = atom->map(bond_atom[i][j]); if (k < 0) continue; diff --git a/src/BPM/compute_nbond_atom.h b/src/BPM/compute_nbond_atom.h index e0c2d7ce01..b55ef91e5d 100644 --- a/src/BPM/compute_nbond_atom.h +++ b/src/BPM/compute_nbond_atom.h @@ -35,7 +35,7 @@ class ComputeNBondAtom : public Compute { double memory_usage() override; private: - int nmax; + int nmax, btype; double *nbond; }; diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index 6a71136d9d..d366163459 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -20,6 +20,7 @@ #include "atom.h" #include "comm.h" +#include "compute_rheo_surface.h" #include "domain.h" #include "error.h" #include "fix_bond_history.h" @@ -42,7 +43,7 @@ using namespace RHEO_NS; /* ---------------------------------------------------------------------- */ BondRHEOShell::BondRHEOShell(LAMMPS *_lmp) : - BondBPM(_lmp), k(nullptr), ecrit(nullptr), gamma(nullptr) + BondBPM(_lmp), compute_surface(nullptr), k(nullptr), ecrit(nullptr), gamma(nullptr) { partial_flag = 1; comm_reverse = 1; @@ -279,7 +280,7 @@ void BondRHEOShell::compute(int eflag, int vflag) // Communicate changes in nbond if (newton_bond) comm->reverse_comm(this); - for(i = 0; i < nlocal; i++) { + for(int i = 0; i < nlocal; i++) { nbond[i] += dbond[i]; // If it has bonds, no shifting @@ -341,6 +342,18 @@ void BondRHEOShell::init_style() if (comm->ghost_velocity == 0) error->all(FLERR, "Bond rheo/shell requires ghost atoms store velocity"); + auto fixes = modify->get_fix_by_style("^rheo$"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use bond rheo/shell"); + class FixRHEO *fix_rheo = dynamic_cast(fixes[0]); + + if (!fix_rheo->surface_flag) error->all(FLERR, + "Bond rheo/shell requires surface calculation in fix rheo"); + compute_surface = fix_rheo->compute_surface; + + if (fix_rheo->oxidation_fix_defined != 1) + error->all(FLERR, "Need to define fix rheo/oxdiation to use bond rheo/shell"); + // check consistency in values (copy?), swap conditions to rsurf + if (!id_fix_bond_history) { id_fix_bond_history = utils::strdup("HISTORY_RHEO_SHELL"); fix_bond_history = dynamic_cast(modify->replace_fix( diff --git a/src/RHEO/bond_rheo_shell.h b/src/RHEO/bond_rheo_shell.h index 513d481eeb..a6a747a3f1 100644 --- a/src/RHEO/bond_rheo_shell.h +++ b/src/RHEO/bond_rheo_shell.h @@ -49,6 +49,8 @@ class BondRHEOShell : public BondBPM { int index_nb, nmax_store; char *id_fix; + class ComputeRHEOSurface *compute_surface; + void process_ineligibility(int, int); void allocate(); void store_data(); diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 2d6ff1e55a..bdc9951f90 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -29,6 +29,7 @@ #include "domain.h" #include "error.h" #include "fix_rheo.h" +#include "fix_rheo_oxidation.h" #include "fix_rheo_pressure.h" #include "fix_rheo_thermal.h" #include "memory.h" @@ -177,6 +178,11 @@ void ComputeRHEOPropertyAtom::init() fixes = modify->get_fix_by_style("rheo/pressure"); fix_pressure = dynamic_cast(fixes[0]); } + + if (shell_flag) { + fixes = modify->get_fix_by_style("rheo/oxidation"); + fix_oxidation = dynamic_cast(fixes[0]); + } } /* ---------------------------------------------------------------------- */ @@ -381,6 +387,21 @@ void ComputeRHEOPropertyAtom::pack_pressure(int n) /* ---------------------------------------------------------------------- */ +void ComputeRHEOPropertyAtom::pack_nbond_shell(int n) +{ + int *nbond = fix_oxidation->nbond; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = nbond[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + void ComputeRHEOPropertyAtom::pack_shift_v(int n) { double **vshift = compute_vshift->vshift; @@ -415,7 +436,7 @@ void ComputeRHEOPropertyAtom::pack_gradv(int n) void ComputeRHEOPropertyAtom::pack_atom_style(int n) { - atom->avec->pack_property_atom(avec_index[n],&buf[n],nvalues,groupbit); + atom->avec->pack_property_atom(avec_index[n], &buf[n], nvalues, groupbit); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index fd73b5883f..a66ef4ece6 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -63,6 +63,7 @@ class ComputeRHEOPropertyAtom : public Compute { class FixRHEO *fix_rheo; class FixRHEOPressure *fix_pressure; class FixRHEOThermal *fix_thermal; + class FixRHEOOxidation *fix_oxidation; class ComputeRHEOInterface *compute_interface; class ComputeRHEOKernel *compute_kernel; class ComputeRHEOSurface *compute_surface; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index b0cb1513fc..04b7d33541 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -48,12 +48,14 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : viscosity_fix_defined = 0; pressure_fix_defined = 0; thermal_fix_defined = 0; + oxidation_fix_defined = 0; thermal_flag = 0; rhosum_flag = 0; shift_flag = 0; interface_flag = 0; surface_flag = 0; + oxidation_flag = 0; int i; int n = atom->ntypes; @@ -252,6 +254,7 @@ void FixRHEO::setup(int /*vflag*/) thermal_fix_defined = 0; viscosity_fix_defined = 0; pressure_fix_defined = 0; + oxidation_fix_defined = 0; // Check fixes cover all atoms (may still fail if atoms are created) // FixRHEOPressure currently requires group all diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 33fd0084db..45f74ed4cd 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -51,6 +51,7 @@ class FixRHEO : public Fix { int shift_flag; int interface_flag; int surface_flag; + int oxidation_flag; int viscosity_fix_defined; int pressure_fix_defined; diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index 1628cef13f..f536df7842 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -20,6 +20,7 @@ #include "atom.h" #include "atom_vec.h" +#include "compute_rheo_surface.h" #include "error.h" #include "fix_rheo.h" #include "force.h" @@ -36,9 +37,9 @@ enum {NONE, CONSTANT}; /* ---------------------------------------------------------------------- */ FixRHEOOxidation::FixRHEOOxidation(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg) //, fix_bond_history(nullptr) + Fix(lmp, narg, arg), compute_surface(nullptr), fix_rheo(nullptr) { - if (narg != 5) error->all(FLERR,"Illegal fix command"); + if (narg != 6) error->all(FLERR,"Illegal fix command"); cut = utils::numeric(FLERR, arg[3], false, lmp); if (cut <= 0.0) error->all(FLERR, "Illegal bond cutoff {} in fix rheo/oxidation", cut); @@ -46,6 +47,9 @@ FixRHEOOxidation::FixRHEOOxidation(LAMMPS *lmp, int narg, char **arg) : btype = utils::inumeric(FLERR, arg[4], false, lmp); if (btype < 1 || btype > atom->nbondtypes) error->all(FLERR, "Illegal value {} for bond type in fix rheo/oxidation", btype); + rsurf = utils::numeric(FLERR, arg[5], false, lmp); + if (rsurf <= 0.0) error->all(FLERR, "Illegal surface distance {} in fix rheo/oxidation", cut); + cutsq = cut * cut; } @@ -72,22 +76,21 @@ void FixRHEOOxidation::init() auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/oxidation"); fix_rheo = dynamic_cast(fixes[0]); - double cut_kernel = fix_rheo->h; - if (cut > cut_kernel) + if (cut > fix_rheo->h) error->all(FLERR, "Bonding length exceeds kernel cutoff"); + if (rsurf >= fix_rheo->h) + error->all(FLERR, "Surface distance must be less than kernel cutoff"); + if (!force->bond) error->all(FLERR, "Must define a bond style with fix rheo/oxidation"); if (!atom->avec->bonds_allow) error->all(FLERR, "Fix rheo/oxidation requires atom bonds"); - //// find instances of bond history to delete data - //histories = modify->get_fix_by_style("BOND_HISTORY"); - //for (auto &ihistory: histories) - // if (strcmp(histories[i]->id, "HISTORY_RHEO_SHELL") == 0) - // fix_bond_history = dynamic_cast(ihistory); -// - //if (!fix_bond_history) - // error->all(FLERR, "Must define bond style rheo/shell to use fix rheo/oxidation"); + int tmp1, tmp2; + index_nb = atom->find_custom("shell_nbond", tmp1, tmp2); + if (index_nb == -1) + error->all(FLERR, "Must use bond style rheo/shell to use fix rheo/oxidation"); + nbond = atom->ivector[index_nb]; // need a half neighbor list auto req = neighbor->add_request(this, NeighConst::REQ_DEFAULT); @@ -111,13 +114,14 @@ void FixRHEOOxidation::setup_pre_force(int /*vflag*/) if (!fix_rheo->surface_flag) error->all(FLERR, "fix rheo/oxidation requires surface calculation in fix rheo"); + compute_surface = fix_rheo->compute_surface; pre_force(0); } /* ---------------------------------------------------------------------- */ -void FixRHEOThermal::pre_force(int /*vflag*/) +void FixRHEOOxidation::pre_force(int /*vflag*/) { } @@ -135,9 +139,9 @@ void FixRHEOOxidation::post_integrate() tagint *tag = atom->tag; tagint **bond_atom = atom->bond_atom; - int *status = atom->status; int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; + double *rsurface = compute_surface->rsurface; double **x = atom->x; inum = list->inum; @@ -148,7 +152,7 @@ void FixRHEOOxidation::post_integrate() // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; - if (!(status[i] & STATUS_SURFACE)) continue; + if (rsurface[i] > rsurf) continue; tagi = tag[i]; xtmp = x[i][0]; @@ -162,7 +166,7 @@ void FixRHEOOxidation::post_integrate() j = jlist[jj]; j &= NEIGHMASK; - if (!(status[j] & STATUS_SURFACE)) continue; + if (rsurface[j] > rsurf) continue; tagj = tag[j]; delx = xtmp - x[j][0]; @@ -208,10 +212,4 @@ void FixRHEOOxidation::post_integrate() } } } - - //todo: - // allow option to create near-surface bonds - // extract # of bonds in property/atom - // check bond style shell used, get index to bonds, share with compute property atom - // add type option to compute nbond/atom } diff --git a/src/RHEO/fix_rheo_oxidation.h b/src/RHEO/fix_rheo_oxidation.h index ca36a6fdf9..5242d24460 100644 --- a/src/RHEO/fix_rheo_oxidation.h +++ b/src/RHEO/fix_rheo_oxidation.h @@ -36,14 +36,15 @@ class FixRHEOOxidation : public Fix { void setup_pre_force(int) override; void pre_force(int) override; void post_integrate() override; + int *nbond; private: - int btype; - double cut, cutsq; + int btype, index_nb; + double rsurf, cut, cutsq; class NeighList *list; + class ComputeRHEOSurface *compute_surface; class FixRHEO *fix_rheo; - //class FixBondHistory *fix_bond_history; }; } // namespace LAMMPS_NS From ceec24d50b353527d8ff52d85e916fcb103a1475 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 4 Apr 2024 09:42:10 -0600 Subject: [PATCH 075/385] Adding hybrid support to BPM, more doc pages --- doc/src/pair_rheo_solid.rst | 76 +++++++++++++--- src/BPM/bond_bpm.cpp | 112 +++++++++++++++--------- src/BPM/bond_bpm.h | 11 ++- src/BPM/bond_bpm_rotational.cpp | 17 ++-- src/BPM/bond_bpm_spring.cpp | 19 ++-- src/BPM/compute_nbond_atom.cpp | 12 ++- src/RHEO/bond_rheo_shell.cpp | 85 ++++++++---------- src/RHEO/bond_rheo_shell.h | 2 +- src/RHEO/compute_rheo_property_atom.cpp | 13 +-- src/RHEO/compute_rheo_property_atom.h | 1 + src/RHEO/fix_rheo_oxidation.h | 5 +- src/RHEO/fix_rheo_thermal.cpp | 13 +-- src/RHEO/pair_rheo_solid.cpp | 4 + src/fix_bond_history.cpp | 96 ++++++++++++++++---- src/fix_bond_history.h | 13 ++- 15 files changed, 322 insertions(+), 157 deletions(-) diff --git a/doc/src/pair_rheo_solid.rst b/doc/src/pair_rheo_solid.rst index b6ff6d809d..ee86992776 100644 --- a/doc/src/pair_rheo_solid.rst +++ b/doc/src/pair_rheo_solid.rst @@ -21,36 +21,88 @@ Examples Description """"""""""" -pair style... +Style *rheo/solid* is effectively a copy of pair style +:doc:`bpm/spring ` except it only applies forces +between solid RHEO particles, determined by checking the status of +each pair of neighboring particles before calculating forces. + +The style computes pairwise forces with the formula + +.. math:: + + F = k (r - r_c) + +where :math:`k` is a stiffness and :math:`r_c` is the cutoff length. +An additional damping force is also applied to interacting +particles. The force is proportional to the difference in the +normal velocity of particles + +.. math:: + + F_D = - \gamma w (\hat{r} \bullet \vec{v}) + +where :math:`\gamma` is the damping strength, :math:`\hat{r}` is the +radial normal vector, :math:`\vec{v}` is the velocity difference +between the two particles, and :math:`w` is a smoothing factor. +This smoothing factor is constructed such that damping forces go to zero +as particles come out of contact to avoid discontinuities. It is +given by + +.. math:: + + w = 1.0 - \left( \frac{r}{r_c} \right)^8 . + +The following coefficients must be defined for each pair of atom types +via the :doc:`pair_coeff ` command as in the examples +above, or in the data file or restart files read by the +:doc:`read_data ` or :doc:`read_restart ` +commands, or by mixing as described below: + +* :math:`k` (force/distance units) +* :math:`r_c` (distance units) +* :math:`\gamma` (force/velocity units) -* :math:`k` (force/distance units) -* :math:`\sigma` (distance units) -* :math:`\gamma` (force/velocity units) ---------- Mixing, shift, table, tail correction, restart, rRESPA info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This style does not support the :doc:`pair_modify ` -shift, table, and tail options. +For atom type pairs I,J and I != J, the A coefficient and cutoff +distance for this pair style can be mixed. A is always mixed via a +*geometric* rule. The cutoff is mixed according to the pair_modify +mix value. The default mix value is *geometric*\ . See the +"pair_modify" command for details. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and -pair_coeff commands in an input script that reads a restart file. +This pair style does not support the :doc:`pair_modify ` +shift option, since the pair interaction goes to 0.0 at the cutoff. -This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, *middle*, *outer* keywords. +The :doc:`pair_modify ` table and tail options are not +relevant for this pair style. + +This pair style writes its information to :doc:`binary restart files +`, so pair_style and pair_coeff commands do not need to be +specified in an input script that reads a restart file. + +This pair style can only be used via the *pair* keyword of the +:doc:`run_style respa ` command. It does not support the +*inner*, *middle*, *outer* keywords. + +---------- Restrictions """""""""""" -This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +This pair style is part of the BPM package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package +` page for more info. Related commands """""""""""""""" :doc:`fix rheo `, -:doc:`pair bpm/spring `, +:doc:`fix rheo/thermal `, +:doc:`pair bpm/spring ` Default """"""" diff --git a/src/BPM/bond_bpm.cpp b/src/BPM/bond_bpm.cpp index 34554497ad..351cff1420 100644 --- a/src/BPM/bond_bpm.cpp +++ b/src/BPM/bond_bpm.cpp @@ -17,6 +17,7 @@ #include "comm.h" #include "domain.h" #include "error.h" +#include "fix.h" #include "fix_bond_history.h" #include "fix_store_local.h" #include "fix_update_special_bonds.h" @@ -39,10 +40,14 @@ BondBPM::BondBPM(LAMMPS *_lmp) : pack_choice(nullptr), output_data(nullptr) { overlay_flag = 0; + ignore_special_flag = 0; prop_atom_flag = 0; break_flag = 1; nvalues = 0; + nhistory = 0; + update_flag = 0; + r0_max_estimate = 0.0; max_stretch = 1.0; @@ -93,39 +98,46 @@ void BondBPM::init_style() fix_store_local->nvalues = nvalues; } - if (overlay_flag) { - if (force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0 || - force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 || force->special_coul[3] != 1.0) - error->all(FLERR, - "With overlay/pair yes, BPM bond styles require a value of 1.0 for all special_bonds weights"); - if (id_fix_update) { - modify->delete_fix(id_fix_update); - delete[] id_fix_update; - id_fix_update = nullptr; - } - } else { - // Require atoms know about all of their bonds and if they break - if (force->newton_bond && break_flag) - error->all(FLERR, "With overlay/pair no, or break yes, BPM bond styles require Newton bond off"); + if (!ignore_special_flag) { + if (overlay_flag) { + if (force->special_lj[1] != 1.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0 || + force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 || force->special_coul[3] != 1.0) + error->all(FLERR, + "With overlay/pair yes, BPM bond styles require a value of 1.0 for all special_bonds weights"); + if (id_fix_update) { + modify->delete_fix(id_fix_update); + delete[] id_fix_update; + id_fix_update = nullptr; + } + } else { + // Require atoms know about all of their bonds and if they break + if (force->newton_bond && break_flag) + error->all(FLERR, "With overlay/pair no, or break yes, BPM bond styles require Newton bond off"); - // special lj must be 0 1 1 to censor pair forces between bonded particles - if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) - error->all(FLERR, - "With overlay/pair no, BPM bond styles require special LJ weights = 0,1,1"); - // if bonds can break, special coulomb must be 1 1 1 to ensure all pairs are included in the - // neighbor list and 1-3 and 1-4 special bond lists are skipped - if (break_flag && (force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 || - force->special_coul[3] != 1.0)) - error->all(FLERR, - "With overlay/pair no, and break yes, BPM bond styles requires special Coulomb weights = 1,1,1"); + // special lj must be 0 1 1 to censor pair forces between bonded particles + if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) + error->all(FLERR, + "With overlay/pair no, BPM bond styles require special LJ weights = 0,1,1"); + // if bonds can break, special coulomb must be 1 1 1 to ensure all pairs are included in the + // neighbor list and 1-3 and 1-4 special bond lists are skipped + if (break_flag && (force->special_coul[1] != 1.0 || force->special_coul[2] != 1.0 || + force->special_coul[3] != 1.0)) + error->all(FLERR, + "With overlay/pair no, and break yes, BPM bond styles requires special Coulomb weights = 1,1,1"); - if (id_fix_dummy && break_flag) { - id_fix_update = utils::strdup("BPM_UPDATE_SPECIAL_BONDS"); - fix_update_special_bonds = dynamic_cast(modify->replace_fix( - id_fix_dummy, fmt::format("{} all UPDATE_SPECIAL_BONDS", id_fix_update), 1)); - delete[] id_fix_dummy; - id_fix_dummy = nullptr; + if (id_fix_dummy && break_flag) { + id_fix_update = utils::strdup("BPM_UPDATE_SPECIAL_BONDS"); + fix_update_special_bonds = dynamic_cast(modify->replace_fix( + id_fix_dummy, fmt::format("{} all UPDATE_SPECIAL_BONDS", id_fix_update), 1)); + delete[] id_fix_dummy; + id_fix_dummy = nullptr; + } } + + // special 1-3 and 1-4 weights must be 1 to prevent building 1-3 and 1-4 special bond lists + if (force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0 || force->special_coul[2] != 1.0 || + force->special_coul[3] != 1.0) + error->all(FLERR, "Bond style bpm requires 1-3 and 1-4 special weights of 1.0"); } if (force->angle || force->dihedral || force->improper) @@ -133,10 +145,16 @@ void BondBPM::init_style() if (atom->molecular == 2) error->all(FLERR, "Bond style bpm cannot be used with atom style template"); - // special 1-3 and 1-4 weights must be 1 to prevent building 1-3 and 1-4 special bond lists - if (force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0 || force->special_coul[2] != 1.0 || - force->special_coul[3] != 1.0) - error->all(FLERR, "Bond style bpm requires 1-3 and 1-4 special weights of 1.0"); + // find all instances of bond history to delete/shift data + // (bond hybrid may create multiple) + histories = modify->get_fix_by_style("BOND_HISTORY"); + n_histories = histories.size(); + + // If a bond type isn't set, must be using bond style hybrid + hybrid_flag = 0; + for (int i = 1; i <= atom->nbondtypes; i++) + if (!setflag[i]) hybrid_flag = 1; + fix_bond_history->setflag = setflag; } /* ---------------------------------------------------------------------- @@ -253,6 +271,14 @@ void BondBPM::settings(int narg, char **arg) } } } + + // Set up necessary history fix + if (!fix_bond_history) { + fix_bond_history = dynamic_cast(modify->replace_fix( + id_fix_dummy2, fmt::format("{} all BOND_HISTORY {} {}", id_fix_bond_history, update_flag, nhistory), 1)); + delete[] id_fix_dummy2; + id_fix_dummy2 = nullptr; + } } /* ---------------------------------------------------------------------- @@ -356,13 +382,16 @@ void BondBPM::process_broken(int i, int j) if (i < nlocal) { for (m = 0; m < num_bond[i]; m++) { - if (bond_atom[i][m] == tag[j]) { + if (bond_atom[i][m] == tag[j] && setflag[bond_type[i][m]]) { bond_type[i][m] = 0; n = num_bond[i]; bond_type[i][m] = bond_type[i][n - 1]; bond_atom[i][m] = bond_atom[i][n - 1]; - fix_bond_history->shift_history(i, m, n - 1); - fix_bond_history->delete_history(i, n - 1); + for (auto &ihistory: histories) { + auto fix_bond_history2 = dynamic_cast (ihistory); + fix_bond_history2->shift_history(i, m, n - 1); + fix_bond_history2->delete_history(i, n - 1); + } num_bond[i]--; break; } @@ -371,13 +400,16 @@ void BondBPM::process_broken(int i, int j) if (j < nlocal) { for (m = 0; m < num_bond[j]; m++) { - if (bond_atom[j][m] == tag[i]) { + if (bond_atom[j][m] == tag[i] && setflag[bond_type[j][m]]) { bond_type[j][m] = 0; n = num_bond[j]; bond_type[j][m] = bond_type[j][n - 1]; bond_atom[j][m] = bond_atom[j][n - 1]; - fix_bond_history->shift_history(j, m, n - 1); - fix_bond_history->delete_history(j, n - 1); + for (auto &ihistory: histories) { + auto fix_bond_history2 = dynamic_cast (ihistory); + fix_bond_history2->shift_history(j, m, n - 1); + fix_bond_history2->delete_history(j, n - 1); + } num_bond[j]--; break; } diff --git a/src/BPM/bond_bpm.h b/src/BPM/bond_bpm.h index 815b3b751f..28e4e7187e 100644 --- a/src/BPM/bond_bpm.h +++ b/src/BPM/bond_bpm.h @@ -16,8 +16,12 @@ #include "bond.h" +#include + namespace LAMMPS_NS { +class Fix; + class BondBPM : public Bond { public: BondBPM(class LAMMPS *); @@ -34,7 +38,7 @@ class BondBPM : public Bond { protected: double r0_max_estimate; double max_stretch; - int store_local_freq; + int store_local_freq, nhistory, update_flag, hybrid_flag; std::vector leftover_iarg; @@ -50,9 +54,12 @@ class BondBPM : public Bond { FnPtrPack *pack_choice; // ptrs to pack functions double *output_data; - int prop_atom_flag, nvalues, overlay_flag, break_flag; + int prop_atom_flag, nvalues, overlay_flag, break_flag, ignore_special_flag; int index_x_ref, index_y_ref, index_z_ref; + int n_histories; + std::vector histories; + void pack_id1(int, int, int); void pack_id2(int, int, int); void pack_time(int, int, int); diff --git a/src/BPM/bond_bpm_rotational.cpp b/src/BPM/bond_bpm_rotational.cpp index ffb0d9521d..b904a2ac07 100644 --- a/src/BPM/bond_bpm_rotational.cpp +++ b/src/BPM/bond_bpm_rotational.cpp @@ -52,6 +52,9 @@ BondBPMRotational::BondBPMRotational(LAMMPS *_lmp) : smooth_flag = 1; normalize_flag = 0; + nhistory = 4; + id_fix_bond_history = utils::strdup("HISTORY_BPM_ROTATIONAL"); + single_extra = 7; svector = new double[7]; } @@ -458,6 +461,9 @@ void BondBPMRotational::compute(int eflag, int vflag) store_data(); } + if (hybrid_flag) + fix_bond_history->compress_history(); + int i1, i2, itmp, n, type; double r[3], r0[3], rhat[3]; double rsq, r0_mag, r_mag, r_mag_inv; @@ -563,6 +569,9 @@ void BondBPMRotational::compute(int eflag, int vflag) ev_tally_xyz(i1, i2, nlocal, newton_bond, 0.0, -force1on2[0] * smooth, -force1on2[1] * smooth, -force1on2[2] * smooth, r[0], r[1], r[2]); } + + if (hybrid_flag) + fix_bond_history->uncompress_history(); } /* ---------------------------------------------------------------------- */ @@ -652,14 +661,6 @@ void BondBPMRotational::init_style() if (domain->dimension == 2) error->warning(FLERR, "Bond style bpm/rotational not intended for 2d use"); - - if (!id_fix_bond_history) { - id_fix_bond_history = utils::strdup("HISTORY_BPM_ROTATIONAL"); - fix_bond_history = dynamic_cast(modify->replace_fix( - id_fix_dummy2, fmt::format("{} all BOND_HISTORY 0 4", id_fix_bond_history), 1)); - delete[] id_fix_dummy2; - id_fix_dummy2 = nullptr; - } } /* ---------------------------------------------------------------------- */ diff --git a/src/BPM/bond_bpm_spring.cpp b/src/BPM/bond_bpm_spring.cpp index 37b79f93fb..0c882ae6c6 100644 --- a/src/BPM/bond_bpm_spring.cpp +++ b/src/BPM/bond_bpm_spring.cpp @@ -23,6 +23,8 @@ #include "modify.h" #include "neighbor.h" +#include "update.h" + #include #include @@ -39,6 +41,9 @@ BondBPMSpring::BondBPMSpring(LAMMPS *_lmp) : smooth_flag = 1; normalize_flag = 0; + nhistory = 1; + id_fix_bond_history = utils::strdup("HISTORY_BPM_SPRING"); + single_extra = 1; svector = new double[1]; } @@ -137,6 +142,9 @@ void BondBPMSpring::compute(int eflag, int vflag) store_data(); } + if (hybrid_flag) + fix_bond_history->compress_history(); + int i1, i2, itmp, n, type; double delx, dely, delz, delvx, delvy, delvz; double e, rsq, r, r0, rinv, smooth, fbond, dot; @@ -226,6 +234,9 @@ void BondBPMSpring::compute(int eflag, int vflag) if (evflag) ev_tally(i1, i2, nlocal, newton_bond, 0.0, fbond, delx, dely, delz); } + + if (hybrid_flag) + fix_bond_history->uncompress_history(); } /* ---------------------------------------------------------------------- */ @@ -283,14 +294,6 @@ void BondBPMSpring::init_style() if (comm->ghost_velocity == 0) error->all(FLERR, "Bond bpm/spring requires ghost atoms store velocity"); - - if (!id_fix_bond_history) { - id_fix_bond_history = utils::strdup("HISTORY_BPM_SPRING"); - fix_bond_history = dynamic_cast(modify->replace_fix( - id_fix_dummy2, fmt::format("{} all BOND_HISTORY 0 1", id_fix_bond_history), 1)); - delete[] id_fix_dummy2; - id_fix_dummy2 = nullptr; - } } /* ---------------------------------------------------------------------- */ diff --git a/src/BPM/compute_nbond_atom.cpp b/src/BPM/compute_nbond_atom.cpp index af1cc2b9bc..b6e7b0139f 100644 --- a/src/BPM/compute_nbond_atom.cpp +++ b/src/BPM/compute_nbond_atom.cpp @@ -14,7 +14,9 @@ #include "compute_nbond_atom.h" #include "atom.h" +#include "atom_vec.h" #include "comm.h" +#include "error.h" #include "force.h" #include "memory.h" @@ -25,18 +27,20 @@ using namespace LAMMPS_NS; ComputeNBondAtom::ComputeNBondAtom(LAMMPS *_lmp, int narg, char **arg) : Compute(_lmp, narg, arg), nbond(nullptr) { - if (narg < 4) utils::missing_cmd_args(FLERR, "compute nbond/atom", error); + if (narg < 3) utils::missing_cmd_args(FLERR, "compute nbond/atom", error); + + if (atom->avec->bonds_allow == 0) + error->all(FLERR,"Compute nbond/atom used when bonds are not allowed"); btype = -1; - - iarg = 3; + int iarg = 3; while (iarg < narg) { if (strcmp(arg[iarg], "bond/type") == 0) { if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "compute nbond/atom bond/type", error); btype = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); iarg += 2; } else { - error->all(FLERR, "Unknown compute nbond/type command {}", arg[iarg]); + error->all(FLERR, "Unknown compute nbond/atom command {}", arg[iarg]); } } diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index d366163459..0a3caa1b4f 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -25,6 +25,7 @@ #include "error.h" #include "fix_bond_history.h" #include "fix_rheo.h" +#include "fix_rheo_oxidation.h" #include "fix_store_local.h" #include "force.h" #include "memory.h" @@ -48,7 +49,12 @@ BondRHEOShell::BondRHEOShell(LAMMPS *_lmp) : partial_flag = 1; comm_reverse = 1; - tform = rmax = -1; + nhistory = 2; + update_flag = 1; + id_fix_bond_history = utils::strdup("HISTORY_RHEO_SHELL"); + ignore_special_flag = 1; + + tform = -1; single_extra = 1; svector = new double[1]; @@ -155,12 +161,14 @@ void BondRHEOShell::store_data() void BondRHEOShell::compute(int eflag, int vflag) { - if (!fix_bond_history->stored_flag) { fix_bond_history->stored_flag = true; store_data(); } + if (hybrid_flag) + fix_bond_history->compress_history(); + int i1, i2, itmp, n, type; double delx, dely, delz, delvx, delvy, delvz; double e, rsq, r, r0, rinv, dr, fbond, dot, t; @@ -168,6 +176,7 @@ void BondRHEOShell::compute(int eflag, int vflag) ev_init(eflag, vflag); + double *rsurface = compute_surface->rsurface; double **x = atom->x; double **v = atom->v; double **f = atom->f; @@ -223,7 +232,7 @@ void BondRHEOShell::compute(int eflag, int vflag) if (t < tform) { // Check if eligible - if (r > rmax || !(status[i1] & STATUS_SURFACE) || !(status[i2] & STATUS_SURFACE)) { + if (r > rmax || rsurface[i1] > rsurf || rsurface[i2] > rsurf) { bondlist[n][2] = 0; process_ineligibility(i1, i2); continue; @@ -286,6 +295,9 @@ void BondRHEOShell::compute(int eflag, int vflag) // If it has bonds, no shifting if (nbond[i] != 0) status[i] |= STATUS_NO_SHIFT; } + + if (hybrid_flag) + fix_bond_history->uncompress_history(); } /* ---------------------------------------------------------------------- */ @@ -339,6 +351,8 @@ void BondRHEOShell::coeff(int narg, char **arg) void BondRHEOShell::init_style() { + BondBPM::init_style(); + if (comm->ghost_velocity == 0) error->all(FLERR, "Bond rheo/shell requires ghost atoms store velocity"); @@ -350,37 +364,12 @@ void BondRHEOShell::init_style() "Bond rheo/shell requires surface calculation in fix rheo"); compute_surface = fix_rheo->compute_surface; - if (fix_rheo->oxidation_fix_defined != 1) - error->all(FLERR, "Need to define fix rheo/oxdiation to use bond rheo/shell"); - // check consistency in values (copy?), swap conditions to rsurf + fixes = modify->get_fix_by_style("^rheo/oxidation$"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo/oxidation to use bond rheo/shell"); + class FixRHEOOxidation *fix_rheo_oxidation = dynamic_cast(fixes[0]); - if (!id_fix_bond_history) { - id_fix_bond_history = utils::strdup("HISTORY_RHEO_SHELL"); - fix_bond_history = dynamic_cast(modify->replace_fix( - id_fix_dummy2, fmt::format("{} all BOND_HISTORY 1 2", id_fix_bond_history), 1)); - delete[] id_fix_dummy2; - id_fix_dummy2 = nullptr; - } - - // Reproduce standard functions of BondBPM, removing special restrictions - // Since this bond is intended to be created by fix rheo/oxidation, it - // ignores special statuses - - if (id_fix_store_local) { - auto ifix = modify->get_fix_by_id(id_fix_store_local); - if (!ifix) error->all(FLERR, "Cannot find fix STORE/LOCAL id {}", id_fix_store_local); - if (strcmp(ifix->style, "STORE/LOCAL") != 0) - error->all(FLERR, "Incorrect fix style matched, not STORE/LOCAL: {}", ifix->style); - fix_store_local = dynamic_cast(ifix); - fix_store_local->nvalues = nvalues; - } - - id_fix_update = nullptr; - - if (force->angle || force->dihedral || force->improper) - error->all(FLERR, "Bond style rheo/shell cannot be used with 3,4-body interactions"); - if (atom->molecular == 2) - error->all(FLERR, "Bond style rheo/shell cannot be used with atom style template"); + rsurf = fix_rheo_oxidation->rsurf; + rmax = fix_rheo_oxidation->cut; } /* ---------------------------------------------------------------------- */ @@ -397,20 +386,13 @@ void BondRHEOShell::settings(int narg, char **arg) tform = utils::numeric(FLERR, arg[iarg + 1], false, lmp); if (tform < 0.0) error->all(FLERR, "Illegal bond rheo/shell value for t/form, {}", tform); i += 1; - } else if (strcmp(arg[iarg], "r/max") == 0) { - if (iarg + 1 > narg) error->all(FLERR, "Illegal bond rheo/shell command, missing option for r/max"); - rmax = utils::numeric(FLERR, arg[iarg + 1], false, lmp); - if (rmax < 0.0) error->all(FLERR, "Illegal bond rheo/shell value for r/max, {}", rmax); - i += 1; } else { error->all(FLERR, "Illegal bond rheo/shell command, invalid argument {}", arg[iarg]); } } if (tform < 0.0) - error->all(FLERR, "Illegal bond rheo/shell command, must specify t/form"); - if (rmax < 0.0) - error->all(FLERR, "Illegal bond rheo/shell command, must specify r/max"); + error->all(FLERR, "Illegal bond rheo/shell command, must specify formation time"); } @@ -467,7 +449,6 @@ void BondRHEOShell::read_restart(FILE *fp) void BondRHEOShell::write_restart_settings(FILE *fp) { fwrite(&tform, sizeof(double), 1, fp); - fwrite(&rmax, sizeof(double), 1, fp); } /* ---------------------------------------------------------------------- @@ -478,10 +459,8 @@ void BondRHEOShell::read_restart_settings(FILE *fp) { if (comm->me == 0) { utils::sfread(FLERR, &tform, sizeof(double), 1, fp, nullptr, error); - utils::sfread(FLERR, &rmax, sizeof(double), 1, fp, nullptr, error); } MPI_Bcast(&tform, 1, MPI_DOUBLE, 0, world); - MPI_Bcast(&rmax, 1, MPI_DOUBLE, 0, world); } @@ -570,13 +549,16 @@ void BondRHEOShell::process_ineligibility(int i, int j) if (i < nlocal) { for (m = 0; m < num_bond[i]; m++) { - if (bond_atom[i][m] == tag[j]) { + if (bond_atom[i][m] == tag[j] && setflag[bond_type[i][m]]) { bond_type[i][m] = 0; n = num_bond[i]; bond_type[i][m] = bond_type[i][n - 1]; bond_atom[i][m] = bond_atom[i][n - 1]; - fix_bond_history->shift_history(i, m, n - 1); - fix_bond_history->delete_history(i, n - 1); + for (auto &ihistory: histories) { + auto fix_bond_history2 = dynamic_cast (ihistory); + fix_bond_history2->shift_history(i, m, n - 1); + fix_bond_history2->delete_history(i, n - 1); + } num_bond[i]--; break; } @@ -585,13 +567,16 @@ void BondRHEOShell::process_ineligibility(int i, int j) if (j < nlocal) { for (m = 0; m < num_bond[j]; m++) { - if (bond_atom[j][m] == tag[i]) { + if (bond_atom[j][m] == tag[i] && setflag[bond_type[j][m]]) { bond_type[j][m] = 0; n = num_bond[j]; bond_type[j][m] = bond_type[j][n - 1]; bond_atom[j][m] = bond_atom[j][n - 1]; - fix_bond_history->shift_history(j, m, n - 1); - fix_bond_history->delete_history(j, n - 1); + for (auto &ihistory: histories) { + auto fix_bond_history2 = dynamic_cast (ihistory); + fix_bond_history2->shift_history(j, m, n - 1); + fix_bond_history2->delete_history(j, n - 1); + } num_bond[j]--; break; } diff --git a/src/RHEO/bond_rheo_shell.h b/src/RHEO/bond_rheo_shell.h index a6a747a3f1..828f693ea3 100644 --- a/src/RHEO/bond_rheo_shell.h +++ b/src/RHEO/bond_rheo_shell.h @@ -43,7 +43,7 @@ class BondRHEOShell : public BondBPM { protected: double *k, *ecrit, *gamma; - double tform, rmax; + double tform, rmax, rsurf; int *dbond, *nbond; int index_nb, nmax_store; diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index bdc9951f90..61b83a4542 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -160,27 +160,30 @@ void ComputeRHEOPropertyAtom::init() error->all(FLERR, "Cannot request velocity shifting property without corresponding option in fix rheo"); if (thermal_flag && !(fix_rheo->thermal_flag)) error->all(FLERR, "Cannot request thermal property without fix rheo/thermal"); - if (shell_flag && !(fix_rheo->oxidation_flag)) - error->all(FLERR, "Cannot request number of shell bonds without fix rheo/oxidation"); compute_interface = fix_rheo->compute_interface; compute_kernel = fix_rheo->compute_kernel; compute_surface = fix_rheo->compute_surface; compute_vshift = fix_rheo->compute_vshift; compute_grad = fix_rheo->compute_grad; +} +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::setup() +{ if (thermal_flag) { - fixes = modify->get_fix_by_style("rheo/thermal"); + auto fixes = modify->get_fix_by_style("rheo/thermal"); fix_thermal = dynamic_cast(fixes[0]); } if (pressure_flag) { - fixes = modify->get_fix_by_style("rheo/pressure"); + auto fixes = modify->get_fix_by_style("rheo/pressure"); fix_pressure = dynamic_cast(fixes[0]); } if (shell_flag) { - fixes = modify->get_fix_by_style("rheo/oxidation"); + auto fixes = modify->get_fix_by_style("rheo/oxidation"); fix_oxidation = dynamic_cast(fixes[0]); } } diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index a66ef4ece6..fc5c5d1bd0 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -29,6 +29,7 @@ class ComputeRHEOPropertyAtom : public Compute { ComputeRHEOPropertyAtom(class LAMMPS *, int, char **); ~ComputeRHEOPropertyAtom() override; void init() override; + void setup() override; void compute_peratom() override; double memory_usage() override; diff --git a/src/RHEO/fix_rheo_oxidation.h b/src/RHEO/fix_rheo_oxidation.h index 5242d24460..be95efbf2c 100644 --- a/src/RHEO/fix_rheo_oxidation.h +++ b/src/RHEO/fix_rheo_oxidation.h @@ -37,12 +37,13 @@ class FixRHEOOxidation : public Fix { void pre_force(int) override; void post_integrate() override; int *nbond; + double rsurf, cut; private: int btype, index_nb; - double rsurf, cut, cutsq; - class NeighList *list; + double cutsq; + class NeighList *list; class ComputeRHEOSurface *compute_surface; class FixRHEO *fix_rheo; }; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 7d9aff5424..a133428d4a 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -270,13 +270,8 @@ void FixRHEOThermal::init() auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL); req->set_cutoff(cut_kernel); - // find instances of bond history to delete data - // skip history for shell, only exception + // find instances of bond history to delete/shift data histories = modify->get_fix_by_style("BOND_HISTORY"); - if (n_histories > 0) - for (int i = 0; i < histories.size(); i++) - if (strcmp(histories[i]->id, "HISTORY_RHEO_SHELL") == 0) - histories.erase(histories.begin() + i); n_histories = histories.size(); } } @@ -498,7 +493,7 @@ void FixRHEOThermal::break_bonds() int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - // Rapidly delete all bonds for local atoms that melt of a given type + // Delete all bonds for local atoms that melt of a given type for (int i = 0; i < nlocal; i++) { if (!(status[i] & STATUS_MELTING)) continue; for (m = (num_bond[i] - 1); m >= 0; m--) { @@ -543,7 +538,7 @@ void FixRHEOThermal::break_bonds() bondlist[n][2] = 0; // Delete bonds for non-melted local atoms (shifting) - if (i < nlocal) { + if (i < nlocal && !(status[i] & STATUS_MELTING)) { for (m = 0; m < num_bond[i]; m++) { if (bond_atom[i][m] == tag[j] && bond_type[i][m] == btype) { nmax = num_bond[i] - 1; @@ -562,7 +557,7 @@ void FixRHEOThermal::break_bonds() } } - if (j < nlocal) { + if (j < nlocal && !(status[j] & STATUS_MELTING)) { for (m = 0; m < num_bond[j]; m++) { if (bond_atom[j][m] == tag[i] && bond_type[j][m] == btype) { nmax = num_bond[j] - 1; diff --git a/src/RHEO/pair_rheo_solid.cpp b/src/RHEO/pair_rheo_solid.cpp index f6dcd95879..9b358420d2 100644 --- a/src/RHEO/pair_rheo_solid.cpp +++ b/src/RHEO/pair_rheo_solid.cpp @@ -327,6 +327,10 @@ double PairRHEOSolid::single(int i, int j, int itype, int jtype, double rsq, dou if (rsq > cutsq[itype][jtype]) return 0.0; + int *status = atom->status; + if (!(status[i] & STATUS_SOLID)) return 0.0; + if (!(status[j] & STATUS_SOLID)) return 0.0; + double **x = atom->x; double **v = atom->v; diff --git a/src/fix_bond_history.cpp b/src/fix_bond_history.cpp index 277df75085..461f91bd52 100644 --- a/src/fix_bond_history.cpp +++ b/src/fix_bond_history.cpp @@ -33,7 +33,7 @@ using namespace FixConst; /* ---------------------------------------------------------------------- */ FixBondHistory::FixBondHistory(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), bondstore(nullptr), id_fix(nullptr), id_array(nullptr) + Fix(lmp, narg, arg), bondstore(nullptr), bondtype_orig(nullptr), bondstore_comp(nullptr), bondstore_orig(nullptr), id_fix(nullptr), id_array(nullptr) { if (narg != 5) error->all(FLERR, "Illegal fix bond/history command"); @@ -53,7 +53,6 @@ FixBondHistory::FixBondHistory(LAMMPS *lmp, int narg, char **arg) : updated_bond_flag = 0; maxbond = 0; - allocate(); } /* ---------------------------------------------------------------------- */ @@ -65,6 +64,8 @@ FixBondHistory::~FixBondHistory() delete[] id_array; memory->destroy(bondstore); + memory->destroy(bondstore_comp); + memory->destroy(bondtype_orig); } /* ---------------------------------------------------------------------- */ @@ -135,6 +136,7 @@ void FixBondHistory::pre_exchange() int nlocal = atom->nlocal; tagint **bond_atom = atom->bond_atom; + int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; tagint *tag = atom->tag; @@ -142,12 +144,12 @@ void FixBondHistory::pre_exchange() i1 = bondlist[n][0]; i2 = bondlist[n][1]; - // skip bond if already broken - if (bondlist[n][2] <= 0) { continue; } + // skip bond if already broken or not allocated + if (bondlist[n][2] <= 0 || !setflag[bondlist[n][2]]) { continue; } if (i1 < nlocal) { for (m = 0; m < num_bond[i1]; m++) { - if (bond_atom[i1][m] == tag[i2]) { + if (bond_atom[i1][m] == tag[i2] && setflag[bond_type[i1][m]]) { for (idata = 0; idata < ndata; idata++) { stored[i1][m * ndata + idata] = bondstore[n][idata]; } @@ -157,7 +159,7 @@ void FixBondHistory::pre_exchange() if (i2 < nlocal) { for (m = 0; m < num_bond[i2]; m++) { - if (bond_atom[i2][m] == tag[i1]) { + if (bond_atom[i2][m] == tag[i1] && setflag[bond_type[i2][m]]) { for (idata = 0; idata < ndata; idata++) { stored[i2][m * ndata + idata] = bondstore[n][idata]; } @@ -179,17 +181,21 @@ void FixBondHistory::allocate() else maxbond = static_cast(LB_FACTOR * atom->nbonds / comm->nprocs); memory->create(bondstore, maxbond, ndata, "fix_bond_store:bondstore"); + if (hybrid_flag) { + memory->create(bondstore_comp, maxbond, ndata, "fix_bond_store:bondstore_comp"); + memory->create(bondtype_orig, maxbond, "fix_bond_store:bondtype_orig"); + } } /* ---------------------------------------------------------------------- */ void FixBondHistory::setup_post_neighbor() { - //Grow array if number of bonds has increased - while (neighbor->nbondlist >= maxbond) { - maxbond += DELTA; - memory->grow(bondstore, maxbond, ndata, "fix_bond_store:bondstore"); - } + hybrid_flag = 0; + for (int i = 1; i <= atom->nbondtypes; i++) + if (!setflag[i]) hybrid_flag = 1; + + if (maxbond == 0) allocate(); pre_exchange(); post_neighbor(); @@ -206,6 +212,10 @@ void FixBondHistory::post_neighbor() while (neighbor->nbondlist >= maxbond) { maxbond += DELTA; memory->grow(bondstore, maxbond, ndata, "fix_bond_store:bondstore"); + if (hybrid_flag) { + memory->grow(bondstore_comp, maxbond, ndata, "fix_bond_store:bondstore_comp"); + memory->grow(bondtype_orig, maxbond, "fix_bond_store:bondtype_orig"); + } } int i1, i2, n, m, idata; @@ -215,6 +225,7 @@ void FixBondHistory::post_neighbor() int nlocal = atom->nlocal; tagint **bond_atom = atom->bond_atom; + int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; tagint *tag = atom->tag; @@ -222,12 +233,12 @@ void FixBondHistory::post_neighbor() i1 = bondlist[n][0]; i2 = bondlist[n][1]; - // skip bond if already broken - if (bondlist[n][2] <= 0) { continue; } + // skip bond if already broken or not allocated + if (bondlist[n][2] <= 0 || !setflag[bondlist[n][2]]) { continue; } if (i1 < nlocal) { for (m = 0; m < num_bond[i1]; m++) { - if (bond_atom[i1][m] == tag[i2]) { + if (bond_atom[i1][m] == tag[i2] && setflag[bond_type[i1][m]]) { for (idata = 0; idata < ndata; idata++) { bondstore[n][idata] = stored[i1][m * ndata + idata]; } @@ -237,7 +248,7 @@ void FixBondHistory::post_neighbor() if (i2 < nlocal) { for (m = 0; m < num_bond[i2]; m++) { - if (bond_atom[i2][m] == tag[i1]) { + if (bond_atom[i2][m] == tag[i1] && setflag[bond_type[i2][m]]) { for (idata = 0; idata < ndata; idata++) { bondstore[n][idata] = stored[i2][m * ndata + idata]; } @@ -246,6 +257,12 @@ void FixBondHistory::post_neighbor() } } + if (hybrid_flag) { + nbondlist_orig = nbondlist; + for (n = 0; n < nbondlist; n++) + bondtype_orig[n] = bondlist[n][2]; + } + updated_bond_flag = 1; } @@ -294,6 +311,55 @@ void FixBondHistory::set_arrays(int i) for (int idata = 0; idata < ndata; idata++) stored[i][m * ndata + idata] = 0.0; } +/* ---------------------------------------------------------------------- + Compress history arrays, cutting out unused types, for bond hybrid +------------------------------------------------------------------------- */ + +void FixBondHistory::compress_history() +{ + // if this is a re-neighbor step or updating, compress bondstore + + int type; + int ncomp = 0; + if (update_flag || (neighbor->ago == 0)) { + for (int n = 0; n < nbondlist_orig; n++) { + type = bondtype_orig[n]; + if (type <= 0) continue; + if (setflag[type]) { + for (int m = 0; m < ndata; m++) + bondstore_comp[ncomp][m] = bondstore[n][m]; + ncomp += 1; + } + } + } + + // replace ptr to original array + bondstore_orig = bondstore; + bondstore = bondstore_comp; +} + +/* ---------------------------------------------------------------------- */ + +void FixBondHistory::uncompress_history() +{ + if (update_flag) { + int ncomp = 0; + for (int n = 0; n < nbondlist_orig; n++) { + type = bondtype_orig[n]; + + if (type <= 0) continue; + if (!setflag[type]) continue; + + for (int m = 0; m < ndata; m++) + bondstore[n][m] = bondstore_comp[ncomp][m]; + ncomp += 1; + } + } + + // restore ptr to original array + bondstore = bondstore_orig; +} + /* ---------------------------------------------------------------------- Delete bond by zeroing data ------------------------------------------------------------------------- */ diff --git a/src/fix_bond_history.h b/src/fix_bond_history.h index fafcf52bd9..8ee3132ab1 100644 --- a/src/fix_bond_history.h +++ b/src/fix_bond_history.h @@ -52,18 +52,29 @@ class FixBondHistory : public Fix { void check_cache(int, int); void clear_cache(); + // methods for bond style hybrid + void compress_history(); + void uncompress_history(); + // if data is temporarily stored while the bond_atom array // is being reordered, use map of vectors with pairs for keys // to enable quick look up std::map, std::vector> cached_histories; + int *setflag; // Set by BondBPM, which bond types are used double **bondstore; int stored_flag; protected: void allocate(); - int update_flag; //Flag whether history values can evolve + int hybrid_flag; + int nbondlist_orig; + int *bondtype_orig; + double **bondstore_comp; + double **bondstore_orig; + + int update_flag; // Flag whether history values can evolve int updated_bond_flag; int nbond, maxbond, ndata; int index; From c63c1856ec5c4300cb7e892d035d69c6d03b12ad Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 4 Apr 2024 11:21:42 -0600 Subject: [PATCH 076/385] Fix compilation error, edit artificial visc toggle --- src/RHEO/pair_rheo.cpp | 3 ++- src/fix_bond_history.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index fe5a1d6dec..cb33b20bea 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -189,10 +189,11 @@ void PairRHEO::compute(int eflag, int vflag) pair_avisc_flag = 0; if (fluidi || fluidj) { pair_force_flag = 1; + if (interface_flag) pair_avisc_flag = 1; } if (fluidi && fluidj) { - pair_avisc_flag = 1; pair_rho_flag = 1; + pair_avisc_flag = 1; } wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2], r); diff --git a/src/fix_bond_history.cpp b/src/fix_bond_history.cpp index 461f91bd52..8fa0b3f923 100644 --- a/src/fix_bond_history.cpp +++ b/src/fix_bond_history.cpp @@ -343,6 +343,7 @@ void FixBondHistory::compress_history() void FixBondHistory::uncompress_history() { if (update_flag) { + int type; int ncomp = 0; for (int n = 0; n < nbondlist_orig; n++) { type = bondtype_orig[n]; From 5383bd26139bb0a2584ee96a9f7ff1e9ba1735e5 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 10 Apr 2024 09:47:55 -0600 Subject: [PATCH 077/385] More doc files, misc clean ups --- doc/src/Howto_rheo.rst | 4 +- doc/src/bond_rheo_shell.rst | 119 ++---- doc/src/compute_rheo_property_atom.rst | 39 +- doc/src/fix_rheo.rst | 2 + doc/src/fix_rheo_oxidation.rst | 53 +-- doc/src/fix_rheo_pressure.rst | 2 + doc/src/fix_rheo_thermal.rst | 2 + doc/src/fix_rheo_viscosity.rst | 2 + doc/src/pair_rheo.rst | 2 + doc/src/pair_rheo_react.rst | 67 --- doc/src/pair_rheo_solid.rst | 2 + src/RHEO/compute_rheo_property_atom.cpp | 54 ++- src/RHEO/compute_rheo_property_atom.h | 4 +- src/RHEO/fix_rheo.cpp | 6 + src/RHEO/fix_rheo_oxidation.cpp | 15 + src/RHEO/fix_rheo_stress.cpp | 137 ------- src/RHEO/fix_rheo_stress.h | 48 --- src/RHEO/fix_rheo_thermal.cpp | 15 + src/RHEO/pair_rheo_react.cpp | 515 ------------------------ src/RHEO/pair_rheo_react.h | 63 --- 20 files changed, 187 insertions(+), 964 deletions(-) delete mode 100644 doc/src/pair_rheo_react.rst delete mode 100644 src/RHEO/fix_rheo_stress.cpp delete mode 100644 src/RHEO/fix_rheo_stress.h delete mode 100644 src/RHEO/pair_rheo_react.cpp delete mode 100644 src/RHEO/pair_rheo_react.h diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index 146716ba18..db710d2366 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -90,10 +90,10 @@ criteria for creating/deleting a bond or altering force calculations). ---------- -.. _howto-howto_rheo_palermo: +.. _howto_rheo_palermo: **(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. -.. _howto-howto_rheo_clemmer: +.. _howto_rheo_clemmer: **(Clemmer)** Clemmer, Pierce, O'Connor, Nevins, Jones, Lechman, Tencer, Appl. Math. Model., 130, 310-326 (2024). diff --git a/doc/src/bond_rheo_shell.rst b/doc/src/bond_rheo_shell.rst index 7f6bab1eab..713bd84136 100644 --- a/doc/src/bond_rheo_shell.rst +++ b/doc/src/bond_rheo_shell.rst @@ -10,10 +10,13 @@ Syntax bond_style rheo/shell keyword value attribute1 attribute2 ... -* optional keyword = *overlay/pair* or *store/local* or *smooth* or *break* +* required keyword = *t/form* +* optional keyword = *store/local* .. parsed-literal:: + *t/form* value = formation time for a bond (time units) + *store/local* values = fix_ID N attributes ... * fix_ID = ID of associated internal fix to store data * N = prepare data for output every this many timesteps @@ -24,56 +27,56 @@ Syntax *x, y, z* = the center of mass position of the 2 atoms when the bond broke (distance units) *x/ref, y/ref, z/ref* = the initial center of mass position of the 2 atoms (distance units) - *overlay/pair* value = *yes* or *no* - bonded particles will still interact with pair forces - - *smooth* value = *yes* or *no* - smooths bond forces near the breaking point - - *normalize* value = *yes* or *no* - normalizes bond forces by the reference length - - *break* value = *yes* or *no* - indicates whether bonds break during a run - Examples """""""" .. code-block:: LAMMPS - bond_style bpm/spring + bond_style rheo/shell t/form 10.0 bond_coeff 1 1.0 0.05 0.1 - bond_style bpm/spring myfix 1000 time id1 id2 - dump 1 all local 1000 dump.broken f_myfix[1] f_myfix[2] f_myfix[3] - dump_modify 1 write_header no - Description """"""""""" -.. versionadded:: 4May2022 +.. versionadded:: TBD -The *bpm/spring* bond style computes forces based on -deviations from the initial reference state of the two atoms. The -reference state is stored by each bond when it is first computed in +The *rheo/shell* bond style is designed to work with +:doc:`fix rheo/oxidation ` which creates candidate +bonds between eligible surface or near-surface particles. When a bond +is first created, it computes no forces and starts a timer. Forces are +not computed until the timer reaches the specified bond formation time +and the bond is fully enabled. If the two particles move outside of the +maximum bond distance or move into the bulk before the timer reaches +the formation time, the bond automatically deletes itself. Not that +this deletion does not generate any broken bond data saved to a +*store/local* fix. + +Before bonds are enabled, they are still treated as regular bonds by +all other parts of LAMMPS. This means they are written to data files +and counted in computes such as :doc:`nbond/atom `. +To only count enabled bonds, use the *nbond/shell* attribute in +:doc:`compute property/atom/rheo `. + +When enabled, the bond then computes forces based on deviations from +the initial reference state of the two atoms much like a BPM style +bond (as further discussed in the :doc:`BPM howto page `). +The reference state is stored by each bond when it is first enabled the setup of a run. Data is then preserved across run commands and is written to :doc:`binary restart files ` such that restarting -the system will not reset the reference state of a bond. +the system will not reset the reference state of a bond or the timer. -This bond style only applies central-body forces which conserve the -translational and rotational degrees of freedom of a bonded set of -particles based on a model described by Clemmer and Robbins -:ref:`(Clemmer) `. The force has a magnitude of +This bond style is based on a model described in Ref. +:ref:`(Clemmer) `. The force has a magnitude of .. math:: - F = k (r - r_0) w + F = 2 k (r - r_0) + \frac{2 * k}{r_0^2 \epsilon_c^2} (r - r_0)^3 where :math:`k` is a stiffness, :math:`r` is the current distance and :math:`r_0` is the initial distance between the two particles, and -:math:`w` is an optional smoothing factor discussed below. Bonds will -break at a strain of :math:`\epsilon_c`. This is done by setting -the bond type to 0 such that forces are no longer computed. +:math:`\epsilon_c` is maximum strain beyond which a bond breaks. This +is done by setting the bond type to 0 such that forces are no longer +computed. An additional damping force is applied to the bonded particles. This forces is proportional to the difference in the @@ -88,15 +91,6 @@ where :math:`\gamma` is the damping strength, :math:`\hat{r}` is the radial normal vector, and :math:`\vec{v}` is the velocity difference between the two particles. -The smoothing factor :math:`w` can be added or removed by setting the -*smooth* keyword to *yes* or *no*, respectively. It is constructed such -that forces smoothly go to zero, avoiding discontinuities, as bonds -approach the critical strain - -.. math:: - - w = 1.0 - \left( \frac{r - r_0}{r_0 \epsilon_c} \right)^8 . - The following coefficients must be defined for each bond type via the :doc:`bond_coeff ` command as in the example above, or in the data file or restart files read by the :doc:`read_data @@ -106,22 +100,11 @@ the data file or restart files read by the :doc:`read_data * :math:`\epsilon_c` (unit less) * :math:`\gamma` (force/velocity units) -If the *normalize* keyword is set to *yes*, the elastic bond force will be -normalized by :math:`r_0` such that :math:`k` must be given in force units. - -By default, pair forces are not calculated between bonded particles. -Pair forces can alternatively be overlaid on top of bond forces by setting -the *overlay/pair* keyword to *yes*. These settings require specific -:doc:`special_bonds ` settings described in the -restrictions. Further details can be found in the :doc:`how to ` -page on BPMs. - -.. versionadded:: 28Mar2023 - -If the *break* keyword is set to *no*, LAMMPS assumes bonds should not break -during a simulation run. This will prevent some unnecessary calculation. -However, if a bond reaches a strain greater than :math:`\epsilon_c`, -it will trigger an error. +Unlike other BPM-style bonds, this bond style does not update special +bond settings when bonds are created or deleted. This bond style also +does not enforce specific :doc:`special_bonds ` settings. +This behavior is purposeful such :doc:`RHEO pair forces ` +and heat flows are still calculated. If the *store/local* keyword is used, an internal fix will track bonds that break during the simulation. Whenever a bond breaks, data is processed @@ -187,39 +170,25 @@ extra quantity can be accessed by the Restrictions """""""""""" -This bond style is part of the BPM package. It is only enabled if +This bond style is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. -By default if pair interactions between bonded atoms are to be disabled, -this bond style requires setting - -.. code-block:: LAMMPS - - special_bonds lj 0 1 1 coul 1 1 1 - -and :doc:`newton ` must be set to bond off. If the *overlay/pair* -keyword is set to *yes*, this bond style alternatively requires setting - -.. code-block:: LAMMPS - - special_bonds lj/coul 1 1 1 - Related commands """""""""""""""" -:doc:`bond_coeff `, :doc:`pair bpm/spring ` +:doc:`bond_coeff `, :doc:`fix rheo/oxidation ` Default """"""" -The option defaults are *overlay/pair* = *no*, *smooth* = *yes*, *normalize* = *no*, and *break* = *yes* +NA ---------- -.. _fragment-Clemmer: +.. _howto_rheo_clemmer: -**(Clemmer)** Clemmer and Robbins, Phys. Rev. Lett. (2022). +**(Clemmer)** Clemmer, Pierce, O'Connor, Nevins, Jones, Lechman, Tencer, Appl. Math. Model., 130, 310-326 (2024). .. _Groot4: diff --git a/doc/src/compute_rheo_property_atom.rst b/doc/src/compute_rheo_property_atom.rst index 7f5de17c3b..8d1cf47f58 100644 --- a/doc/src/compute_rheo_property_atom.rst +++ b/doc/src/compute_rheo_property_atom.rst @@ -27,8 +27,8 @@ Syntax .. parsed-literal:: - *phase* = atom phase status - *chi* = atom phase neighborhood metric + *phase* = atom phase state + *chi* = atom local phase metric *surface* = atom surface status *surface/r* = atom distance from the surface *surface/divr* = divergence of position at atom position @@ -45,6 +45,7 @@ Syntax *status* = atom full status *rho* = atom density *grad/v/\** = atom velocity gradient + *nbond/shell* = number of oxide bonds Examples """""""" @@ -52,21 +53,34 @@ Examples .. code-block:: LAMMPS compute 1 all rheo/property/atom phase surface/r pressure + compute 2 all rheo/property/atom shift/v/x grad/v/xx Description """"""""""" -Define a computation that simply stores atom attributes specific to the -RHEO package for each atom in the group. This is useful so that the -values can be used by other :doc:`output commands ` that -take computes as inputs. See for example, the :doc:`compute reduce -`, :doc:`fix ave/atom `, :doc:`fix -ave/histo `, :doc:`fix ave/chunk `, -and :doc:`atom-style variable ` commands. +.. versionadded:: TBD + +Define a computation that stores atom attributes specific to the RHEO +package for each atom in the group. This is useful so that the values +can be used by other :doc:`output commands ` that take +computes as inputs. See for example, the +:doc:`compute reduce `, +:doc:`fix ave/atom `, +:doc:`fix ave/histo `, +:doc:`fix ave/chunk `, and +:doc:`atom-style variable ` commands. The possible attributes are described in more detail in other RHEO doc -pages include :doc:`fix rheo `, :doc:`pair rheo `, -and :doc:`the RHEO howto page `. +pages including :doc:`the RHEO howto page `. Many +properties require their respective fixes, listed below in related +commands, be defined. + +The *surface/n/\** and *shift/v/\** attributes are vectors that require +specification of the *x*, *y*, or *z* component, e.g. *surface/n/x*. + +The *grad/v/\** attribute is a tensor and requires specification of +the *xx*, *yy*, *zz*, *xy*, *xz*, *yx*, *yz*, *zx*, or *zy* component, +e.g. *grad/v/xy*. The values are stored in a per-atom vector or array as discussed below. Zeroes are stored for atoms not in the specified group or for @@ -98,7 +112,8 @@ Related commands :doc:`fix rheo/viscosity `, :doc:`fix rheo/pressure `, :doc:`fix rheo/thermal `, -:doc:`pair rheo ` +:doc:`fix rheo/oxdiation `, +:doc:`fix rheo ` Default """"""" diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 76d4ae3972..f48dd3fcde 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -43,6 +43,8 @@ Examples Description """"""""""" +.. versionadded:: TBD + Perform time integration for RHEO particles, updating positions, velocities, and densities. For a detailed breakdown of the integration timestep and numerical details, see :ref:`(Palermo) `. For an diff --git a/doc/src/fix_rheo_oxidation.rst b/doc/src/fix_rheo_oxidation.rst index a747ec582f..42e2b6d59e 100644 --- a/doc/src/fix_rheo_oxidation.rst +++ b/doc/src/fix_rheo_oxidation.rst @@ -8,43 +8,42 @@ Syntax .. parsed-literal:: - fix ID group-ID rheo/oxidation cut btype + fix ID group-ID rheo/oxidation cut btype rsurf * ID, group-ID are documented in :doc:`fix ` command * rheo/oxidation = style name of this fix command * cut = maximum bond length (distance units) * btype = type of bonds created +* rsurf = distance from surface to create bonds (distance units) Examples """""""" .. code-block:: LAMMPS - fix 1 all rheo/oxidation 1.5 2 + fix 1 all rheo/oxidation 1.5 2 0.0 + fix 1 all rheo/oxidation 1.0 1 2.0 Description """"""""""" -This fix... +.. versionadded:: TBD -Each list consists of a series of type -ranges separated by commas. The range can be specified as a -single numeric value, or a wildcard asterisk can be used to specify a range -of values. This takes the form "\*" or "\*n" or "n\*" or "m\*n". For -example, if M = the number of atom types, then an asterisk with no numeric -values means all types from 1 to M. A leading asterisk means all types -from 1 to n (inclusive). A trailing asterisk means all types from n to M -(inclusive). A middle asterisk means all types from m to n (inclusive). -Note that all atom types must be included in exactly one of the N collections. +This fix dynamically creates bonds on the surface of fluids to +represent physical processes such as oxidation. It is intended +for use with bond style :doc:`bond rheo/shell `. -While the *Tfreeze* keyword is optional, the *conductivity* and -*specific/heat* keywords are mandatory. +Every timestep, particles check neighbors within a distance of *cut*. +This distance must be smaller than the kernel length defined in +:doc:`fix rheo `. If both particles are on the fluid surface, +or within a distance of *rsurf* from the surface, a bond of type +*btype* is created between the two particles. This process is +further described in Ref. :ref:`(Clemmer) `. -Multiple instances of this fix may be defined to apply different -properties to different groups. However, the union of fix groups -across all instances of fix rheo/thermal must cover all atoms. -If there are multiple instances of this fix, any intersections in -the fix groups will lead to incorrect thermal integration. +If used in conjunction with solid bodies, such as those generated +by the *react* option of :doc:`fix rheo/thermal `, +it is recommended that one uses a :doc:`hybrid bond style ` +with different bond types for solid and oxide bonds. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -58,10 +57,8 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" -This fix must be used with an atom style that includes temperature, -heatflow, and conductivity such as atom_tyle rheo/thermal This fix -must be used in conjuction with :doc:`fix rheo ` with the -*thermal* setting. +This fix must be used with an bond style :doc:`rheo/shell ` +and :doc:`fix rheo ` with surface detection enabled. This fix is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. @@ -70,12 +67,16 @@ Related commands """""""""""""""" :doc:`fix rheo `, -:doc:`fix rheo/viscosity `, -:doc:`fix rheo/pressure `, -:doc:`pair rheo `, +:doc:`bond rheo/shell `, :doc:`compute rheo/property/atom ` Default """"""" none + +---------- + +.. _howto_rheo_clemmer: + +**(Clemmer)** Clemmer, Pierce, O'Connor, Nevins, Jones, Lechman, Tencer, Appl. Math. Model., 130, 310-326 (2024). diff --git a/doc/src/fix_rheo_pressure.rst b/doc/src/fix_rheo_pressure.rst index 2edd703299..f2a994da88 100644 --- a/doc/src/fix_rheo_pressure.rst +++ b/doc/src/fix_rheo_pressure.rst @@ -33,6 +33,8 @@ Examples Description """"""""""" +.. versionadded:: TBD + This fix defines a pressure equation of state for RHEO particles. One can define different equations of state for different atom types, but an equation must be specified for every atom type. diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index 2ece5521bc..63d9f817ad 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -48,6 +48,8 @@ Examples Description """"""""""" +.. versionadded:: TBD + This fix performs time integration of temperature evolution for atom style rheo/thermal. In addition, it defines multiple thermal properties of particles and handles melting/solidification, if applicable. For more details diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst index 64c6539acc..8c403f8d0b 100644 --- a/doc/src/fix_rheo_viscosity.rst +++ b/doc/src/fix_rheo_viscosity.rst @@ -32,6 +32,8 @@ Examples Description """"""""""" +.. versionadded:: TBD + This fix defines a viscosity for RHEO particles. One can define different viscosities for different atom types, but a viscosity must be specified for every atom type. diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst index f6c3d9e3ba..9ad5586b97 100644 --- a/doc/src/pair_rheo.rst +++ b/doc/src/pair_rheo.rst @@ -31,6 +31,8 @@ Examples Description """"""""""" +.. versionadded:: TBD + Pair style *rheo* computes pressure and viscous forces between particles in the :doc:`rheo package `. If thermal evolution is turned on in :doc:`fix rheo `, then the pair style also calculates diff --git a/doc/src/pair_rheo_react.rst b/doc/src/pair_rheo_react.rst deleted file mode 100644 index 6e7eb49c9d..0000000000 --- a/doc/src/pair_rheo_react.rst +++ /dev/null @@ -1,67 +0,0 @@ -.. index:: pair_style rheo/react - -pair_style rheo/react command -========================= - -Syntax -"""""" - -.. code-block:: LAMMPS - - pair_style rheo/react - -Examples -"""""""" - -.. code-block:: LAMMPS - - pair_style rheo/react - pair_coeff * * 1.0 1.5 1.0 0.05 1.0 100 2.0 - -Description -""""""""""" - -pair style... - -The following coefficients must be defined for each pair of atom types -via the :doc:`pair_coeff ` command as in the example above, -or in the data file or restart files read by the -:doc:`read_data ` or :doc:`read_restart ` -commands, or by mixing as described below: - -* :math:`k` (force/distance units) -* :math:`r_max` (distance units) -* :math:`\epsilon` (unitless) -* :math:`\gamma` (force/velocity units) -* :math:`t_form` (time units) -* :math:`r_from_surface` (distance units) - ----------- - -Mixing, shift, table, tail correction, restart, rRESPA info -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -This style does not support the :doc:`pair_modify ` -shift, table, and tail options. - -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and -pair_coeff commands in an input script that reads a restart file. - -This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, *middle*, *outer* keywords. - -Restrictions -"""""""""""" - -This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. - -Related commands -"""""""""""""""" - -:doc:`fix rheo `, -:doc:`compute rheo/property/atom ` - -Default -""""""" - -none diff --git a/doc/src/pair_rheo_solid.rst b/doc/src/pair_rheo_solid.rst index ee86992776..4bac9b726f 100644 --- a/doc/src/pair_rheo_solid.rst +++ b/doc/src/pair_rheo_solid.rst @@ -21,6 +21,8 @@ Examples Description """"""""""" +.. versionadded:: TBD + Style *rheo/solid* is effectively a copy of pair style :doc:`bpm/spring ` except it only applies forces between solid RHEO particles, determined by checking the status of diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 61b83a4542..11b03623b1 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -57,7 +57,8 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; - pressure_flag = thermal_flag = interface_flag = surface_flag = shift_flag = shell_flag = 0; + pressure_flag = thermal_flag = interface_flag = 0; + surface_flag = shift_flag = shell_flag = 0; // parse input values // customize a new keyword by adding to if statement @@ -70,32 +71,34 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a for (int iarg = 3; iarg < narg; iarg++) { i = iarg-3; - if (strcmp(arg[iarg],"phase") == 0) { + if (strcmp(arg[iarg], "phase") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_phase; - } else if (strcmp(arg[iarg],"rho") == 0) { + } else if (strcmp(arg[iarg], "rho") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_rho; - } else if (strcmp(arg[iarg],"chi") == 0) { + } else if (strcmp(arg[iarg], "chi") == 0) { interface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_chi; - } else if (strcmp(arg[iarg],"surface") == 0) { + } else if (strcmp(arg[iarg], "surface") == 0) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface; - } else if (strcmp(arg[iarg],"surface/r") == 0) { + } else if (strcmp(arg[iarg], "surface/r") == 0) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_r; - } else if (strcmp(arg[iarg],"surface/divr") == 0) { + } else if (strcmp(arg[iarg], "surface/divr") == 0) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_divr; } else if (utils::strmatch(arg[iarg], "^surface/n")) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_n; col_index[i] = get_vector_index(arg[iarg]); - } else if (strcmp(arg[iarg],"coordination") == 0) { + } else if (strcmp(arg[iarg], "coordination") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_coordination; - } else if (strcmp(arg[iarg],"pressure") == 0) { + } else if (strcmp(arg[iarg], "pressure") == 0) { pressure_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_pressure; - } else if (strcmp(arg[iarg],"cv") == 0) { + } else if (strcmp(arg[iarg], "viscosity") == 0) { + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_viscosity; + } else if (strcmp(arg[iarg], "cv") == 0) { thermal_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; } else if (utils::strmatch(arg[iarg], "^shift/v")) { @@ -113,7 +116,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a arg[iarg], atom->get_style()); pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; thermal_flag = 1; - } else if (strcmp(arg[iarg],"nbond/shell") == 0) { + } else if (strcmp(arg[iarg], "nbond/shell") == 0) { shell_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_nbond_shell; } else { @@ -124,9 +127,9 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a arg[iarg], atom->get_style()); pack_choice[i] = &ComputeRHEOPropertyAtom::pack_atom_style; - if (strcmp(arg[iarg],"temperature") == 0) thermal_flag = 1; - if (strcmp(arg[iarg],"heatflow") == 0) thermal_flag = 1; - if (strcmp(arg[iarg],"conductivity") == 0) thermal_flag = 1; + if (strcmp(arg[iarg], "temperature") == 0) thermal_flag = 1; + if (strcmp(arg[iarg], "heatflow") == 0) thermal_flag = 1; + if (strcmp(arg[iarg], "conductivity") == 0) thermal_flag = 1; } } @@ -149,7 +152,7 @@ ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() void ComputeRHEOPropertyAtom::init() { auto fixes = modify->get_fix_by_style("^rheo$"); - if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); + if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use compute rheo/property/atom"); fix_rheo = dynamic_cast(fixes[0]); if (interface_flag && !(fix_rheo->interface_flag)) @@ -390,6 +393,21 @@ void ComputeRHEOPropertyAtom::pack_pressure(int n) /* ---------------------------------------------------------------------- */ +void ComputeRHEOPropertyAtom::pack_viscosity(int n) +{ + int *mask = atom->mask; + double *viscosity = atom->viscosity; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = viscosity[i]; + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + void ComputeRHEOPropertyAtom::pack_nbond_shell(int n) { int *nbond = fix_oxidation->nbond; @@ -490,11 +508,11 @@ int ComputeRHEOPropertyAtom::get_tensor_index(char* option) int ComputeRHEOPropertyAtom::get_vector_index(char* option) { int index; - if (utils::strmatch(option,"x$")) { + if (utils::strmatch(option, "x$")) { index = 0; - } else if (utils::strmatch(option,"y$")) { + } else if (utils::strmatch(option, "y$")) { index = 1; - } else if (utils::strmatch(option,"z$")) { + } else if (utils::strmatch(option, "z$")) { if (domain->dimension == 2) error->all(FLERR, "Invalid compute rheo/property/atom property {} in 2D", option); index = 2; diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index fc5c5d1bd0..a61455f0c5 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -35,7 +35,8 @@ class ComputeRHEOPropertyAtom : public Compute { private: int nvalues, nmax; - int pressure_flag, thermal_flag, interface_flag, surface_flag, shift_flag, shell_flag; + int pressure_flag, thermal_flag, interface_flag; + int surface_flag, shift_flag, shell_flag; int *avec_index; int *col_index; double *buf; @@ -55,6 +56,7 @@ class ComputeRHEOPropertyAtom : public Compute { void pack_shift_v(int); void pack_gradv(int); void pack_pressure(int); + void pack_viscosity(int); void pack_nbond_shell(int); void pack_atom_style(int); diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 04b7d33541..98382b07b5 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -19,6 +19,7 @@ #include "fix_rheo.h" #include "atom.h" +#include "citeme.h" #include "compute_rheo_grad.h" #include "compute_rheo_interface.h" #include "compute_rheo_surface.h" @@ -37,6 +38,9 @@ using namespace LAMMPS_NS; using namespace RHEO_NS; using namespace FixConst; +static const char cite_rheo[] = + "TBD\n\n"; + /* ---------------------------------------------------------------------- */ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : @@ -137,6 +141,8 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : } iarg += 1; } + + if (lmp->citeme) lmp->citeme->add(cite_rheo); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index f536df7842..bc31593653 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -20,6 +20,7 @@ #include "atom.h" #include "atom_vec.h" +#include "citeme.h" #include "compute_rheo_surface.h" #include "error.h" #include "fix_rheo.h" @@ -34,6 +35,18 @@ using namespace RHEO_NS; using namespace FixConst; enum {NONE, CONSTANT}; +static const char cite_rheo_oxide[] = + "@article{ApplMathModel.130.310,\n" + " title = {A hybrid smoothed-particle hydrodynamics model of oxide skins on molten aluminum},\n" + " journal = {Applied Mathematical Modelling},\n" + " volume = {130},\n" + " pages = {310-326},\n" + " year = {2024},\n" + " issn = {0307-904X},\n" + " doi = {https://doi.org/10.1016/j.apm.2024.02.027},\n" + " author = {Joel T. Clemmer and Flint Pierce and Thomas C. O'Connor and Thomas D. Nevins and Elizabeth M.C. Jones and Jeremy B. Lechman and John Tencer},\n" + "}\n\n"; + /* ---------------------------------------------------------------------- */ FixRHEOOxidation::FixRHEOOxidation(LAMMPS *lmp, int narg, char **arg) : @@ -51,6 +64,8 @@ FixRHEOOxidation::FixRHEOOxidation(LAMMPS *lmp, int narg, char **arg) : if (rsurf <= 0.0) error->all(FLERR, "Illegal surface distance {} in fix rheo/oxidation", cut); cutsq = cut * cut; + + if (lmp->citeme) lmp->citeme->add(cite_rheo_oxide); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_stress.cpp b/src/RHEO/fix_rheo_stress.cpp deleted file mode 100644 index b391527f1c..0000000000 --- a/src/RHEO/fix_rheo_stress.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* ---------------------------------------------------------------------- - 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. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: Joel Clemmer (SNL) ------------------------------------------------------------------------ */ - -#include "fix_rheo_stress.h" - -#include "atom.h" -#include "comm.h" -#include "compute.h" -#include "domain.h" -#include "fix_store_atom.h" -#include "group.h" -#include "error.h" -#include "modify.h" -#include "update.h" - -#include -#include - -using namespace LAMMPS_NS; -using namespace FixConst; - -/* ---------------------------------------------------------------------- */ - -FixRHEOStress::FixRHEOStress(LAMMPS *lmp, int narg, char **arg) : - id_compute(nullptr), id_fix(nullptr), stress_compute(nullptr), store_fix(nullptr), Fix(lmp, narg, arg) -{ - if (narg != 3) error->all(FLERR,"Illegal fix rheo/stress command"); - comm_forward = 6; -} - -/* ---------------------------------------------------------------------- */ - -FixRHEOStress::~FixRHEOStress() -{ - modify->delete_compute(id_compute); - modify->delete_fix(id_fix); -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOStress::post_constructor() -{ - id_fix = utils::strdup(std::string(id) + "_store"); - store_fix = dynamic_cast(modify->add_fix(fmt::format("{} {} STORE/ATOM d_pxx d_pyy d_pzz d_pxy d_pxz d_pyz", id_fix, group->names[igroup]))); - array_atom = store_fix->astore; - - id_compute = utils::strdup(std::string(id) + "_compute"); - stress_compute = modify->add_compute(fmt::format("{} {} stress/atom NULL ke pair bond", id_compute, group->names[igroup])); -} - -/* ---------------------------------------------------------------------- */ - -int FixRHEOStress::setmask() -{ - int mask = 0; - mask |= PRE_FORCE; - mask |= END_OF_STEP; - return mask; -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOStress::init() -{ - stress_compute->addstep(update->ntimestep+1); -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOStress::pre_force(int vflag) -{ - // add pre-force and forward to ghosts (not done in store/atom) - comm->forward_comm(this); -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOStress::end_of_step() -{ - stress_compute->compute_peratom(); - - // copy compute to fix property atom - double **saved_stress = store_fix->astore; - double **stress = stress_compute->array_atom; - - int ntotal = atom->nlocal+atom->nghost; - for (int i = 0; i < ntotal; i++) - for (int a = 0; a < 6; a++) - saved_stress[i][a] = stress[i][a]; - - stress_compute->addstep(update->ntimestep + 1); -} - -/* ---------------------------------------------------------------------- */ - -int FixRHEOStress::pack_forward_comm(int n, int *list, double *buf, - int /*pbc_flag*/, int * /*pbc*/) -{ - int i, j, a, m; - double **saved_stress = store_fix->astore; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - for (a = 0; a < 6; a++) - buf[m++] = saved_stress[j][a]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOStress::unpack_forward_comm(int n, int first, double *buf) -{ - int i, a, m, last; - double **saved_stress = store_fix->astore; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - for (a = 0; a < 6; a++) - saved_stress[i][a] = buf[m++]; -} diff --git a/src/RHEO/fix_rheo_stress.h b/src/RHEO/fix_rheo_stress.h deleted file mode 100644 index 4bf522793f..0000000000 --- a/src/RHEO/fix_rheo_stress.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - 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. -------------------------------------------------------------------------- */ - -#ifdef FIX_CLASS -// clang-format off -FixStyle(rheo/stress,FixRHEOStress); -// clang-format on -#else - -#ifndef LMP_FIX_RHEO_STRESS_H -#define LMP_FIX_RHEO_STRESS_H - -#include "fix.h" - -namespace LAMMPS_NS { - -class FixRHEOStress : public Fix { - public: - FixRHEOStress(class LAMMPS *, int, char **); - ~FixRHEOStress() override; - void post_constructor() override; - int setmask() override; - void init() override; - void pre_force(int) override; - void end_of_step() override; - int pack_forward_comm(int, int *, double *, int, int *) override; - void unpack_forward_comm(int, int, double *) override; - - private: - char *id_compute, *id_fix; - class Compute *stress_compute; - class FixStoreAtom *store_fix; -}; - -} // namespace LAMMPS_NS - -#endif -#endif diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index a133428d4a..9fbdb8c8f6 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -20,6 +20,7 @@ #include "atom.h" #include "atom_vec.h" +#include "citeme.h" #include "comm.h" #include "compute_rheo_grad.h" #include "compute_rheo_vshift.h" @@ -43,6 +44,18 @@ using namespace RHEO_NS; using namespace FixConst; enum {NONE, CONSTANT}; +static const char cite_rheo_oxide[] = + "@article{ApplMathModel.130.310,\n" + " title = {A hybrid smoothed-particle hydrodynamics model of oxide skins on molten aluminum},\n" + " journal = {Applied Mathematical Modelling},\n" + " volume = {130},\n" + " pages = {310-326},\n" + " year = {2024},\n" + " issn = {0307-904X},\n" + " doi = {https://doi.org/10.1016/j.apm.2024.02.027},\n" + " author = {Joel T. Clemmer and Flint Pierce and Thomas C. O'Connor and Thomas D. Nevins and Elizabeth M.C. Jones and Jeremy B. Lechman and John Tencer},\n" + "}\n\n"; + /* ---------------------------------------------------------------------- */ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : @@ -193,6 +206,8 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : if (Tc_style[i] == NONE && L_style[i] != NONE) error->all(FLERR, "Must specify critical temperature for atom type {} to use latent heat in fix rheo/thermal", i); } + + if (lmp->citeme) lmp->citeme->add(cite_rheo_oxide); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/pair_rheo_react.cpp b/src/RHEO/pair_rheo_react.cpp deleted file mode 100644 index 4709ea169e..0000000000 --- a/src/RHEO/pair_rheo_react.cpp +++ /dev/null @@ -1,515 +0,0 @@ -/* ---------------------------------------------------------------------- - 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. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: - Joel Clemmer (SNL) ------------------------------------------------------------------------ */ - -#include "pair_rheo_react.h" - -#include "atom.h" -#include "comm.h" -#include "compute_rheo_surface.h" -#include "error.h" -#include "fix.h" -#include "fix_dummy.h" -#include "fix_neigh_history.h" -#include "fix_rheo.h" -#include "force.h" -#include "memory.h" -#include "modify.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "neigh_request.h" -#include "update.h" -#include "utils.h" - -using namespace LAMMPS_NS; -using namespace RHEO_NS; - -/* ---------------------------------------------------------------------- */ - -PairRHEOReact::PairRHEOReact(LAMMPS *lmp) : Pair(lmp), - dbond(NULL) -{ - single_enable = 0; - size_history = 2; - beyond_contact = 1; - comm_reverse = 1; - nondefault_history_transfer = 1; - - // create dummy fix as placeholder for FixNeighHistory - // this is so final order of Modify:fix will conform to input script - - fix_history = nullptr; - fix_dummy = dynamic_cast( - modify->add_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY" + std::to_string(instance_me) + " all DUMMY")); - - // For nbond, create an instance of fix property atom - // Need restarts + exchanging with neighbors since it needs to persist - // between timesteps (fix property atom will handle callbacks) - - int tmp1, tmp2; - index_nb = atom->find_custom("react_nbond", tmp1, tmp2); - if (index_nb == -1) { - id_fix = utils::strdup("pair_rheo_react_fix_property_atom"); - modify->add_fix(fmt::format("{} all property/atom i_react_nbond", id_fix)); - index_nb = atom->find_custom("react_nbond", tmp1, tmp2); - } - nbond = atom->ivector[index_nb]; - - //Store non-persistent per atom quantities, intermediate - - nmax_store = atom->nmax; - memory->create(dbond, nmax_store, "rheo/react:dbond"); -} - -/* ---------------------------------------------------------------------- */ - -PairRHEOReact::~PairRHEOReact() -{ - if (modify->nfix && fix_history) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT" + std::to_string(instance_me)); - if (modify->nfix && fix_dummy) modify->delete_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY" + std::to_string(instance_me)); - if (modify->nfix) modify->delete_fix(id_fix); - delete[] id_fix; - - if (allocated) { - memory->destroy(setflag); - memory->destroy(cutsq); - memory->destroy(cutbsq); - - memory->destroy(cutbond); - memory->destroy(k); - memory->destroy(eps); - memory->destroy(gamma); - memory->destroy(t_form); - memory->destroy(rlimit); - } - - memory->destroy(dbond); -} - -/* ---------------------------------------------------------------------- */ - -void PairRHEOReact::compute(int eflag, int vflag) -{ - int i, j, ii, jj, inum, jnum, fluidi, fluidj; - double xtmp, ytmp, ztmp, delx, dely, delz; - double vxtmp, vytmp, vztmp, delvx, delvy, delvz; - double rsq, r, rinv, r0, fpair, dot, smooth; - int itype, jtype; - - int *ilist, *jlist, *numneigh, **firstneigh; - int *saved, **firstsaved; - double *data, *alldata, **firstdata; - - ev_init(eflag,vflag); - - int bondupdate = 1; - if (update->setupflag) bondupdate = 0; - double dt = update->dt; - - double **x = atom->x; - double **v = atom->v; - double **f = atom->f; - int *type = atom->type; - int *status = atom->status; - int *mask = atom->mask; - int *nbond = atom->ivector[index_nb]; - double *rsurf = compute_surface->rsurface; - - int nlocal = atom->nlocal; - int newton_pair = force->newton_pair; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - firstsaved = fix_history->firstflag; - firstdata = fix_history->firstvalue; - - if (atom->nmax > nmax_store){ - nmax_store = atom->nmax; - memory->destroy(dbond); - memory->create(dbond, nmax_store, "rheo/react:dbond"); - } - - size_t nbytes = nmax_store * sizeof(int); - memset(&dbond[0], 0, nbytes); - - // loop over neighbors of my atoms - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - itype = type[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - vxtmp = v[i][0]; - vytmp = v[i][1]; - vztmp = v[i][2]; - fluidi = !(status[i] & PHASECHECK); - - saved = firstsaved[i]; - alldata = firstdata[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - jtype = type[j]; - fluidj = !(status[j] & PHASECHECK); - data = &alldata[2*jj]; - - // If not bonded and there's an internal fluid particle, unsave any data and skip - if (!(saved[jj] == 1 && data[0] > 0)) { - if ((fluidi && (rsurf[i] > rlimit[itype][jtype])) || (fluidj && (rsurf[j] > rlimit[itype][jtype]))) { - saved[jj] = 0; - continue; - } - } - - // If both are solid, unbond and skip - if (!fluidi && !fluidj) { - //If bonded, deincrement - if (saved[jj] == 1 && data[0] > 0) { - dbond[i] --; - dbond[j] --; - } - saved[jj] = 0; - continue; - } - - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx * delx + dely * dely + delz * delz; - - // If unbonded and beyond bond distance, unsave and skip - if (data[0] == -1 && rsq > cutbsq[itype][jtype]) { - saved[jj] = 0; - continue; - } - - r = sqrt(rsq); - // Initialize data if not currently saved since all could bond if they are on the surface - if (saved[jj] == 0) { - data[0] = -1; - data[1] = 0; - saved[jj] = 1; - } - - // Check for bond formation (unbonded) or breakage (bonded) - if (data[0] == -1) { - // If unbonded, check if we count down to bonding if both on surface (not given for r or s) - if (bondupdate && (rsurf[i] <= rlimit[itype][jtype]) && (rsurf[j] <= rlimit[itype][jtype])) { - data[1] += dt; - if (data[1] >= t_form[itype][jtype]) { - data[0] = r; - dbond[i] ++; - dbond[j] ++; - data[1] = 0; - } - } - } else { - // If bonded, check if breaks in tension - r0 = data[0]; - if (r > ((1.0 + eps[itype][jtype]) * r0)) { - saved[jj] = 0; - dbond[i] --; - dbond[j] --; - data[0] = -1; - } - } - - // Skip if unbonded - if (data[0] <= 0) continue; - - delvx = vxtmp - v[j][0]; - delvy = vytmp - v[j][1]; - delvz = vztmp - v[j][2]; - rinv = 1.0 / r; - r0 = data[0]; - - fpair = k[itype][jtype] * (r0 - r); - - dot = delx * delvx + dely * delvy + delz * delvz; - fpair -= gamma[itype][jtype] * dot * rinv; - - smooth = 1.0; - if (r > r0) { - smooth = (r - r0) / (r0 * eps[itype][jtype]); - smooth *= smooth; - smooth *= smooth; - smooth = 1 - smooth; - } - - fpair *= rinv * smooth; - - f[i][0] += delx * fpair; - f[i][1] += dely * fpair; - f[i][2] += delz * fpair; - if (newton_pair || j < nlocal) { - f[j][0] -= delx * fpair; - f[j][1] -= dely * fpair; - f[j][2] -= delz * fpair; - } - - if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.0, 0.0, fpair, delx, dely, delz); - } - } - - // Communicate changes in nbond - if (newton_pair) comm->reverse_comm(this); - - for(i = 0; i < nlocal; i++) { - fluidi = !(status[i] & PHASECHECK); - nbond[i] += dbond[i]; - - // If it has bonds it is reactive (no shifting) - // If a reactive particle breaks all bonds, return to fluid - // Keep it non-shifting for this timestep to be safe - if (nbond[i] != 0 && fluidi) status[i] |= STATUS_NO_SHIFT; - } - - if (vflag_fdotr) virial_fdotr_compute(); -} - -/* ---------------------------------------------------------------------- - allocate all arrays -------------------------------------------------------------------------- */ - -void PairRHEOReact::allocate() -{ - allocated = 1; - int n = atom->ntypes; - - memory->create(setflag, n + 1, n + 1, "pair:setflag"); - for (int i = 1; i <= n; i++) - for (int j = i; j <= n; j++) - setflag[i][j] = 0; - - memory->create(cutbond, n + 1, n + 1, "pair:cutbond"); - memory->create(cutbsq, n + 1, n + 1, "pair:cutbsq"); - memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); - memory->create(k, n + 1, n + 1, "pair:k"); - memory->create(eps, n + 1, n + 1, "pair:eps"); - memory->create(gamma, n + 1, n + 1, "pair:gamma"); - memory->create(t_form, n + 1, n + 1, "pair:t_form"); - memory->create(rlimit, n + 1, n + 1, "pair:rlimit"); -} - -/* ---------------------------------------------------------------------- - global settings - ------------------------------------------------------------------------- */ - -void PairRHEOReact::settings(int narg, char **arg) -{ -} - -/* ---------------------------------------------------------------------- - set coeffs for one or more type pairs -------------------------------------------------------------------------- */ - -void PairRHEOReact::coeff(int narg, char **arg) -{ - if (narg != 9) error->all(FLERR, "Incorrect args for pair coefficients"); - if (!allocated) allocate(); - - int ilo, ihi, jlo, jhi; - utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi,error); - utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi,error); - - double k_one = utils::numeric(FLERR, arg[2], false, lmp); - double cutb_one = utils::numeric(FLERR, arg[3], false, lmp); - double eps_one = utils::numeric(FLERR, arg[4], false, lmp); - double gamma_one = utils::numeric(FLERR, arg[5], false, lmp); - double t_form_one = utils::numeric(FLERR, arg[6], false, lmp); - double rlimit_one = utils::numeric(FLERR, arg[7], false, lmp); - - if (k_one < 0.0 || eps_one < 0.0 || t_form_one < 0.0) - error->all(FLERR, "Illegal pair_style command"); - - int count = 0; - for (int i = ilo; i <= ihi; i++) { - for (int j = MAX(jlo,i); j <= jhi; j++) { - k[i][j] = k_one; - cutbond[i][j] = cutb_one; - eps[i][j] = eps_one; - gamma[i][j] = gamma_one; - t_form[i][j] = t_form_one; - rlimit[i][j] = rlimit_one; - setflag[i][j] = 1; - count++; - } - } - - if (count == 0) error->all(FLERR, "Incorrect args for pair coefficients"); -} - -/* ---------------------------------------------------------------------- - init specific to this pair style -------------------------------------------------------------------------- */ - -void PairRHEOReact::init_style() -{ - int irequest = neighbor->request(this, instance_me); - //neighbor->requests[irequest]->history = 1; - - if (fix_history == nullptr) { - auto cmd = fmt::format("NEIGH_HISTORY_RHEO_REACT{} all NEIGH_HISTORY {}", instance_me, size_history); - fix_history = dynamic_cast( - modify->replace_fix("NEIGH_HISTORY_RHEO_REACT_DUMMY" + std::to_string(instance_me), cmd, 1)); - fix_history->pair = this; - fix_dummy = nullptr; - } -} - -/* ---------------------------------------------------------------------- - setup specific to this pair style - ------------------------------------------------------------------------- */ - -void PairRHEOReact::setup() -{ - auto fixes = modify->get_fix_by_style("^rheo$"); - if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/tension"); - fix_rheo = dynamic_cast(fixes[0]); - - if (!fix_rheo->surface_flag) error->all(FLERR, - "Pair rheo/react requires surface calculation in fix rheo"); - - compute_surface = fix_rheo->compute_surface; - - if (force->newton_pair == 0) error->all(FLERR, - "Pair rheo/react needs newton pair on for bond changes to be consistent"); -} - -/* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i -------------------------------------------------------------------------- */ - -double PairRHEOReact::init_one(int i, int j) -{ - if (setflag[i][j] == 0) error->all(FLERR, "All pair coeffs are not set"); - - cutbsq[i][j] = cutbond[i][j] * cutbond[i][j]; - - cutbsq[j][i] = cutbsq[i][j]; - cutbond[j][i] = cutbond[i][j]; - k[j][i] = k[i][j]; - eps[j][i] = eps[i][j]; - gamma[j][i] = gamma[i][j]; - t_form[j][i] = t_form[i][j]; - rlimit[j][i] = rlimit[i][j]; - - double cut = cutbond[i][j] * (1.0 + eps[i][j]); - - return cut; -} - -/* ---------------------------------------------------------------------- - proc 0 writes to restart file -------------------------------------------------------------------------- */ - -void PairRHEOReact::write_restart(FILE *fp) -{ - write_restart_settings(fp); - - int i,j; - for (i = 1; i <= atom->ntypes; i++) - for (j = i; j <= atom->ntypes; j++) - fwrite(&setflag[i][j], sizeof(int), 1, fp); - if (setflag[i][j]) { - fwrite(&k[i][j], sizeof(double), 1, fp); - fwrite(&cutbond[i][j], sizeof(double), 1, fp); - fwrite(&eps[i][j], sizeof(double), 1, fp); - fwrite(&gamma[i][j], sizeof(double), 1, fp); - fwrite(&t_form[i][j], sizeof(double), 1, fp); - fwrite(&rlimit[i][j], sizeof(double), 1, fp); - } -} - -/* ---------------------------------------------------------------------- - proc 0 reads from restart file, bcasts -------------------------------------------------------------------------- */ - -void PairRHEOReact::read_restart(FILE *fp) -{ - read_restart_settings(fp); - allocate(); - - int i,j; - int me = comm->me; - for (i = 1; i <= atom->ntypes; i++) - for (j = i; j <= atom->ntypes; j++) { - if (me == 0) utils::sfread(FLERR, &setflag[i][j], sizeof(int), 1, fp, nullptr, error); - MPI_Bcast(&setflag[i][j], 1, MPI_INT, 0, world); - if (setflag[i][j]) { - if (me == 0) { - utils::sfread(FLERR, &k[i][j], sizeof(double), 1, fp, nullptr, error); - utils::sfread(FLERR, &cutbond[i][j], sizeof(double), 1, fp, nullptr, error); - utils::sfread(FLERR, &eps[i][j], sizeof(double), 1, fp, nullptr, error); - utils::sfread(FLERR, &gamma[i][j], sizeof(double), 1, fp, nullptr, error); - utils::sfread(FLERR, &t_form[i][j], sizeof(double), 1, fp, nullptr, error); - utils::sfread(FLERR, &rlimit[i][j], sizeof(double), 1, fp, nullptr, error); - } - MPI_Bcast(&k[i][j], 1,MPI_DOUBLE, 0, world); - MPI_Bcast(&cutbond[i][j], 1,MPI_DOUBLE, 0, world); - MPI_Bcast(&eps[i][j], 1,MPI_DOUBLE, 0, world); - MPI_Bcast(&gamma[i][j], 1,MPI_DOUBLE, 0, world); - MPI_Bcast(&t_form[i][j], 1,MPI_DOUBLE, 0, world); - MPI_Bcast(&rlimit[i][j], 1,MPI_DOUBLE, 0, world); - } - } -} - - - - -/* ---------------------------------------------------------------------- - transfer history during fix/neigh/history exchange - transfer same sign -------------------------------------------------------------------------- */ - -void PairRHEOReact::transfer_history(double* source, double* target) -{ - for (int i = 0; i < size_history; i++) - target[i] = source[i]; -} - -/* ---------------------------------------------------------------------- */ - -int PairRHEOReact::pack_reverse_comm(int n, int first, double *buf) -{ - int i, m, last; - m = 0; - last = first + n; - - for (i = first; i < last; i++) { - buf[m++] = dbond[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void PairRHEOReact::unpack_reverse_comm(int n, int *list, double *buf) -{ - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - dbond[j] += buf[m++]; - } -} diff --git a/src/RHEO/pair_rheo_react.h b/src/RHEO/pair_rheo_react.h deleted file mode 100644 index 88d5dbeb0e..0000000000 --- a/src/RHEO/pair_rheo_react.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - 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. -------------------------------------------------------------------------- */ - -#ifdef PAIR_CLASS -// clang-format off -PairStyle(rheo/react,PairRHEOReact) -// clang-format on -#else - -#ifndef LMP_PAIR_RHEO_REACT_H -#define LMP_PAIR_RHEO_REACT_H - -#include "pair.h" - -namespace LAMMPS_NS { - -class PairRHEOReact : public Pair { - public: - PairRHEOReact(class LAMMPS *); - ~PairRHEOReact() override; - void compute(int, int) override; - void settings(int, char **) override; - void coeff(int, char **) override; - void init_style() override; - void setup() override; - double init_one(int, int) override; - void write_restart(FILE *) override; - void read_restart(FILE *) override; - int pack_reverse_comm(int, int, double *) override; - void unpack_reverse_comm(int, int *, double *) override; - - protected: - double **cutbond, **cutbsq, **k, **eps, **gamma, **t_form, **rlimit; - - void allocate(); - void transfer_history(double*, double*); - - int size_history; - int *dbond, *nbond; - - int index_nb, nmax_store; - char *id_fix; - - class FixDummy *fix_dummy; - class FixNeighHistory *fix_history; - class FixRHEO *fix_rheo; - class ComputeRHEOSurface *compute_surface; -}; - -} // namespace LAMMPS_NS - -#endif -#endif From 1135d6be64b7b2bd2fb1c0ffbebca2f6f7283197 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 10 Apr 2024 10:44:41 -0600 Subject: [PATCH 078/385] Noting artificial/visc exception in doc --- doc/src/pair_rheo.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst index f6c3d9e3ba..be7311c480 100644 --- a/doc/src/pair_rheo.rst +++ b/doc/src/pair_rheo.rst @@ -39,7 +39,10 @@ heat exchanged between particles. The *artificial/viscosity* keyword is used to specify the magnitude :math:`\zeta` of an optional artificial viscosity contribution to forces. This factor can help stabilize simulations by smoothing out small length -scale variations in velocity fields. +scale variations in velocity fields. Artificial viscous forces are only +exchanged by fluid particles unless interfaces are not reconstructed in +fix rheo, in which fluid particles will also exchange artificial viscous +forces with solid particles to improve stability. The *rho/damp* keyword is used to specify the magnitude :math:`\xi` of an optional pairwise damping term between the density of particles. This From 4220be380c3b4aa487dc85710d08d7cafa3dbbbd Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 24 Apr 2024 11:48:44 -0600 Subject: [PATCH 079/385] Finishing oxidation, adding hybrid compatability for BPM --- doc/src/Howto_rheo.rst | 8 +- doc/src/fix_rheo.rst | 20 +++-- src/.gitignore | 2 + src/BPM/bond_bpm.cpp | 2 +- src/GRANULAR/fix_add_heat.cpp | 138 ++++++++++++++++++++++++++++++++ src/GRANULAR/fix_add_heat.h | 45 +++++++++++ src/RHEO/bond_rheo_shell.cpp | 23 ++++-- src/RHEO/fix_rheo_oxidation.cpp | 21 +---- src/RHEO/fix_rheo_thermal.cpp | 6 +- src/RHEO/pair_rheo.cpp | 2 +- src/bond_hybrid.cpp | 26 ++++++ src/bond_hybrid.h | 1 + src/fix_bond_history.cpp | 13 +-- src/fix_bond_history.h | 3 +- 14 files changed, 260 insertions(+), 50 deletions(-) create mode 100644 src/GRANULAR/fix_add_heat.cpp create mode 100644 src/GRANULAR/fix_add_heat.h diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index db710d2366..748c91845b 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -31,9 +31,9 @@ properties like positions and forces, particles store a local density, viscosity, pressure, and status. If thermal evolution is modeled, one must use atom style rheo/thermal which also include a local temperature and conductivity. The status variable uses bitmasking to track various -properties of a particle such as its current phase (fluid or solid) and its -location relative to a surface. Many of these properties (and others) can -be easily accessed using +properties of a particle such as its current state of matter (fluid or solid) +and its location relative to a surface. Many of these properties (and others) +can be easily accessed using :doc:`compute rheo/property/atom `. Fluid interactions, including pressure forces, viscous forces, and heat exchange, @@ -84,7 +84,7 @@ breaking if stretched too far. Unlike the above method, this option does not rem the underlying fluid interactions (although particle shifting is turned off) and does not modify special bond settings of particles. -While these two options are not expected to be appropriate for every multiphase system, +While these two options are not expected to be appropriate for every system, either framework can be modified to create more suitable models (e.g. by changing the criteria for creating/deleting a bond or altering force calculations). diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index f48dd3fcde..5c46ad892e 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -80,14 +80,18 @@ surfaces. A modified form of Fickian particle shifting can be enabled with the *shift* keyword. This effectively shifts particle positions to generate a -more uniform spatial distribution. In systems with free surfaces, the -*surface/detection* keyword can be used to classify the location of -particles as being within the bulk fluid, on a free surface, or isolated -from other particles in a splash or droplet. Shifting is then disabled in -the direction away from the free surface to prevent it from diffusing -particles away from the bulk fluid. Surface detection can also be used -to control surface-nucleated effects like oxidation when used in combination -with :doc:`fix rheo/oxidation `. +more uniform spatial distribution. Shifting currently does consider the +type of a particle and therefore may be inappropriate in systems consisting +of multiple materials. + +In systems with free surfaces, the *surface/detection* keyword can be used +to classify the location of particles as being within the bulk fluid, on a +free surface, or isolated from other particles in a splash or droplet. +Shifting is then disabled in the direction away from the free surface to +prevent it from diffusing particles away from the bulk fluid. Surface +detection can also be used to control surface-nucleated effects like +oxidation when used in combination with +:doc:`fix rheo/oxidation `. The *surface/detection* keyword takes three arguments: *sdstyle*, *limit*, and *limi/splash*. The first, *sdstyle*, specifies whether surface particles diff --git a/src/.gitignore b/src/.gitignore index a77c6c58a6..1bf840cf31 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -765,6 +765,8 @@ /fix_acks2_reaxff.h /fix_adapt_fep.cpp /fix_adapt_fep.h +/fix_add_heat.cpp +/fix_add_heat.h /fix_addtorque.cpp /fix_addtorque.h /fix_append_atoms.cpp diff --git a/src/BPM/bond_bpm.cpp b/src/BPM/bond_bpm.cpp index 351cff1420..b0ebc37257 100644 --- a/src/BPM/bond_bpm.cpp +++ b/src/BPM/bond_bpm.cpp @@ -71,7 +71,7 @@ BondBPM::~BondBPM() if (id_fix_dummy) modify->delete_fix(id_fix_dummy); if (id_fix_dummy2) modify->delete_fix(id_fix_dummy2); if (id_fix_update) modify->delete_fix(id_fix_update); - if (id_fix_bond_history) modify->delete_fix(id_fix_bond_history); + if (fix_bond_history) modify->delete_fix(id_fix_bond_history); if (id_fix_store_local) modify->delete_fix(id_fix_store_local); if (id_fix_prop_atom) modify->delete_fix(id_fix_prop_atom); diff --git a/src/GRANULAR/fix_add_heat.cpp b/src/GRANULAR/fix_add_heat.cpp new file mode 100644 index 0000000000..2db3389560 --- /dev/null +++ b/src/GRANULAR/fix_add_heat.cpp @@ -0,0 +1,138 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Joel Clemmer (SNL) +------------------------------------------------------------------------- */ + +#include "fix_add_heat.h" + +#include "atom.h" +#include "error.h" +#include "input.h" +#include "memory.h" +#include "update.h" +#include "variable.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +enum { NONE, CONSTANT, EQUAL, ATOM }; + +/* ---------------------------------------------------------------------- */ + +FixAddHeat::FixAddHeat(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg), varstr(nullptr), qatom(nullptr) +{ + if (narg < 4) utils::missing_cmd_args(FLERR, "fix add/heat", error); + dynamic_group_allow = 1; + overwrite_flag = 0; + + style = NONE; + if (utils::strmatch(arg[3], "^v_")) { + varstr = utils::strdup(arg[3] + 2); + } else { + value = utils::numeric(FLERR, arg[3], false, lmp); + style = CONSTANT; + } + + // optional args + + int iarg = 4; + while (iarg < narg) { + if (strcmp(arg[iarg], "overwrite") == 0) { + overwrite_flag = 1; + iarg += 1; + } else + error->all(FLERR, "Illegal fix viscous command"); + } + + maxatom = -1; +} + +/* ---------------------------------------------------------------------- */ + +FixAddHeat::~FixAddHeat() +{ + delete[] varstr; + memory->destroy(qatom); +} + +/* ---------------------------------------------------------------------- */ + +int FixAddHeat::setmask() +{ + int mask = 0; + mask |= POST_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixAddHeat::init() +{ + if (!atom->temperature_flag) + error->all(FLERR, "Fix add/heat requires atom style with temperature property"); + if (!atom->heatflow_flag) + error->all(FLERR, "Fix add/heat requires atom style with heatflow property"); + + // check variable + + if (varstr) { + var = input->variable->find(varstr); + if (var < 0) error->all(FLERR, "Variable {} for fix addforce does not exist", varstr); + if (input->variable->equalstyle(var)) + style = EQUAL; + else if (input->variable->atomstyle(var)) + style = ATOM; + else + error->all(FLERR, "Variable {} for fix addforce is invalid style", varstr); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixAddHeat::post_force(int /*vflag*/) +{ + int *mask = atom->mask; + double *heatflow = atom->heatflow; + double dtinv = 1.0 / update->dt; + + if (overwrite_flag) { + for (int i = 0; i < atom->nlocal; i++) + if (mask[i] & groupbit) + heatflow[i] = 0.0; + } + + if (style == CONSTANT) { + for (int i = 0; i < atom->nlocal; i++) + if (mask[i] & groupbit) + heatflow[i] += value * dtinv; + } else if (style == EQUAL) { + value = input->variable->compute_equal(var); + for (int i = 0; i < atom->nlocal; i++) + if (mask[i] & groupbit) + heatflow[i] += value * dtinv; + } else if (style == ATOM) { + + if (atom->nmax > maxatom) { + maxatom = atom->nmax; + memory->destroy(qatom); + memory->create(qatom, maxatom, "addheat:qatom"); + } + input->variable->compute_atom(var, igroup, &qatom[0], 1, 0); + for (int i = 0; i < atom->nlocal; i++) + if (mask[i] & groupbit) + heatflow[i] += qatom[i] * dtinv; + } +} diff --git a/src/GRANULAR/fix_add_heat.h b/src/GRANULAR/fix_add_heat.h new file mode 100644 index 0000000000..8a51f13ee4 --- /dev/null +++ b/src/GRANULAR/fix_add_heat.h @@ -0,0 +1,45 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS +// clang-format off +FixStyle(add/heat,FixAddHeat); +// clang-format on +#else + +#ifndef LMP_FIX_ADD_HEAT_H +#define LMP_FIX_ADD_HEAT_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixAddHeat : public Fix { + public: + FixAddHeat(class LAMMPS *, int, char **); + ~FixAddHeat() override; + int setmask() override; + void init() override; + void post_force(int) override; + + protected: + double value; + int var, style, maxatom, overwrite_flag; + char *varstr; + double *qatom; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index 0a3caa1b4f..6b464c4000 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -199,7 +199,6 @@ void BondRHEOShell::compute(int eflag, int vflag) memset(&dbond[0], 0, nbytes); for (n = 0; n < nbondlist; n++) { - // skip bond if already broken if (bondlist[n][2] <= 0) continue; @@ -218,8 +217,16 @@ void BondRHEOShell::compute(int eflag, int vflag) i2 = itmp; } - // If bond hasn't been set - set timer to zero - if (t < EPSILON || std::isnan(t)) r0 = store_bond(n, i1, i2); + delx = x[i1][0] - x[i2][0]; + dely = x[i1][1] - x[i2][1]; + delz = x[i1][2] - x[i2][2]; + rsq = delx * delx + dely * dely + delz * delz; + r = sqrt(rsq); + + // If bond hasn't been set - zero data + if (t < EPSILON || std::isnan(t)) + t = store_bond(n, i1, i2); + delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; @@ -239,8 +246,9 @@ void BondRHEOShell::compute(int eflag, int vflag) } // Check ellapsed time - bondstore[n][1] += dt; - if (bondstore[n][1] >= tform) { + t += dt; + bondstore[n][1] = t; + if (t >= tform) { bondstore[n][0] = r; r0 = r; if (newton_bond || i1 < nlocal) dbond[i1] ++; @@ -285,7 +293,6 @@ void BondRHEOShell::compute(int eflag, int vflag) if (evflag) ev_tally(i1, i2, nlocal, newton_bond, 0.0, fbond, delx, dely, delz); } - // Communicate changes in nbond if (newton_bond) comm->reverse_comm(this); @@ -555,7 +562,7 @@ void BondRHEOShell::process_ineligibility(int i, int j) bond_type[i][m] = bond_type[i][n - 1]; bond_atom[i][m] = bond_atom[i][n - 1]; for (auto &ihistory: histories) { - auto fix_bond_history2 = dynamic_cast (ihistory); + auto fix_bond_history2 = dynamic_cast (ihistory); fix_bond_history2->shift_history(i, m, n - 1); fix_bond_history2->delete_history(i, n - 1); } @@ -573,7 +580,7 @@ void BondRHEOShell::process_ineligibility(int i, int j) bond_type[j][m] = bond_type[j][n - 1]; bond_atom[j][m] = bond_atom[j][n - 1]; for (auto &ihistory: histories) { - auto fix_bond_history2 = dynamic_cast (ihistory); + auto fix_bond_history2 = dynamic_cast (ihistory); fix_bond_history2->shift_history(j, m, n - 1); fix_bond_history2->delete_history(j, n - 1); } diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index bc31593653..46eaab3bf1 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -108,7 +108,7 @@ void FixRHEOOxidation::init() nbond = atom->ivector[index_nb]; // need a half neighbor list - auto req = neighbor->add_request(this, NeighConst::REQ_DEFAULT); + auto req = neighbor->add_request(this, NeighConst::REQ_FULL); req->set_cutoff(cut); } @@ -200,31 +200,16 @@ void FixRHEOOxidation::post_integrate() } if (bflag) continue; - for (n = 0; n < num_bond[j]; n++) { - if (bond_type[j][n] == btype && bond_atom[j][n] == tagi) { - bflag = 1; - break; - } - } - if (bflag) continue; - // Add bonds to owned atoms // If newton bond, add to both, otherwise add to whichever has a smaller tag - if (i < nlocal && (!newton_bond || tagi < tagj)) { + + if (!newton_bond || tagi < tagj) { if (num_bond[i] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/oxidation for atom {}", tagi); bond_type[i][num_bond[i]] = btype; bond_atom[i][num_bond[i]] = tagj; num_bond[i]++; } - - if (j < nlocal && (!newton_bond || tagj < tagi)) { - if (num_bond[j] == atom->bond_per_atom) - error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/oxidation for atom {}", tagj); - bond_type[j][num_bond[j]] = btype; - bond_atom[j][num_bond[j]] = tagi; - num_bond[j]++; - } } } } diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 9fbdb8c8f6..3a39bbe596 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -543,8 +543,8 @@ void FixRHEOThermal::break_bonds() // Update bond list and break solid-melted bonds for (n = 0; n < nbondlist; n++) { - // skip bond if already broken - if (bondlist[n][2] <= 0) continue; + // skip bond if not correct type + if (bondlist[n][2] != btype) continue; i = bondlist[n][0]; j = bondlist[n][1]; @@ -561,7 +561,7 @@ void FixRHEOThermal::break_bonds() bond_atom[i][m] = bond_atom[i][nmax]; if (n_histories > 0) for (auto &ihistory: histories) { - auto fix_bond_history = dynamic_cast (ihistory); + auto fix_bond_history = dynamic_cast (ihistory); fix_bond_history->shift_history(i, m, nmax); fix_bond_history->delete_history(i, nmax); } diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index cb33b20bea..6e8c20a5d8 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -189,7 +189,7 @@ void PairRHEO::compute(int eflag, int vflag) pair_avisc_flag = 0; if (fluidi || fluidj) { pair_force_flag = 1; - if (interface_flag) pair_avisc_flag = 1; + if (!interface_flag) pair_avisc_flag = 1; } if (fluidi && fluidj) { pair_rho_flag = 1; diff --git a/src/bond_hybrid.cpp b/src/bond_hybrid.cpp index 5f84db1886..910e9a5574 100644 --- a/src/bond_hybrid.cpp +++ b/src/bond_hybrid.cpp @@ -34,6 +34,7 @@ BondHybrid::BondHybrid(LAMMPS *lmp) : Bond(lmp) nstyles = 0; has_quartic = -1; nbondlist = nullptr; + orig_map = nullptr; maxbond = nullptr; bondlist = nullptr; } @@ -55,6 +56,7 @@ BondHybrid::~BondHybrid() memory->destroy(setflag); memory->destroy(map); delete[] nbondlist; + delete[] orig_map; delete[] maxbond; for (int i = 0; i < nstyles; i++) memory->destroy(bondlist[i]); delete[] bondlist; @@ -88,6 +90,10 @@ void BondHybrid::compute(int eflag, int vflag) memory->destroy(bondlist[m]); maxbond[m] = nbondlist[m] + EXTRA; memory->create(bondlist[m], maxbond[m], 3, "bond_hybrid:bondlist"); + if (partial_flag) { + memory->destroy(orig_map[m]); + memory->create(orig_map[m], maxbond[m], "bond_hybrid:orig_map"); + } } nbondlist[m] = 0; } @@ -98,6 +104,8 @@ void BondHybrid::compute(int eflag, int vflag) bondlist[m][n][0] = bondlist_orig[i][0]; bondlist[m][n][1] = bondlist_orig[i][1]; bondlist[m][n][2] = bondlist_orig[i][2]; + if (partial_flag) + orig_map[m][n] = i; nbondlist[m]++; } } @@ -142,6 +150,19 @@ void BondHybrid::compute(int eflag, int vflag) } } + // if bond type can be set to zero and deleted, update bondlist_orig + tagint *tag = atom->tag; + if (partial_flag) { + for (m = 0; m < nstyles; m++) { + for (i = 0; i < nbondlist[m]; i++) { + if (bondlist[m][i][2] <= 0) { + n = orig_map[m][i]; + bondlist_orig[n][2] = bondlist[m][i][2]; + } + } + } + } + // restore ptrs to original bondlist neighbor->nbondlist = nbondlist_orig; @@ -161,9 +182,11 @@ void BondHybrid::allocate() nbondlist = new int[nstyles]; maxbond = new int[nstyles]; + orig_map = new int *[nstyles]; bondlist = new int **[nstyles]; for (int m = 0; m < nstyles; m++) maxbond[m] = 0; for (int m = 0; m < nstyles; m++) bondlist[m] = nullptr; + for (int m = 0; m < nstyles; m++) orig_map[m] = nullptr; } /* ---------------------------------------------------------------------- @@ -191,6 +214,8 @@ void BondHybrid::settings(int narg, char **arg) memory->destroy(map); delete[] nbondlist; delete[] maxbond; + for (i = 0; i < nstyles; i++) memory->destroy(orig_map[i]); + delete[] orig_map; for (i = 0; i < nstyles; i++) memory->destroy(bondlist[i]); delete[] bondlist; } @@ -355,6 +380,7 @@ void BondHybrid::init_style() // to create an entry for it in the bond type to sub-style map if (has_quartic >= 0) map[0] = has_quartic; + else map[0] = -1; } /* ---------------------------------------------------------------------- diff --git a/src/bond_hybrid.h b/src/bond_hybrid.h index df1437c038..282a719be5 100644 --- a/src/bond_hybrid.h +++ b/src/bond_hybrid.h @@ -50,6 +50,7 @@ class BondHybrid : public Bond { int *nbondlist; // # of bonds in sub-style bondlists int *maxbond; // max # of bonds sub-style lists can store int ***bondlist; // bondlist for each sub-style + int **orig_map; // location of substyle bond in original bondlist void allocate(); void flags(); diff --git a/src/fix_bond_history.cpp b/src/fix_bond_history.cpp index 8fa0b3f923..c2be1d481c 100644 --- a/src/fix_bond_history.cpp +++ b/src/fix_bond_history.cpp @@ -324,12 +324,13 @@ void FixBondHistory::compress_history() if (update_flag || (neighbor->ago == 0)) { for (int n = 0; n < nbondlist_orig; n++) { type = bondtype_orig[n]; + if (type <= 0) continue; - if (setflag[type]) { - for (int m = 0; m < ndata; m++) - bondstore_comp[ncomp][m] = bondstore[n][m]; - ncomp += 1; - } + if (!setflag[type]) continue; + + for (int m = 0; m < ndata; m++) + bondstore_comp[ncomp][m] = bondstore[n][m]; + ncomp += 1; } } @@ -352,7 +353,7 @@ void FixBondHistory::uncompress_history() if (!setflag[type]) continue; for (int m = 0; m < ndata; m++) - bondstore[n][m] = bondstore_comp[ncomp][m]; + bondstore_orig[n][m] = bondstore[ncomp][m]; ncomp += 1; } } diff --git a/src/fix_bond_history.h b/src/fix_bond_history.h index 8ee3132ab1..880a31eb35 100644 --- a/src/fix_bond_history.h +++ b/src/fix_bond_history.h @@ -64,6 +64,7 @@ class FixBondHistory : public Fix { int *setflag; // Set by BondBPM, which bond types are used double **bondstore; int stored_flag; + int ndata; protected: void allocate(); @@ -76,7 +77,7 @@ class FixBondHistory : public Fix { int update_flag; // Flag whether history values can evolve int updated_bond_flag; - int nbond, maxbond, ndata; + int nbond, maxbond; int index; char *id_fix; char *id_array; From 21cae39d140c94e08fead15cff6a142c217a81f0 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 24 Apr 2024 13:04:51 -0600 Subject: [PATCH 080/385] Documentation for fix add/heat --- doc/src/fix_add_heat.rst | 87 ++++++++++++++++++++++++++++++++++++ doc/src/fix_heat_flow.rst | 10 ++++- doc/src/fix_rheo_thermal.rst | 3 +- 3 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 doc/src/fix_add_heat.rst diff --git a/doc/src/fix_add_heat.rst b/doc/src/fix_add_heat.rst new file mode 100644 index 0000000000..3964c96b27 --- /dev/null +++ b/doc/src/fix_add_heat.rst @@ -0,0 +1,87 @@ +.. index:: fix add/heat + +fix add/heat command +==================== + +Syntax +"""""" + +.. code-block:: LAMMPS + + fix ID group-ID add/heat rate values ... + +* ID, group-ID are documented in :doc:`fix ` command +* add/heat = style name of this fix command +* rate = rate of heat flow (energy/time units) +* zero or more keyword/value pairs may be appended to args +* keyword = *overwrite* + + .. parsed-literal:: + + *overwrite* = sets the heat flow instead of adding it + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix 1 all add/heat v_heat + fix 1 all add/heat 1.0 overwrite + +Description +""""""""""" + +This fix adds heat to particles every timestep at a given rate. The rate +can be can be specified as an equal-style or atom-style +:doc:`variable `. If the value is a variable, it should be +specified as v_name, where name is the variable name. In this case, the +variable will be evaluated each time step, and its value will be used to +determine the rate of heat added. + +Equal-style variables can specify formulas with various mathematical +functions and include :doc:`thermo_style ` command +keywords for the simulation box parameters, time step, and elapsed time. +Thus, it is easy to specify time-dependent heating. + +Atom-style variables can specify the same formulas as equal-style +variables but can also include per-atom values, such as atom +coordinates. Thus, it is easy to specify a spatially-dependent heating +field with optional time-dependence as well. + +If the *overwrite* keyword is specified, this fix will effectively set +the total heat flow on a particle, overwriting contributions from other +pair styles. + +---------- + +Restart, fix_modify, output, run start/stop, minimize info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +No information about this fix is written to :doc:`binary restart files `. +None of the :doc:`fix_modify ` options are relevant to this fix. +No global or per-atom quantities are stored by this fix for access by various +:doc:`output commands `. No parameter of this fix can be used +with the *start/stop* keywords of the :doc:`run ` command. This fix is +not invoked during :doc:`energy minimization `. + +Restrictions +"""""""""""" + +This pair style is part of the GRANULAR package. It is +only enabled if LAMMPS was built with that package. +See the :doc:`Build package ` page for more info. + +This fix requires that atoms store temperature and heat flow +as defined by the :doc:`fix property/atom ` command. + +Related commands +"""""""""""""""" + +:doc:`fix heat/flow `, +:doc:`fix property/atom `, +:doc:`fix rheo/thermal ` + +Default +""""""" + +none diff --git a/doc/src/fix_heat_flow.rst b/doc/src/fix_heat_flow.rst index 1ca99a1686..aa2b3fbc06 100644 --- a/doc/src/fix_heat_flow.rst +++ b/doc/src/fix_heat_flow.rst @@ -1,7 +1,7 @@ .. index:: fix heat/flow fix heat/flow command -========================== +===================== Syntax """""" @@ -56,13 +56,19 @@ not invoked during :doc:`energy minimization `. Restrictions """""""""""" +This pair style is part of the GRANULAR package. It is +only enabled if LAMMPS was built with that package. +See the :doc:`Build package ` page for more info. + This fix requires that atoms store temperature and heat flow as defined by the :doc:`fix property/atom ` command. Related commands """""""""""""""" -:doc:`pair granular `, :doc:`fix property/atom ` +:doc:`pair granular `, +:doc:`fix add/heat `, +:doc:`fix property/atom ` Default """"""" diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index 63d9f817ad..2ffb665bb7 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -109,7 +109,8 @@ Related commands :doc:`fix rheo `, :doc:`pair rheo `, -:doc:`compute rheo/property/atom ` +:doc:`compute rheo/property/atom `, +:doc:`fix add/heat ` Default """"""" From 7ad74ffbd8eba648d9cbf2cbbb183ea13904ea36 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 24 Apr 2024 13:10:44 -0600 Subject: [PATCH 081/385] Removing unused files --- src/RHEO/fix_rheo_tension.cpp | 718 ---------------------------------- src/RHEO/fix_rheo_tension.h | 59 --- 2 files changed, 777 deletions(-) delete mode 100644 src/RHEO/fix_rheo_tension.cpp delete mode 100644 src/RHEO/fix_rheo_tension.h diff --git a/src/RHEO/fix_rheo_tension.cpp b/src/RHEO/fix_rheo_tension.cpp deleted file mode 100644 index 388b574365..0000000000 --- a/src/RHEO/fix_rheo_tension.cpp +++ /dev/null @@ -1,718 +0,0 @@ -/* ---------------------------------------------------------------------- - 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. - ------------------------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - Contributing authors: - Joel Clemmer (SNL) ------------------------------------------------------------------------ */ - -// Todo: -// add citations -// remove (or fix) pairwise forces on undercoordinated atoms -// add option for vacuum tension (Frustenau 2020?) - -#include "fix_rheo_tension.h" - -#include "atom.h" -#include "comm.h" -#include "compute_rheo_kernel.h" -#include "compute_rheo_interface.h" -#include "compute_rheo_vshift.h" -#include "domain.h" -#include "error.h" -#include "fix_rheo.h" -#include "force.h" -#include "math_extra.h" -#include "memory.h" -#include "modify.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "update.h" -#include "utils.h" - -#include - -using namespace LAMMPS_NS; -using namespace RHEO_NS; -using namespace MathExtra; -using namespace FixConst; - -/* ---------------------------------------------------------------------- */ - -FixRHEOTension::FixRHEOTension(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), compute_kernel(nullptr), compute_interface(nullptr), compute_vshift(nullptr), fix_rheo(nullptr), rho0(nullptr) -{ - if (narg != 8) error->all(FLERR,"Illegal fix command"); - alpha = utils::numeric(FLERR, arg[3], false, lmp); - beta = utils::numeric(FLERR, arg[4], false, lmp); - wmin = utils::numeric(FLERR, arg[5], false, lmp); - cmin = utils::numeric(FLERR, arg[6], false, lmp); - vshift_strength = utils::numeric(FLERR, arg[7], false, lmp); - - comm_forward = 3; - comm_reverse = 3; - - // Create cgrad, n, and divr arrays as custom atom properties, - // can print with compute property/atom - // no grow callback as there's no reason to copy/exchange data, manually grow - // For norm, create a local array since they are unlikely to be printed - - int tmp1, tmp2; - index_ct = atom->find_custom("c_rheo_tension", tmp1, tmp2); - if (index_ct == -1) index_ct = atom->add_custom("c_rheo_tension", 1, 0); - ct = atom->dvector[index_ct]; - - index_cgradt = atom->find_custom("cgrad_rheo_tension", tmp1, tmp2); - if (index_cgradt == -1) index_cgradt = atom->add_custom("cgrad_rheo_tension", 1, 3); - cgradt = atom->darray[index_cgradt]; - - index_nt = atom->find_custom("n_rheo_tension", tmp1, tmp2); - if (index_nt == -1) index_nt = atom->add_custom("n_rheo_tension", 1, 3); - nt = atom->darray[index_nt]; - - index_divnt = atom->find_custom("divn_rheo_tension", tmp1, tmp2); - if (index_divnt == -1) index_divnt = atom->add_custom("divn_rheo_tension", 1, 0); - divnt = atom->dvector[index_divnt]; - - index_wsame = atom->find_custom("wsame_rheo_tension", tmp1, tmp2); - if (index_wsame == -1) index_wsame = atom->add_custom("wsame_rheo_tension", 1, 0); - wsame = atom->dvector[index_wsame]; - - index_ft = atom->find_custom("f_rheo_tension", tmp1, tmp2); - if (index_ft == -1) index_ft = atom->add_custom("f_rheo_tension", 1, 3); - ft = atom->darray[index_ft]; - - norm = nullptr; - nmax_store = 0; -} - -/* ---------------------------------------------------------------------- */ - -FixRHEOTension::~FixRHEOTension() -{ - // Remove custom property if it exists - int tmp1, tmp2, index; - - index = atom->find_custom("c_rheo_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - - index = atom->find_custom("cgrad_rheo_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 3); - - index = atom->find_custom("n_rheo_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 3); - - index = atom->find_custom("divn_rheo_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - - index = atom->find_custom("wsame_rheo_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - - index = atom->find_custom("f_rheo_tension", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 3); - - memory->destroy(norm); -} - -/* ---------------------------------------------------------------------- */ - -int FixRHEOTension::setmask() -{ - int mask = 0; - mask |= PRE_FORCE; - return mask; -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOTension::init() -{ - auto fixes = modify->get_fix_by_style("^rheo$"); - if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/tension"); - fix_rheo = dynamic_cast(fixes[0]); - - compute_kernel = fix_rheo->compute_kernel; - compute_interface = fix_rheo->compute_interface; - compute_vshift = fix_rheo->compute_vshift; - interface_flag = fix_rheo->interface_flag; - shift_flag = fix_rheo->shift_flag; - h = fix_rheo->h; - rho0 = fix_rheo->rho0; - - hsq = h * h; - - neighbor->add_request(this, NeighConst::REQ_DEFAULT); -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOTension::init_list(int /*id*/, NeighList *ptr) -{ - list = ptr; -} - - -/* ---------------------------------------------------------------------- */ - -void FixRHEOTension::setup(int vflag) -{ - // Grow and populate arrays for dump files - if (nmax_store <= atom->nmax) - grow_arrays(atom->nmax); - - size_t nbytes = nmax_store * sizeof(double); - memset(&ct[0], 0, nbytes); - memset(&norm[0], 0, nbytes); - memset(&wsame[0], 0, nbytes); - memset(&divnt[0], 0, nbytes); - memset(&cgradt[0][0], 0, 3 * nbytes); - memset(&ft[0][0], 0, 3 * nbytes); - memset(&nt[0][0], 0, 3 * nbytes); -} - -/* ---------------------------------------------------------------------- - Calculate and apply tension forces -------------------------------------------------------------------------- */ - -void FixRHEOTension::pre_force(int vflag) -{ - int i, j, a, ii, jj, inum, jnum, itype, jtype; - int fluidi, fluidj; - double xtmp, ytmp, ztmp, w, wp, ctmp; - double rhoi, rhoj, Voli, Volj; - double *dWij, *dWji; - double dx[3]; - - int *ilist, *jlist, *numneigh, **firstneigh; - double imass, jmass, rsq, r, rinv; - - int nlocal = atom->nlocal; - int newton = force->newton; - int dim = domain->dimension; - - v_init(vflag); - - double **x = atom->x; - double **f = atom->f; - double *rho = atom->rho; - double *mass = atom->mass; - imageint *image = atom->image; - int *type = atom->type; - int *status = atom->status; - - inum = list->inum; - ilist = list->ilist; - numneigh = list->numneigh; - firstneigh = list->firstneigh; - - if (nmax_store <= atom->nmax) - grow_arrays(atom->nmax); - - size_t nbytes = nmax_store * sizeof(double); - memset(&ct[0], 0, nbytes); - memset(&norm[0], 0, nbytes); - memset(&wsame[0], 0, nbytes); - memset(&divnt[0], 0, nbytes); - memset(&cgradt[0][0], 0, 3 * nbytes); - memset(&ft[0][0], 0, 3 * nbytes); - - // Calculate color gradient - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - fluidi = !(status[i] & PHASECHECK); - jlist = firstneigh[i]; - jnum = numneigh[i]; - imass = mass[itype]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - dx[0] = xtmp - x[j][0]; - dx[1] = ytmp - x[j][1]; - dx[2] = ztmp - x[j][2]; - - rsq = lensq3(dx); - - if (rsq > hsq) continue; - - fluidj = !(status[j] & PHASECHECK); - jtype = type[j]; - r = sqrt(rsq); - - rhoi = rho[i]; - rhoj = rho[j]; - - // Add corrections for walls - if (interface_flag) { - if (fluidi && (!fluidj)) { - rhoj = compute_interface->correct_rho(j, i); - } else if ((!fluidi) && fluidj) { - rhoi = compute_interface->correct_rho(i, j); - } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0[itype]; - rhoj = rho0[jtype]; - } - } - - Voli = mass[itype] / rhoi; - Volj = mass[jtype] / rhoj; - - w = compute_kernel->calc_w(i, j, dx[0], dx[1], dx[2], r); - - if (itype != jtype) ctmp = 1; - else ctmp = 0; - - ct[i] += ctmp * Volj * w; - if (newton || j < nlocal) - ct[j] += ctmp * Voli * w; - } - } - - comm_stage = 0; - comm_reverse = 1; - if (newton) comm->reverse_comm(this); - - // Calculate color gradient - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - fluidi = !(status[i] & PHASECHECK); - jlist = firstneigh[i]; - jnum = numneigh[i]; - imass = mass[itype]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - dx[0] = xtmp - x[j][0]; - dx[1] = ytmp - x[j][1]; - dx[2] = ztmp - x[j][2]; - rsq = lensq3(dx); - - if (rsq > hsq) continue; - - fluidj = !(status[j] & PHASECHECK); - jtype = type[j]; - r = sqrt(rsq); - - rhoi = rho[i]; - rhoj = rho[j]; - - // Add corrections for walls - if (interface_flag) { - if (fluidi && (!fluidj)) { - rhoj = compute_interface->correct_rho(j, i); - } else if ((!fluidi) && fluidj) { - rhoi = compute_interface->correct_rho(i, j); - } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0[itype]; - rhoj = rho0[jtype]; - } - } - - Voli = mass[itype] / rhoi; - Volj = mass[jtype] / rhoj; - - wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2], r); - dWij = compute_kernel->dWij; - dWji = compute_kernel->dWji; - - //c = 0; - //if (itype != jtype) c += rhoi; - //c /= (rhoi + rhoj); - - if (itype != jtype) ctmp = 1; - else ctmp = 0; - - for (a = 0; a < dim; a++) { - cgradt[i][a] -= ctmp * Volj * dWij[a]; - if (newton || j < nlocal) - cgradt[j][a] -= ctmp * Voli * dWji[a]; - } - } - } - - comm_stage = 1; - comm_reverse = 3; - if (newton) comm->reverse_comm(this); - - // Calculate normal direction - double minv; - for (i = 0; i < nlocal; i++) { - minv = cgradt[i][0] * cgradt[i][0] + cgradt[i][1] * cgradt[i][1]; - if (dim == 3) minv += cgradt[i][2] * cgradt[i][2]; - minv = sqrt(minv); - if (minv != 0) minv = 1 / minv; - - for (a = 0; a < dim; a++) - nt[i][a] = cgradt[i][a] * minv; - } - - comm_forward = 3; - comm->forward_comm(this); - - // Calculate divergence - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - fluidi = !(status[i] & PHASECHECK); - jlist = firstneigh[i]; - jnum = numneigh[i]; - imass = mass[itype]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - dx[0] = xtmp - x[j][0]; - dx[1] = ytmp - x[j][1]; - dx[2] = ztmp - x[j][2]; - rsq = lensq3(dx); - - if (rsq > hsq) continue; - - fluidj = !(status[j] & PHASECHECK); - jtype = type[j]; - r = sqrt(rsq); - rinv = 1 / r; - - rhoi = rho[i]; - rhoj = rho[j]; - - // Add corrections for walls - if (interface_flag) { - if (fluidi && (!fluidj)) { - rhoj = compute_interface->correct_rho(j, i); - } else if ((!fluidi) && fluidj) { - rhoi = compute_interface->correct_rho(i, j); - } else if ((!fluidi) && (!fluidj)) { - rhoi = rho0[itype]; - rhoj = rho0[jtype]; - } - } - - Voli = mass[itype] / rhoi; - Volj = mass[jtype] / rhoj; - - w = compute_kernel->calc_w(i, j, dx[0], dx[1], dx[2], r); - wp = compute_kernel->calc_dw(i, j, dx[0], dx[1], dx[2], r); - dWij = compute_kernel->dWij; - dWji = compute_kernel->dWji; - - for (a = 0; a < dim; a++) { - if (itype != jtype) { - divnt[i] -= (nt[i][a] + nt[j][a]) * Volj * dWij[a]; - } else { - divnt[i] -= (nt[i][a] - nt[j][a]) * Volj * dWij[a]; - wsame[i] += w * r; - } - norm[i] -= dx[a] * Volj * dWij[a]; - if (newton || j < nlocal) { - if (itype != jtype) { - divnt[j] -= (nt[j][a] + nt[i][a]) * Voli * dWji[a]; - } else { - divnt[j] -= (nt[j][a] - nt[i][a]) * Voli * dWji[a]; - wsame[j] += w * r; - } - norm[j] += dx[a] * Voli * dWji[a]; - } - } - } - } - - comm_stage = 2; - comm_reverse = 3; - if (newton) comm->reverse_comm(this); - - comm_forward = 1; - comm->forward_comm(this); - - // Skip forces if it's setup - if (update->setupflag) return; - - // apply force, remove normal vshift - - double **vshift; - if (shift_flag) - vshift = compute_vshift->vshift; - double nx, ny, nz, vx, vy, vz, dot; - double wmin_inv, weight, prefactor, unwrap[3], v[6]; - - if (wmin > 0) wmin_inv = 1.0 / wmin; - else wmin_inv = 0.0; - - for (i = 0; i < nlocal; i++) { - - if (wsame[i] < wmin) continue; - - weight = MIN(1.0, wsame[i] * wmin_inv); //MAX -> MIN 2/14/24 - itype = type[i]; - - if (norm[i] != 0) - divnt[i] *= dim * norm[i]; - else - divnt[i] = 0.0; - - // Tension force from Adami, Hu, Adams 2010 - prefactor = -alpha * divnt[i] * weight; - for (a = 0; a < dim; a++) { - f[i][a] += prefactor * cgradt[i][a]; - ft[i][a] += prefactor * cgradt[i][a]; - } - - // remove normal shifting component for interfacial particles - // Based on Yang, Rakhsha, Hu, & Negrut 2022 - if (shift_flag && (vshift_strength != 1.0)) { - if (ct[i] > cmin) { - nx = nt[i][0]; - ny = nt[i][1]; - vx = vshift[i][0]; - vy = vshift[i][1]; - - dot = nx * vx + ny * vy; - if (dim == 3) { - nz = nt[i][2]; - vz = vshift[i][2]; - dot += nz * vz; - } - - // Allowing shifting into the bulk - //if (dot > 0.0) continue; - - vshift[i][0] -= (1.0 - vshift_strength) * nx * dot; - vshift[i][1] -= (1.0 - vshift_strength) * ny * dot; - if (dim == 3) { - vshift[i][2] -= (1.0 - vshift_strength) * nz * dot; - } - } - } - - if (evflag) { - domain->unmap(x[i], image[i], unwrap); - v[0] = prefactor * cgradt[i][0] * unwrap[0]; - v[1] = prefactor * cgradt[i][1] * unwrap[1]; - v[2] = prefactor * cgradt[i][2] * unwrap[2]; - v[3] = prefactor * cgradt[i][0] * unwrap[1]; - v[4] = prefactor * cgradt[i][0] * unwrap[2]; - v[5] = prefactor * cgradt[i][1] * unwrap[2]; - v_tally(i, v); - } - } - - // If there is no lower limit, apply optional pairwise forces - // This is totally ad hoc, needs some work - // Attempts to deal with stray single particles - if (wmin <= 0 || beta == 0.0) return; - - int newton_pair = force->newton_pair; - double fpair, wi, wj; - double cut_two_thirds = 2.0 * h / 3.0; - double cut_five_sixths = 5.0 * h / 6.0; - double cut_sixth_sq = (h / 6.0) * (h / 6.0); - double cut_third_sq = (h / 3.0) * (h / 3.0); - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - itype = type[i]; - jlist = firstneigh[i]; - jnum = numneigh[i]; - - wi = MAX(MIN(1.0, (wmin - wsame[i]) * wmin_inv), 0.0); - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; - - if (wsame[i] >= wmin && wsame[j] >= wmin) continue; - - dx[0] = xtmp - x[j][0]; - dx[1] = ytmp - x[j][1]; - dx[2] = ztmp - x[j][2]; - rsq = lensq3(dx); - - if (rsq > hsq) continue; - - r = sqrt(rsq); - jtype = type[j]; - - if (itype == jtype) { - fpair = (r - cut_two_thirds); - fpair *= fpair; - fpair -= cut_third_sq; - } else { - //fpair = 0.0; - - if (r > (0.5*cut_two_thirds)) continue; - fpair = (r - cut_two_thirds); - fpair *= fpair; - fpair -= cut_third_sq; - - //if (r > cut_two_thirds) continue; - //fpair = (r - cut_five_sixths); - //fpair *= fpair; - //fpair -= cut_sixth_sq; - - //fpair = (h - r) * 0.66666666666666; - } - - wj = MAX(MIN(1.0, (wmin - wsame[j]) * wmin_inv), 0.0); - rinv = 1.0 / r; - fpair *= MAX(wi, wj) * beta * rinv; - - f[i][0] += dx[0] * fpair; - f[i][1] += dx[1] * fpair; - f[i][2] += dx[2] * fpair; - - if (newton_pair || j < nlocal) { - f[j][0] -= dx[0] * fpair; - f[j][1] -= dx[1] * fpair; - f[j][2] -= dx[2] * fpair; - } - - if (evflag) { - // In progress - } - } - } -} - - -/* ---------------------------------------------------------------------- */ - -int FixRHEOTension::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) -{ - int i, j, a, m; - m = 0; - - if (comm_stage == 1) - for (i = 0; i < n; i++) { - j = list[i]; - for (a = 0; a < 3; a++) - buf[m++] = nt[j][a]; - } - else if (comm_stage == 2) - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = wsame[j]; - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOTension::unpack_forward_comm(int n, int first, double *buf) -{ - int i, a, m, last; - - m = 0; - last = first + n; - if (comm_stage == 1) - for (i = first; i < last; i++) - for (a = 0; a < 3; a++) - nt[i][a] = buf[m++]; - else if (comm_stage == 2) - for (i = first; i < last; i++) - wsame[i] = buf[m++]; -} - - -/* ---------------------------------------------------------------------- */ - -int FixRHEOTension::pack_reverse_comm(int n, int first, double *buf) -{ - int i, a, m, last; - - m = 0; - last = first + n; - if (comm_stage == 0) - for (i = first; i < last; i++) - buf[m++] = ct[i]; - else if (comm_stage == 1) - for (i = first; i < last; i++) - for (a = 0; a < 3; a++) - buf[m++] = cgradt[i][a]; - else if (comm_stage == 2) - for (i = first; i < last; i++) { - buf[m++] = norm[i]; - buf[m++] = divnt[i]; - buf[m++] = wsame[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOTension::unpack_reverse_comm(int n, int *list, double *buf) -{ - int i, j, a, m; - - m = 0; - if (comm_stage == 0) - for (i = 0; i < n; i++) { - j = list[i]; - ct[j] += buf[m++]; - } - else if (comm_stage == 1) - for (i = 0; i < n; i++) { - j = list[i]; - for (a = 0; a < 3; a++) - cgradt[j][a] += buf[m++]; - } - else if (comm_stage == 2) - for (i = 0; i < n; i++) { - j = list[i]; - norm[j] += buf[m++]; - divnt[j] += buf[m++]; - wsame[j] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void FixRHEOTension::grow_arrays(int nmax) -{ - // Grow atom variables and reassign pointers - memory->grow(atom->dvector[index_ct], nmax, "atom:rheo_ct"); - memory->grow(atom->darray[index_cgradt], nmax, 3, "atom:rheo_cgradt"); - memory->grow(atom->darray[index_nt], nmax, 3, "atom:rheo_nt"); - memory->grow(atom->dvector[index_divnt], nmax, "atom:rheo_divnt"); - memory->grow(atom->dvector[index_wsame], nmax, "atom:rheo_wsame"); - memory->grow(atom->darray[index_ft], nmax, 3, "atom:rheo_ft"); - - ct = atom->dvector[index_ct]; - cgradt = atom->darray[index_cgradt]; - nt = atom->darray[index_nt]; - divnt = atom->dvector[index_divnt]; - wsame = atom->dvector[index_wsame]; - ft = atom->darray[index_ft]; - - // Grow local variables - memory->grow(norm, nmax, "rheo/tension:norm"); - - nmax_store = atom->nmax; -} \ No newline at end of file diff --git a/src/RHEO/fix_rheo_tension.h b/src/RHEO/fix_rheo_tension.h deleted file mode 100644 index 52d368531f..0000000000 --- a/src/RHEO/fix_rheo_tension.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- c++ -*- ---------------------------------------------------------- - 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. -------------------------------------------------------------------------- */ - -#ifdef FIX_CLASS -// clang-format off -FixStyle(rheo/tension,FixRHEOTension) -// clang-format on -#else - -#ifndef LMP_FIX_RHEO_TENSION_H -#define LMP_FIX_RHEO_TENSION_H - -#include "fix.h" - -namespace LAMMPS_NS { - -class FixRHEOTension : public Fix { - public: - FixRHEOTension(class LAMMPS *, int, char **); - ~FixRHEOTension() override; - int setmask() override; - void init() override; - void init_list(int, class NeighList *) override; - void setup(int) override; - void pre_force(int) override; - int pack_forward_comm(int, int *, double *, int, int *) override; - void unpack_forward_comm(int, int, double *) override; - int pack_reverse_comm(int, int, double *) override; - void unpack_reverse_comm(int, int *, double *) override; - void grow_arrays(int) override; - - private: - int nmax_store, comm_stage, interface_flag, shift_flag; - int index_ct, index_nt, index_cgradt, index_divnt, index_ft, index_wsame; - - double *ct, **nt, **cgradt, *divnt, *norm, **ft, *wsame; - double alpha, beta, wmin, cmin, vshift_strength, h, hsq, hinv, hinv3, *rho0; - - class ComputeRHEOKernel *compute_kernel; - class ComputeRHEOInterface *compute_interface; - class ComputeRHEOVShift *compute_vshift; - class FixRHEO *fix_rheo; - class NeighList *list; -}; - -} // namespace LAMMPS_NS - -#endif -#endif From 4886678619aa9daf9d31346422821a6a69e8072f Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 29 Apr 2024 16:14:53 -0600 Subject: [PATCH 082/385] Updating masks, cleaning up special bond handling --- src/BPM/fix_update_special_bonds.cpp | 33 ++++++++++++++-------- src/RHEO/fix_rheo.h | 10 +++---- src/RHEO/fix_rheo_thermal.cpp | 42 ++++++++++++++++++++++------ 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/BPM/fix_update_special_bonds.cpp b/src/BPM/fix_update_special_bonds.cpp index b6bf8b433f..b21de90b52 100644 --- a/src/BPM/fix_update_special_bonds.cpp +++ b/src/BPM/fix_update_special_bonds.cpp @@ -93,16 +93,19 @@ void FixUpdateSpecialBonds::pre_exchange() for (auto const &it : broken_pairs) { tagi = it.first; tagj = it.second; + i = atom->map(tagi); j = atom->map(tagj); // remove i from special bond list for atom j and vice versa // ignore n2, n3 since 1-3, 1-4 special factors required to be 1.0 + // assume ghosts don't need special information if (i < nlocal) { slist = special[i]; n1 = nspecial[i][0]; for (m = 0; m < n1; m++) if (slist[m] == tagj) break; + if (m == n1) error->one(FLERR, "Special bond {} {} not found", tagi, tagj); for (; m < n1 - 1; m++) slist[m] = slist[m + 1]; nspecial[i][0]--; nspecial[i][1] = nspecial[i][2] = nspecial[i][0]; @@ -113,6 +116,7 @@ void FixUpdateSpecialBonds::pre_exchange() n1 = nspecial[j][0]; for (m = 0; m < n1; m++) if (slist[m] == tagi) break; + if (m == n1) error->one(FLERR, "Special bond {} {} not found", tagi, tagj); for (; m < n1 - 1; m++) slist[m] = slist[m + 1]; nspecial[j][0]--; nspecial[j][1] = nspecial[j][2] = nspecial[j][0]; @@ -127,19 +131,24 @@ void FixUpdateSpecialBonds::pre_exchange() // add i to special bond list for atom j and vice versa // ignore n2, n3 since 1-3, 1-4 special factors required to be 1.0 - n1 = nspecial[i][0]; - if (n1 >= atom->maxspecial) - error->one(FLERR, "Special list size exceeded in fix update/special/bond"); - special[i][n1] = tagj; - nspecial[i][0] += 1; - nspecial[i][1] = nspecial[i][2] = nspecial[i][0]; + // assume ghosts don't need special information + if (i < nlocal) { + n1 = nspecial[i][0]; + if (n1 >= atom->maxspecial) + error->one(FLERR, "Special list size exceeded for atom {}", tagi); + special[i][n1] = tagj; + nspecial[i][0] += 1; + nspecial[i][1] = nspecial[i][2] = nspecial[i][0]; + } - n1 = nspecial[j][0]; - if (n1 >= atom->maxspecial) - error->one(FLERR, "Special list size exceeded in fix update/special/bond"); - special[j][n1] = tagi; - nspecial[j][0] += 1; - nspecial[j][1] = nspecial[j][2] = nspecial[j][0]; + if (j < nlocal) { + n1 = nspecial[j][0]; + if (n1 >= atom->maxspecial) + error->one(FLERR, "Special list size exceeded for atom {}", tagj); + special[j][n1] = tagi; + nspecial[j][0] += 1; + nspecial[j][1] = nspecial[j][2] = nspecial[j][0]; + } } broken_pairs.clear(); diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 45f74ed4cd..51e0962000 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -94,11 +94,11 @@ namespace RHEO_NS { }; // Masks and their inverses - #define PHASEMASK 0xFFFFFFFC - #define PHASECHECK 0x00000003 - #define SURFACEMASK 0xFFFFFFC3 - #define SURFACECHECK 0x0000003C - #define OPTIONSMASK 0xFFFFFE3F + #define PHASEMASK 0xFFFFFFFC // 11111111111111111111111111111100 + #define PHASECHECK 0x00000003 // 00000000000000000000000000000011 + #define SURFACEMASK 0xFFFFFFC3 // 11111111111111111111111111000011 + #define SURFACECHECK 0x0000003C // 00000000000000000000000000111100 + #define OPTIONSMASK 0xFFFFFC3F // 11111111111111111111110000111111 } // namespace RHEO_NS } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 3a39bbe596..f2dbd6c8bb 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -281,6 +281,10 @@ void FixRHEOThermal::init() fix_update_special_bonds = dynamic_cast(fixes[0]); } + // must have newton off so both processors will search nlist to build bonds + if (force->newton_pair) + error->all(FLERR, "Need Newton off for reactive bond generation"); + // need a half neighbor list, built only when particles freeze auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL); req->set_cutoff(cut_kernel); @@ -494,7 +498,7 @@ void FixRHEOThermal::reset_dt() void FixRHEOThermal::break_bonds() { - int m, n, nmax, i, j; + int m, n, nmax, i, j, melti, meltj; tagint *tag = atom->tag; int *status = atom->status; @@ -510,11 +514,13 @@ void FixRHEOThermal::break_bonds() // Delete all bonds for local atoms that melt of a given type for (int i = 0; i < nlocal; i++) { - if (!(status[i] & STATUS_MELTING)) continue; + melti = status[i] & STATUS_MELTING; + if (!melti) continue; for (m = (num_bond[i] - 1); m >= 0; m--) { if (bond_type[i][m] != btype) continue; j = atom->map(bond_atom[i][m]); + meltj = status[j] & STATUS_MELTING; nmax = num_bond[i] - 1; if (m == nmax) { @@ -535,8 +541,17 @@ void FixRHEOThermal::break_bonds() bond_type[i][nmax] = 0; num_bond[i]--; - if (fix_update_special_bonds) - fix_update_special_bonds->add_broken_bond(i, j); + // Update special unless two owned atoms melt simultaneously then + // only update for atom with lower tag + if (fix_update_special_bonds) { + if (i < nlocal && j < nlocal && melti && meltj) { + if (tag[i] < tag[j]) { + fix_update_special_bonds->add_broken_bond(i, j); + } + } else { + fix_update_special_bonds->add_broken_bond(i, j); + } + } } } @@ -548,12 +563,15 @@ void FixRHEOThermal::break_bonds() i = bondlist[n][0]; j = bondlist[n][1]; - if (!(status[i] & STATUS_MELTING) && !(status[j] & STATUS_MELTING)) continue; + melti = status[i] & STATUS_MELTING; + meltj = status[j] & STATUS_MELTING; + + if (!melti && !meltj) continue; bondlist[n][2] = 0; // Delete bonds for non-melted local atoms (shifting) - if (i < nlocal && !(status[i] & STATUS_MELTING)) { + if (i < nlocal && !melti) { for (m = 0; m < num_bond[i]; m++) { if (bond_atom[i][m] == tag[j] && bond_type[i][m] == btype) { nmax = num_bond[i] - 1; @@ -572,7 +590,7 @@ void FixRHEOThermal::break_bonds() } } - if (j < nlocal && !(status[j] & STATUS_MELTING)) { + if (j < nlocal && !meltj) { for (m = 0; m < num_bond[j]; m++) { if (bond_atom[j][m] == tag[i] && bond_type[j][m] == btype) { nmax = num_bond[j] - 1; @@ -590,6 +608,12 @@ void FixRHEOThermal::break_bonds() } } } + + // Unless both atoms melt simultaneously, need to remove special bond if the melted atom is a ghost + if (melti && meltj) continue; + if (fix_update_special_bonds) + if (((i >= nlocal) && melti) || ((j >= nlocal) && meltj)) + fix_update_special_bonds->add_broken_bond(i, j); } } @@ -649,7 +673,6 @@ void FixRHEOThermal::create_bonds() if (i < nlocal && (!newton_bond || tag[i] < tag[j])) { if (num_bond[i] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); - if (fix_update_special_bonds) fix_update_special_bonds->add_created_bond(i, j); bond_type[i][num_bond[i]] = btype; bond_atom[i][num_bond[i]] = tag[j]; num_bond[i]++; @@ -658,11 +681,12 @@ void FixRHEOThermal::create_bonds() if (j < nlocal && (!newton_bond || tag[j] < tag[i])) { if (num_bond[j] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); - if (fix_update_special_bonds) fix_update_special_bonds->add_created_bond(i, j); bond_type[j][num_bond[j]] = btype; bond_atom[j][num_bond[j]] = tag[i]; num_bond[j]++; } + + if (fix_update_special_bonds) fix_update_special_bonds->add_created_bond(i, j); } } } From da7459c80562724e900e82024c9c82db90df89bd Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 3 May 2024 15:13:45 -0600 Subject: [PATCH 083/385] Adding heat options, prevent asynchronous mpi bond creation/deletion --- doc/src/fix_add_heat.rst | 44 +++++++++++---- src/GRANULAR/fix_add_heat.cpp | 95 ++++++++++++++++++++------------- src/GRANULAR/fix_add_heat.h | 6 +-- src/RHEO/fix_rheo_oxidation.cpp | 61 ++++++++++++++++++--- src/RHEO/fix_rheo_oxidation.h | 2 + src/RHEO/fix_rheo_thermal.cpp | 34 ++++++++---- 6 files changed, 174 insertions(+), 68 deletions(-) diff --git a/doc/src/fix_add_heat.rst b/doc/src/fix_add_heat.rst index 3964c96b27..2a2d855927 100644 --- a/doc/src/fix_add_heat.rst +++ b/doc/src/fix_add_heat.rst @@ -8,31 +8,53 @@ Syntax .. code-block:: LAMMPS - fix ID group-ID add/heat rate values ... + fix ID group-ID add/heat style args keyword values ... * ID, group-ID are documented in :doc:`fix ` command * add/heat = style name of this fix command -* rate = rate of heat flow (energy/time units) +* style = *constant* or *linear* or *quartic* + + .. parsed-literal:: + + *constant* args = rate + rate = rate of heat flow (energy/time units) + *linear* args = t_target k + t_target = target temperature (temperature units) + k = prefactor (energy/(time*temperature) units) + *quartic* args = t_target k + t_target = target temperature (temperature units) + k = prefactor (energy/(time*temperature^4) units) + * zero or more keyword/value pairs may be appended to args * keyword = *overwrite* .. parsed-literal:: - *overwrite* = sets the heat flow instead of adding it + *overwrite* value = *yes* or *no* + *yes* = sets current heat flow of particle + *no* = adds to current heat flow of particle Examples """""""" .. code-block:: LAMMPS - fix 1 all add/heat v_heat - fix 1 all add/heat 1.0 overwrite + fix 1 all add/heat constant v_heat + fix 1 all add/heat linear 10.0 1.0 overwrite yes Description """"""""""" -This fix adds heat to particles every timestep at a given rate. The rate -can be can be specified as an equal-style or atom-style +This fix adds heat to particles every timestep. + +For the *constant* style, heat is added at the specified rate. For the *linear* style, +heat is added at a rate of :math:`k (T_{target} - T)` where :math:`k` is the +specified prefactor, :math:`T_{target}` is the specified target temperature, and +:math:`T` is the temperature of the atom. This may be more representative of a +conductive process. For the *quartic* style, heat is added at a rate of +:math:`k (T_{target}^4 - T^4)`, akin to radiative heat transfer. + +The rate or temperature can be can be specified as an equal-style or atom-style :doc:`variable `. If the value is a variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each time step, and its value will be used to @@ -48,9 +70,9 @@ variables but can also include per-atom values, such as atom coordinates. Thus, it is easy to specify a spatially-dependent heating field with optional time-dependence as well. -If the *overwrite* keyword is specified, this fix will effectively set -the total heat flow on a particle, overwriting contributions from other -pair styles. +If the *overwrite* keyword is set to *yes*, this fix will effectively set +the total heat flow on a particle, overwriting contributions from pair +styles or other fixes. ---------- @@ -84,4 +106,4 @@ Related commands Default """"""" -none +The default for the *overwrite* keyword is *no* diff --git a/src/GRANULAR/fix_add_heat.cpp b/src/GRANULAR/fix_add_heat.cpp index 2db3389560..7109ffb01c 100644 --- a/src/GRANULAR/fix_add_heat.cpp +++ b/src/GRANULAR/fix_add_heat.cpp @@ -27,34 +27,52 @@ using namespace LAMMPS_NS; using namespace FixConst; -enum { NONE, CONSTANT, EQUAL, ATOM }; +enum { CONSTANT, EQUAL, ATOM }; +enum { ADD, LINEAR, QUARTIC }; /* ---------------------------------------------------------------------- */ FixAddHeat::FixAddHeat(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), varstr(nullptr), qatom(nullptr) + Fix(lmp, narg, arg), varstr(nullptr), vatom(nullptr) { - if (narg < 4) utils::missing_cmd_args(FLERR, "fix add/heat", error); + if (narg < 5) utils::missing_cmd_args(FLERR, "fix add/heat", error); dynamic_group_allow = 1; overwrite_flag = 0; - style = NONE; - if (utils::strmatch(arg[3], "^v_")) { - varstr = utils::strdup(arg[3] + 2); + if (strcmp(arg[3], "constant") == 0) { + style = ADD; + } else if (strcmp(arg[3], "linear") == 0) { + style = LINEAR; + } else if (strcmp(arg[3], "quartic") == 0) { + style = QUARTIC; } else { - value = utils::numeric(FLERR, arg[3], false, lmp); - style = CONSTANT; + error->all(FLERR, "Invalid option {}", arg[3]); + } + + if (utils::strmatch(arg[4], "^v_")) { + varstr = utils::strdup(arg[4] + 2); + } else { + value = utils::numeric(FLERR, arg[4], false, lmp); + vstyle = CONSTANT; + } + + int iarg = 5; + if (style != ADD) { + if (narg != 6) utils::missing_cmd_args(FLERR, "fix add/heat", error); + prefactor = utils::numeric(FLERR, arg[5], false, lmp); + iarg = 6; } // optional args - int iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg], "overwrite") == 0) { - overwrite_flag = 1; - iarg += 1; - } else - error->all(FLERR, "Illegal fix viscous command"); + if (iarg + 1 >= narg) utils::missing_cmd_args(FLERR, "fix add/heat", error); + overwrite_flag = utils::bnumeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else { + error->all(FLERR, "Illegal fix add/heat command, invalid argument {}", arg[iarg]); + } } maxatom = -1; @@ -65,7 +83,7 @@ FixAddHeat::FixAddHeat(LAMMPS *lmp, int narg, char **arg) : FixAddHeat::~FixAddHeat() { delete[] varstr; - memory->destroy(qatom); + memory->destroy(vatom); } /* ---------------------------------------------------------------------- */ @@ -92,9 +110,9 @@ void FixAddHeat::init() var = input->variable->find(varstr); if (var < 0) error->all(FLERR, "Variable {} for fix addforce does not exist", varstr); if (input->variable->equalstyle(var)) - style = EQUAL; + vstyle = EQUAL; else if (input->variable->atomstyle(var)) - style = ATOM; + vstyle = ATOM; else error->all(FLERR, "Variable {} for fix addforce is invalid style", varstr); } @@ -106,33 +124,38 @@ void FixAddHeat::post_force(int /*vflag*/) { int *mask = atom->mask; double *heatflow = atom->heatflow; + double *temperature = atom->temperature; double dtinv = 1.0 / update->dt; - if (overwrite_flag) { + if (vstyle == ATOM) { + if (atom->nmax > maxatom) { + maxatom = atom->nmax; + memory->destroy(vatom); + memory->create(vatom, maxatom, "addheat:vatom"); + } + + input->variable->compute_atom(var, igroup, &vatom[0], 1, 0); + } + + if (overwrite_flag) for (int i = 0; i < atom->nlocal; i++) if (mask[i] & groupbit) heatflow[i] = 0.0; - } - if (style == CONSTANT) { - for (int i = 0; i < atom->nlocal; i++) - if (mask[i] & groupbit) - heatflow[i] += value * dtinv; - } else if (style == EQUAL) { - value = input->variable->compute_equal(var); - for (int i = 0; i < atom->nlocal; i++) - if (mask[i] & groupbit) - heatflow[i] += value * dtinv; - } else if (style == ATOM) { + double vtmp, dt; + if (vstyle == CONSTANT) vtmp = value; + if (vstyle == EQUAL) vtmp = input->variable->compute_equal(var); + for (int i = 0; i < atom->nlocal; i++) { + if (mask[i] & groupbit) { + if (vstyle == ATOM) vtmp = vatom[i]; - if (atom->nmax > maxatom) { - maxatom = atom->nmax; - memory->destroy(qatom); - memory->create(qatom, maxatom, "addheat:qatom"); + if (style == ADD) { + heatflow[i] += dtinv * vtmp; + } else if (style == LINEAR) { + heatflow[i] += dtinv * prefactor * (vtmp - temperature[i]); + } else if (style == QUARTIC) { + heatflow[i] += dtinv * prefactor * (pow(vtmp, 4.0) - pow(temperature[i], 4.0)); + } } - input->variable->compute_atom(var, igroup, &qatom[0], 1, 0); - for (int i = 0; i < atom->nlocal; i++) - if (mask[i] & groupbit) - heatflow[i] += qatom[i] * dtinv; } } diff --git a/src/GRANULAR/fix_add_heat.h b/src/GRANULAR/fix_add_heat.h index 8a51f13ee4..4fa8adf42e 100644 --- a/src/GRANULAR/fix_add_heat.h +++ b/src/GRANULAR/fix_add_heat.h @@ -33,10 +33,10 @@ class FixAddHeat : public Fix { void post_force(int) override; protected: - double value; - int var, style, maxatom, overwrite_flag; + double value, prefactor; + int var, vstyle, maxatom, style, overwrite_flag; char *varstr; - double *qatom; + double *vatom; }; } // namespace LAMMPS_NS diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index 46eaab3bf1..8539f04277 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -21,6 +21,7 @@ #include "atom.h" #include "atom_vec.h" #include "citeme.h" +#include "comm.h" #include "compute_rheo_surface.h" #include "error.h" #include "fix_rheo.h" @@ -54,6 +55,8 @@ FixRHEOOxidation::FixRHEOOxidation(LAMMPS *lmp, int narg, char **arg) : { if (narg != 6) error->all(FLERR,"Illegal fix command"); + comm_forward = 3; + cut = utils::numeric(FLERR, arg[3], false, lmp); if (cut <= 0.0) error->all(FLERR, "Illegal bond cutoff {} in fix rheo/oxidation", cut); @@ -146,7 +149,7 @@ void FixRHEOOxidation::post_integrate() { int i, j, n, ii, jj, inum, jnum, bflag; int *ilist, *jlist, *numneigh, **firstneigh; - double xtmp, ytmp, ztmp, delx, dely, delz, rsq; + double delx, dely, delz, rsq; tagint tagi, tagj; int nlocal = atom->nlocal; @@ -164,15 +167,16 @@ void FixRHEOOxidation::post_integrate() numneigh = list->numneigh; firstneigh = list->firstneigh; + // Forward positions (after inititial integrate, before comm) + // Note: surface designation lags one timestep, acceptable error + comm->forward_comm(this); + // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (rsurface[i] > rsurf) continue; tagi = tag[i]; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; @@ -184,9 +188,19 @@ void FixRHEOOxidation::post_integrate() if (rsurface[j] > rsurf) continue; tagj = tag[j]; - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; + + // Ensure pair is always ordered to ensure numerical operations + // are identical to minimize the possibility that a bond straddling + // an mpi grid (newton off) isn't created on one proc but not the other + if (tagi < tagj) { + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + } else { + delx = x[j][0] - x[i][0]; + dely = x[j][1] - x[i][1]; + delz = x[j][2] - x[i][2]; + } rsq = delx * delx + dely * dely + delz * delz; if (rsq > cutsq) continue; @@ -213,3 +227,36 @@ void FixRHEOOxidation::post_integrate() } } } + +/* ---------------------------------------------------------------------- */ + +int FixRHEOOxidation::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + int i, j, k, m; + double **x = atom->x; + m = 0; + + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOOxidation::unpack_forward_comm(int n, int first, double *buf) +{ + int i, k, m, last; + double **x = atom->x; + m = 0; + last = first + n; + for (i = first; i < last; i++) { + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; + } +} diff --git a/src/RHEO/fix_rheo_oxidation.h b/src/RHEO/fix_rheo_oxidation.h index be95efbf2c..5991a830c0 100644 --- a/src/RHEO/fix_rheo_oxidation.h +++ b/src/RHEO/fix_rheo_oxidation.h @@ -36,6 +36,8 @@ class FixRHEOOxidation : public Fix { void setup_pre_force(int) override; void pre_force(int) override; void post_integrate() override; + int pack_forward_comm(int, int *, double *, int, int *) override; + void unpack_forward_comm(int, int, double *) override; int *nbond; double rsurf, cut; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index f2dbd6c8bb..5d4134a461 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -186,7 +186,7 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : if (iarg + 2 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/thermal react", error); cut_bond = utils::numeric(FLERR, arg[iarg + 1], false, lmp); btype = utils::numeric(FLERR, arg[iarg + 2], false, lmp); - comm_forward = 1; + comm_forward = 4; if (cut_bond <= 0.0) error->all(FLERR, "Illegal max bond length must be greater than zero");\ if (btype < 1 || btype > atom->nbondtypes) error->all(FLERR, "Illegal value for bond type"); @@ -400,7 +400,7 @@ void FixRHEOThermal::post_integrate() MPI_Allreduce(&n_freeze, &n_freeze_all, 1, MPI_INT, MPI_SUM, world); if (cut_bond > 0 && (n_melt_all || n_freeze_all)) { - // Forward status then delete/create bonds + // Forward status + positions (after inititial integrate, before comm) comm->forward_comm(this); if (n_freeze_all) create_bonds(); @@ -623,7 +623,7 @@ void FixRHEOThermal::create_bonds() { int i, j, ii, jj, inum, jnum; int *ilist, *jlist, *numneigh, **firstneigh; - double xtmp, ytmp, ztmp, delx, dely, delz, rsq; + double delx, dely, delz, rsq; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; @@ -648,10 +648,6 @@ void FixRHEOThermal::create_bonds() i = ilist[ii]; if (!(status[i] & STATUS_SOLID)) continue; - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - jlist = firstneigh[i]; jnum = numneigh[i]; @@ -662,9 +658,18 @@ void FixRHEOThermal::create_bonds() if (!(status[j] & STATUS_SOLID)) continue; if (!(status[i] & STATUS_FREEZING) && !(status[j] & STATUS_FREEZING)) continue; - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; + // Ensure pair is always ordered to ensure numerical operations + // are identical to minimize the possibility that a bond straddling + // an mpi grid (newton off) isn't created on one proc but not the other + if (tag[i] < tag[j]) { + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + } else { + delx = x[j][0] - x[i][0]; + dely = x[j][1] - x[i][1]; + delz = x[j][2] - x[i][2]; + } rsq = delx * delx + dely * dely + delz * delz; if (rsq > cutsq_bond) continue; @@ -731,11 +736,15 @@ int FixRHEOThermal::pack_forward_comm(int n, int *list, double *buf, { int i, j, k, m; int *status = atom->status; + double **x = atom->x; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = ubuf(status[j]).d; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; } return m; } @@ -746,10 +755,13 @@ void FixRHEOThermal::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; int *status = atom->status; - + double **x = atom->x; m = 0; last = first + n; for (i = first; i < last; i++) { status[i] = (int) ubuf(buf[m++]).i; + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; } } From e5d687528766a15857bd35b9393c2ca00ab237cc Mon Sep 17 00:00:00 2001 From: Thomas O'Connor Date: Thu, 9 May 2024 11:52:16 -0400 Subject: [PATCH 084/385] Update Howto_rheo.rst Typos and wording. --- doc/src/Howto_rheo.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index 748c91845b..e9e0861dc3 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -1,9 +1,9 @@ Reproducing hydrodynamics and elastic objects (RHEO) ==================================================== -The RHEO package is built around an implementation of smoothed particle -hydrodynamics (SPH) coupled to the :doc:`BPM package ` to model -solid elements of a system. The SPH solver supports many advanced options +The RHEO package is a hybrid implementation of smoothed particle +hydrodynamics (SPH) for fluid flow, coupled to the :doc:`BPM package ` to model +solid elements. RHEO combines these methods to enable mesh-free modeling of multiphase material systems. The SPH solver supports many advanced options including reproducing kernels, particle shifting, free surface identification, and solid surface reconstruction. To model fluid-solid systems, the status of particles can dynamically change between a fluid and solid state, e.g. during @@ -23,14 +23,14 @@ instance of :doc:`fix rheo/pressure ` and of state and viscosity model, respectively. Optionally, one can model a heat equation with :doc:`fix rheo/thermal`, which also allows the user to specify equations for a particle's thermal conductivity, specific heat, -latent heat, and melting temperature. Fix rheo must be defined prior to all +latent heat, and melting temperature. The ordering of these fixes in an an input script matters. Fix rheo must be defined prior to all other RHEO fixes. Typically, RHEO requires atom style rheo. In addition to typical atom properties like positions and forces, particles store a local density, viscosity, pressure, and status. If thermal evolution is modeled, one must use atom style rheo/thermal which also include a local temperature and -conductivity. The status variable uses bitmasking to track various +thermal conductivity. RHEO style atoms also have a status variable which uses bitmasking to track various properties of a particle such as its current state of matter (fluid or solid) and its location relative to a surface. Many of these properties (and others) can be easily accessed using @@ -39,14 +39,14 @@ can be easily accessed using Fluid interactions, including pressure forces, viscous forces, and heat exchange, are calculated using :doc:`pair rheo `. Unlike typical pair styles, pair rheo ignores the :doc:`special bond ` settings. Instead, -it determines whether to calculate forces based on the status of particles: +it determines whether to calculate forces based on the status of particles: e.g., hydrodynamic forces are only calculated if a fluid particle is involved. ---------- -To model elastic objects, there are current two mechanisms in RHEO, one designed +To model elastic objects, there are currently two mechanisms in RHEO, one designed for bulk solid bodies and the other for thin shells. Both mechanisms rely on -overlaying bonds and therefore require a hybrid of atom style bond and rheo +introducing bonded forces between particles and therefore require a hybrid of atom style bond and rheo (or rheo/thermal). To create an elastic solid body, one has to (a) change the status of constituent From 343f8afbf6548e3b454174a5353c9cc17a37ad12 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 14 May 2024 14:47:11 -0600 Subject: [PATCH 085/385] Many minor tweaks, adding self/mass + oxide noshift --- doc/src/fix_rheo.rst | 40 ++++++++++++++++++------- doc/src/fix_rheo_viscosity.rst | 49 ++++++++++++++++++++++++++----- src/RHEO/compute_rheo_rho_sum.cpp | 16 +++++++--- src/RHEO/compute_rheo_rho_sum.h | 1 + src/RHEO/fix_rheo.cpp | 8 ++++- src/RHEO/fix_rheo.h | 1 + src/RHEO/fix_rheo_oxidation.cpp | 6 +++- src/RHEO/fix_rheo_thermal.cpp | 2 +- src/RHEO/fix_rheo_viscosity.cpp | 3 +- 9 files changed, 100 insertions(+), 26 deletions(-) diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 5c46ad892e..556d683c72 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -17,7 +17,7 @@ Syntax * zmin = minimal number of neighbors for reproducing kernels * zero or more keyword/value pairs may be appended to args * keyword = *thermal* or *interface/reconstruct* or *surface/detection* or - *shift* or *rho/sum* or *density* or *speed/sound* + *shift* or *rho/sum* or *density* or *self/mass* or *speed/sound* .. parsed-literal:: @@ -29,6 +29,7 @@ Syntax *limit/splash* = threshold for splash particles *shift* values = none, turns on velocity shifting *rho/sum* values = none, uses the kernel to compute the density of particles + *self/mass* values = none, a particle uses its own mass in a rho summation *density* values = *rho01*, ... *rho0N* (density) *speed/sound* values = *cs0*, ... *csN* (velocity) @@ -106,24 +107,38 @@ threshold for this classification is set by the numerical value of By default, RHEO integrates particles' densities using a mass diffusion equation. Alternatively, one can update densities every timestep by performing -a kernel summation of the masses of neighboring particles by specifying the *rho/sum* keyword. +a kernel summation of the masses of neighboring particles by specifying the *rho/sum* +keyword. -The *density* is used to specify the equilbrium density of each of the N +The *self/mass* keyword modifies the behavior of the density summation in *rho/sum*. +Typically, the density :math:`\rho` of a particle is calculated as the sum + +.. math:: + \rho_i = \Sum_{j} W_{ij} M_j + +where the summation is over neighbors, :math:`W_{ij}` is the kernel, and :math:`M_j` +is the mass of particle :math:`j`. The *self/mass* keyword augments this expression +by replacing :math:`M_j` with :math:`M_i`. This may be useful in simulations of +multiple fluid phases with large differences in density, :ref:`(Hu) `. + +The *density* keyword is used to specify the equilbrium density of each of the N particle types. It must be followed by N numerical values specifying each type's equilibrium density *rho0*. -The *density* is used to specify the speed of sound of each of the N particle -types. It must be followed by N numerical values specifying each type's speed -of sound *cs*. +The *speed/sound* keyword is used to specify the speed of sound of each of the +N particle types. It must be followed by N numerical values specifying each +type's speed of sound *cs*. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +No information about this fix is written to :doc:`binary restart files `. +None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various :doc:`output commands `. No parameter of this fix can be used with the *start/stop* keywords of -the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. +the :doc:`run ` command. This fix is not invoked during +:doc:`energy minimization `. Restrictions """""""""""" @@ -138,7 +153,8 @@ set to all. Only one instance of fix rheo may be defined and it must be defined prior to all other RHEO fixes. This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +LAMMPS was built with that package. See the +:doc:`Build package ` page for more info. Related commands """""""""""""""" @@ -156,6 +172,10 @@ Default ---------- -.. _howto-howto_rheo_palermo: +.. _howto_rheo_palermo: **(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. + +.. _fix_rheo_hu: + +**(Hu)** Hu, and Adams J. Comp. Physics, 213, 844-861 (2006). diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst index 8c403f8d0b..8175178787 100644 --- a/doc/src/fix_rheo_viscosity.rst +++ b/doc/src/fix_rheo_viscosity.rst @@ -14,20 +14,26 @@ Syntax * rheo/viscosity = style name of this fix command * one or more types and viscosity styles must be appended * types = lists of types (see below) -* vstyle = *constant* +* vstyle = *constant* or *power* .. parsed-literal:: *constant* args = *eta* *eta* = viscosity + *power* args = *eta*, *gd0*, *K*, *n* + *eta* = viscosity + *gd0* = critical strain rate + *K* = consistency index + *n* = power-law exponent + Examples """""""" .. code-block:: LAMMPS fix 1 all rheo/viscosity * constant 1.0 - fix 1 all rheo/viscosity 1 constant 1.0 2 constant 2.0 + fix 1 all rheo/viscosity 1 constant 1.0 2 power 0.1 5e-4 0.001 0.5 Description """"""""""" @@ -47,18 +53,38 @@ means all types from 1 to n (inclusive). A trailing asterisk means all types from m to :math:`N` (inclusive). A middle asterisk means all types from m to n (inclusive). -The *types* definition is followed by the viscosity style, *vstyle*. Currently, -the only option is *constant*. Style *constant* simply applies a constant value -of the viscosity *eta* to each particle of the assigned type. +The *types* definition is followed by the viscosity style, *vstyle*. Two +options are available, *constant* and *power*. Style *constant* simply +applies a constant value of the viscosity *eta* to each particle of the +assigned type. Style *power* is a Hershchel-Bulkley constitutive equation +for the stress :math:`\tau` + +.. math:: + + \tau = \left(\frac{\tau_0}{\dot{\gamma}} + K \dot{\gamma}^{n - 1}\right) \dot{\gamma}, \tau \ge \tau_0 + +where :math:`\dot{\gamma}` is the strain rate and :math:`tau_0` is the critical +yield stress, below which :math:`\dot{\gamma} = 0.0`. To avoid divergences, this +expression is regularized by defining a critical strain rate *gd0*. If the local +strain rate on a particle falls below this limit, a constant viscosity of *eta* +is assigned. This implies a value of + +.. math:: + \tau_0 = \eta * \dot{\gamma}_0 - K \dot{\gamma}_0^N + +as further discussed in :ref:`(Palermo) `. + Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +No information about this fix is written to :doc:`binary restart files `. +None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various :doc:`output commands `. No parameter of this fix can be used with the *start/stop* keywords of -the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. +the :doc:`run ` command. This fix is not invoked during +:doc:`energy minimization `. Restrictions """""""""""" @@ -69,7 +95,8 @@ conjuction with :doc:`fix rheo `. The fix group must be set to all. Only one instance of fix rheo/viscosity can be defined. This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +LAMMPS was built with that package. See the +:doc:`Build package ` page for more info. Related commands """""""""""""""" @@ -82,3 +109,9 @@ Default """"""" none + +---------- + +.. _howto_rheo_palermo: + +**(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp index 8322ad4ad4..c7270897a4 100644 --- a/src/RHEO/compute_rheo_rho_sum.cpp +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -35,7 +35,9 @@ using namespace LAMMPS_NS; ComputeRHEORhoSum::ComputeRHEORhoSum(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), fix_rheo(nullptr), compute_kernel(nullptr) { - if (narg != 3) error->all(FLERR,"Illegal compute RHEO/rho command"); + if (narg != 4) error->all(FLERR,"Illegal compute RHEO/rho command"); + + self_mass_flag = utils::bnumeric(FLERR, arg[3], false, lmp); comm_forward = 1; comm_reverse = 1; @@ -117,9 +119,15 @@ void ComputeRHEORhoSum::compute_peratom() rsq = delx * delx + dely * dely + delz * delz; if (rsq < cutsq) { w = compute_kernel->calc_w(i, j, delx, dely, delz, sqrt(rsq)); - rho[i] += w * mass[type[i]]; - if (newton || j < nlocal) { - rho[j] += w * mass[type[j]]; + + if (self_mass_flag) { + rho[i] += w * mass[type[i]]; + if (newton || j < nlocal) + rho[j] += w * mass[type[j]]; + } else { + rho[i] += w * mass[type[j]]; + if (newton || j < nlocal) + rho[j] += w * mass[type[i]]; } } } diff --git a/src/RHEO/compute_rheo_rho_sum.h b/src/RHEO/compute_rheo_rho_sum.h index 6ec2547b95..491e61ea81 100644 --- a/src/RHEO/compute_rheo_rho_sum.h +++ b/src/RHEO/compute_rheo_rho_sum.h @@ -39,6 +39,7 @@ class ComputeRHEORhoSum : public Compute { class FixRHEO *fix_rheo; private: + int self_mass_flag; double cut, cutsq; class NeighList *list; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index 98382b07b5..a355aee5d8 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -60,6 +60,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : interface_flag = 0; surface_flag = 0; oxidation_flag = 0; + self_mass_flag = 0; int i; int n = atom->ntypes; @@ -124,6 +125,8 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : interface_flag = 1; } else if (strcmp(arg[iarg], "rho/sum") == 0) { rhosum_flag = 1; + } else if (strcmp(arg[iarg], "self/mass")) { + self_mass_flag = 1; } else if (strcmp(arg[iarg], "density") == 0) { if (iarg + n >= narg) error->all(FLERR, "Illegal rho0 option in fix rheo"); for (i = 1; i <= n; i++) @@ -142,6 +145,9 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : iarg += 1; } + if (self_mass_flag && !rhosum_flag) + error->all(FLERR, "Cannot use self/mass setting without rho/sum"); + if (lmp->citeme) lmp->citeme->add(cite_rheo); } @@ -178,7 +184,7 @@ void FixRHEO::post_constructor() if (rhosum_flag) { compute_rhosum = dynamic_cast(modify->add_compute( - "rheo_rhosum all RHEO/RHO/SUM")); + fmt::format("rheo_rhosum all RHEO/RHO/SUM {}", self_mass_flag))); compute_rhosum->fix_rheo = this; } diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 51e0962000..89a0591824 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -41,6 +41,7 @@ class FixRHEO : public Fix { // Model parameters double h, cut; double *rho0, *csq; + int self_mass_flag; int zmin_kernel, zmin_surface, zmin_splash; int kernel_style, surface_style; double divr_surface; diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index 8539f04277..9f19d4f4da 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -141,6 +141,10 @@ void FixRHEOOxidation::setup_pre_force(int /*vflag*/) void FixRHEOOxidation::pre_force(int /*vflag*/) { + int *status = atom->status; + for (int i = 0; i < atom->nlocal; i++) + if (num_bond[i] != 0) + status[i] |= STATUS_NO_SHIFT; } /* ---------------------------------------------------------------------- */ @@ -215,7 +219,7 @@ void FixRHEOOxidation::post_integrate() if (bflag) continue; // Add bonds to owned atoms - // If newton bond, add to both, otherwise add to whichever has a smaller tag + // If newton bond off, add to both, otherwise add to whichever has a smaller tag if (!newton_bond || tagi < tagj) { if (num_bond[i] == atom->bond_per_atom) diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 5d4134a461..24a6a73021 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -674,7 +674,7 @@ void FixRHEOThermal::create_bonds() if (rsq > cutsq_bond) continue; // Add bonds to owned atoms - // If newton bond, add to both, otherwise add to whichever has a smaller tag + // If newton bond off, add to both, otherwise add to whichever has a smaller tag if (i < nlocal && (!newton_bond || tag[i] < tag[j])) { if (num_bond[i] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index abaa55ca70..2d5d58d494 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -56,6 +56,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : memory->create(gd0, n + 1, "rheo:gd0"); memory->create(K, n + 1, "rheo:K"); memory->create(npow, n + 1, "rheo:npow"); + memory->create(tau0, n + 1, "rheo:tau0"); for (i = 1; i <= n; i++) viscosity_style[i] = NONE; int iarg = 3; @@ -76,7 +77,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : viscosity_style[i] = CONSTANT; eta[i] = eta_one; } - } else if (strcmp(arg[iarg], "power") == 0) { + } else if (strcmp(arg[iarg + 1], "power") == 0) { if (iarg + 5 >= narg) utils::missing_cmd_args(FLERR, "fix rheo/viscosity power", error); comm_forward = 1; From 8d25c510c11cdbd538f8b29d391b5be8b7a7f551 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Sun, 19 May 2024 11:22:52 -0600 Subject: [PATCH 086/385] Draft examples, patches, clarify interface reconstruct in RHEO --- doc/src/Examples.rst | 2 + doc/src/Howto_rheo.rst | 28 +- doc/src/bond_rheo_shell.rst | 2 +- doc/src/compute_rheo_property_atom.rst | 32 +- doc/src/fix_rheo.rst | 3 +- doc/src/fix_rheo_oxidation.rst | 10 +- doc/src/fix_rheo_thermal.rst | 8 + doc/src/read_data.rst | 2 +- .../PACKAGES/rheo/dam-break/in.rheo.dam.break | 87 --- examples/rheo/balloon/in.rheo.balloon | 74 ++ examples/rheo/dam-break/in.rheo.dam.break | 81 +++ examples/rheo/ice-cubes/in.rheo.ice.cubes | 80 +++ examples/rheo/ice-cubes/square.mol | 658 ++++++++++++++++++ examples/rheo/oxidation/in.rheo.oxidation | 102 +++ .../rheo/poiseuille/in.rheo.poiseuille | 44 +- .../rheo/taylor-green/in.rheo.taylor.green | 26 +- src/GRANULAR/fix_add_heat.cpp | 2 +- src/RHEO/bond_rheo_shell.cpp | 1 - src/RHEO/compute_rheo_grad.cpp | 8 +- src/RHEO/compute_rheo_interface.cpp | 26 +- src/RHEO/compute_rheo_property_atom.cpp | 9 +- src/RHEO/compute_rheo_surface.cpp | 93 +-- src/RHEO/compute_rheo_surface.h | 1 - src/RHEO/compute_rheo_vshift.cpp | 29 +- src/RHEO/compute_rheo_vshift.h | 1 + src/RHEO/fix_rheo.cpp | 25 +- src/RHEO/fix_rheo.h | 2 +- src/RHEO/fix_rheo_oxidation.cpp | 49 +- src/RHEO/fix_rheo_oxidation.h | 3 +- src/RHEO/fix_rheo_thermal.cpp | 41 +- src/RHEO/fix_rheo_thermal.h | 2 +- src/RHEO/pair_rheo.cpp | 8 +- 32 files changed, 1265 insertions(+), 274 deletions(-) delete mode 100644 examples/PACKAGES/rheo/dam-break/in.rheo.dam.break create mode 100644 examples/rheo/balloon/in.rheo.balloon create mode 100644 examples/rheo/dam-break/in.rheo.dam.break create mode 100644 examples/rheo/ice-cubes/in.rheo.ice.cubes create mode 100644 examples/rheo/ice-cubes/square.mol create mode 100644 examples/rheo/oxidation/in.rheo.oxidation rename examples/{PACKAGES => }/rheo/poiseuille/in.rheo.poiseuille (55%) rename examples/{PACKAGES => }/rheo/taylor-green/in.rheo.taylor.green (68%) diff --git a/doc/src/Examples.rst b/doc/src/Examples.rst index c5da4a498b..3d2103fd6f 100644 --- a/doc/src/Examples.rst +++ b/doc/src/Examples.rst @@ -134,6 +134,8 @@ Lowercase directories +-------------+------------------------------------------------------------------+ | rerun | use of rerun and read_dump commands | +-------------+------------------------------------------------------------------+ +| rheo | RHEO simulations of fluid flows and phase transitions | ++-------------+------------------------------------------------------------------+ | rigid | rigid bodies modeled as independent or coupled | +-------------+------------------------------------------------------------------+ | shear | sideways shear applied to 2d solid, with and without a void | diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index 748c91845b..b09925d6ac 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -10,8 +10,12 @@ particles can dynamically change between a fluid and solid state, e.g. during melting/solidification, which determines how they interact and their physical behavior. The package is designed with modularity in mind, so one can easily turn various features on/off, adjust physical details of the system, or -develop new capabilities. Additional numerical details can be found in -:ref:`(Palermo) ` and :ref:`(Clemmer) `. +develop new capabilities. For instance, the numerics associated with +calculating gradients, reproducing kernels, etc. are separated into distinct +classes to simplify the development of new integration schemes which can call +these calculations. Additional numerical details can be found in +:ref:`(Palermo) ` and +:ref:`(Clemmer) `. ---------- @@ -29,12 +33,17 @@ other RHEO fixes. Typically, RHEO requires atom style rheo. In addition to typical atom properties like positions and forces, particles store a local density, viscosity, pressure, and status. If thermal evolution is modeled, one must -use atom style rheo/thermal which also include a local temperature and -conductivity. The status variable uses bitmasking to track various -properties of a particle such as its current state of matter (fluid or solid) -and its location relative to a surface. Many of these properties (and others) -can be easily accessed using -:doc:`compute rheo/property/atom `. +use atom style rheo/thermal which also includes a local energy, temperature, and +conductivity. Note that the temperature is always derived from the energy. +This implies the *temperature* attribute of :doc:`the set command ` does not +affect particles. Instead, one should use the *sph/e* attribute. + +The status variable uses bitmasking to track various properties of a particle +such as its current state of matter (fluid or solid) and its location relative +to a surface. Some of these properties (and others) can be accessed using +:doc:`compute rheo/property/atom `. The *status* attribute +in :doc:`the set command ` only allows control over the first bit which sets +the state of matter, 0 is fluid and 1 is solid. Fluid interactions, including pressure forces, viscous forces, and heat exchange, are calculated using :doc:`pair rheo `. Unlike typical pair styles, @@ -61,7 +70,8 @@ in the same elastic body. In systems with thermal evolution, fix rheo/thermal can optionally set a melting/solidification temperature allowing particles to dynamically swap their -state between fluid and solid. Using the *react* option, one can specify a maximum +state between fluid and solid when the temperature exceeds or drops below the +critical temperature, respectively. Using the *react* option, one can specify a maximum bond length and a bond type. Then, when solidifying, particles will search their local neighbors and automatically create bonds with any neighboring solid particles in range. For BPM bond styles, bonds will then use the immediate position of the two diff --git a/doc/src/bond_rheo_shell.rst b/doc/src/bond_rheo_shell.rst index 713bd84136..3b5cfa6a49 100644 --- a/doc/src/bond_rheo_shell.rst +++ b/doc/src/bond_rheo_shell.rst @@ -65,7 +65,7 @@ the setup of a run. Data is then preserved across run commands and is written to :doc:`binary restart files ` such that restarting the system will not reset the reference state of a bond or the timer. -This bond style is based on a model described in Ref. +This bond style is based on a model described in :ref:`(Clemmer) `. The force has a magnitude of .. math:: diff --git a/doc/src/compute_rheo_property_atom.rst b/doc/src/compute_rheo_property_atom.rst index 8d1cf47f58..a7e1bff383 100644 --- a/doc/src/compute_rheo_property_atom.rst +++ b/doc/src/compute_rheo_property_atom.rst @@ -16,19 +16,18 @@ Syntax .. parsed-literal:: - possible attributes = phase, chi, surface, surface/r, + possible attributes = phase, surface, surface/r, surface/divr, surface/n/x, surface/n/y, surface/n/z, coordination, cv, shift/v/x, shift/v/y, shift/v/z, energy, temperature, heatflow, conductivity, cv, viscosity, pressure, - status, rho, grad/v/xx, grad/v/xy, grad/v/xz, + rho, grad/v/xx, grad/v/xy, grad/v/xz, grad/v/yx, grad/v/yy/, grad/v/yz, grad/v/zx, grad/v/zy, grad/v/zz .. parsed-literal:: *phase* = atom phase state - *chi* = atom local phase metric *surface* = atom surface status *surface/r* = atom distance from the surface *surface/divr* = divergence of position at atom position @@ -42,7 +41,6 @@ Syntax *cv* = atom specific heat *viscosity* = atom viscosity *pressure* = atom pressure - *status* = atom full status *rho* = atom density *grad/v/\** = atom velocity gradient *nbond/shell* = number of oxide bonds @@ -70,14 +68,32 @@ computes as inputs. See for example, the :doc:`fix ave/chunk `, and :doc:`atom-style variable ` commands. -The possible attributes are described in more detail in other RHEO doc -pages including :doc:`the RHEO howto page `. Many -properties require their respective fixes, listed below in related -commands, be defined. +Many properties require their respective fixes, listed below in related +commands, be defined. For instance, the *viscosity* attribute is the +viscosity of a particle calculated by +:doc:`fix rheo/viscous `. The meaning of less obvious +properties is described below. + +The *phase* property indicates whether the particle is in a fluid state, +a value of 0, or a solid state, a value of 1. + +The *surface* property indicates the surface designation produced by +the *interface/reconstruct* option of :doc:`fix rheo `. Bulk +particles have a value of 0, surface particles have a value of 1, and +splash particles have a value of 2. The *surface/r* property is the +distance from the surface, up to the kernel cutoff length. Surface particles +have a value of 0. The *surface/n* properties are the components of the +surface normal vector. + +The *shift/v* properties are the components of the shifting velocity +produced by the *shift* option of :doc:`fix rheo `. The *surface/n/\** and *shift/v/\** attributes are vectors that require specification of the *x*, *y*, or *z* component, e.g. *surface/n/x*. +The *nbond/shell* property is the number of shell bonds that have been +activated from :doc:`bond style rheo/shell `. + The *grad/v/\** attribute is a tensor and requires specification of the *xx*, *yy*, *zz*, *xy*, *xz*, *yx*, *yz*, *zx*, or *zy* component, e.g. *grad/v/xy*. diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 556d683c72..978691db41 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -92,7 +92,8 @@ Shifting is then disabled in the direction away from the free surface to prevent it from diffusing particles away from the bulk fluid. Surface detection can also be used to control surface-nucleated effects like oxidation when used in combination with -:doc:`fix rheo/oxidation `. +:doc:`fix rheo/oxidation `. Surface detection is not +performed on solid bodies. The *surface/detection* keyword takes three arguments: *sdstyle*, *limit*, and *limi/splash*. The first, *sdstyle*, specifies whether surface particles diff --git a/doc/src/fix_rheo_oxidation.rst b/doc/src/fix_rheo_oxidation.rst index 42e2b6d59e..3043291c60 100644 --- a/doc/src/fix_rheo_oxidation.rst +++ b/doc/src/fix_rheo_oxidation.rst @@ -35,10 +35,12 @@ for use with bond style :doc:`bond rheo/shell `. Every timestep, particles check neighbors within a distance of *cut*. This distance must be smaller than the kernel length defined in -:doc:`fix rheo `. If both particles are on the fluid surface, -or within a distance of *rsurf* from the surface, a bond of type -*btype* is created between the two particles. This process is -further described in Ref. :ref:`(Clemmer) `. +:doc:`fix rheo `. Bonds of type *btype* are created between +pairs of particles that satisfy one of two conditions. First, if both +particles are on the fluid surface, or within a distance of *rsurf* +from the surface. Secondly, if one particle is on the fluid surface +and the other bond is solid. This process is further described in +:ref:`(Clemmer) `. If used in conjunction with solid bodies, such as those generated by the *react* option of :doc:`fix rheo/thermal `, diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index 2ffb665bb7..1ceb1259c0 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -55,12 +55,20 @@ rheo/thermal. In addition, it defines multiple thermal properties of particles and handles melting/solidification, if applicable. For more details on phase transitions in RHEO, see :doc:`the RHEO howto `. +Note that the temperature of a particle is always derived from the energy. +This implies the *temperature* attribute of :doc:`the set command ` does +not affect particles. Instead, one should use the *sph/e* attribute. + For each atom type, one can define attributes for the *conductivity*, *specific/heat*, *latent/heat*, and critical temperature (*Tfreeze*). The conductivity and specific heat must be defined for all atom types. The latent heat and critical temperature are optional. However, a critical temperature must be defined to specify a latent heat. +Note, if shifting is turned on in :doc:`fix rheo `, the gradient +of the energy is used to shift energies. This may be inappropriate in systems +with multiple atom types with different specific heats. + For each property, one must first define a list of atom types. A wild-card asterisk can be used in place of or in conjunction with the *types* argument to set the coefficients for multiple pairs of atom types. This takes the diff --git a/doc/src/read_data.rst b/doc/src/read_data.rst index 4950d8bc25..5ebb34dcab 100644 --- a/doc/src/read_data.rst +++ b/doc/src/read_data.rst @@ -717,7 +717,7 @@ of analysis. * - rheo - atom-ID atom-type status rho x y z * - rheo/thermal - - atom-ID atom-type status rho temperature x y z + - atom-ID atom-type status rho energy x y z * - smd - atom-ID atom-type molecule volume mass kradius cradius x0 y0 z0 x y z * - sph diff --git a/examples/PACKAGES/rheo/dam-break/in.rheo.dam.break b/examples/PACKAGES/rheo/dam-break/in.rheo.dam.break deleted file mode 100644 index 207fd6885e..0000000000 --- a/examples/PACKAGES/rheo/dam-break/in.rheo.dam.break +++ /dev/null @@ -1,87 +0,0 @@ -# ------ 2D dam break ------ # - -dimension 2 -units lj -atom_style rheo -boundary f s p -comm_modify vel yes -newton off -comm_style tiled - - -# ------ Create simulation box ------ # - -variable sf equal 0.05 -variable n equal 1.0/(${sf}^2) -variable cut equal 3.0*${sf} - -region box block -1 55 -1 20 -0.01 0.01 units box -create_box 2 box -lattice sq ${n} - -region left_wall block -1 0 EDGE EDGE -0.01 0.01 units box -region right_wall block 53.66 EDGE EDGE EDGE -0.01 0.01 units box -region bot_wall block 0.01 53.65 -1 0 -0.01 0.01 units box -region interior block 0.01 10 0.01 20 -0.01 0.01 units box - -create_atoms 1 region interior -create_atoms 2 region left_wall -create_atoms 2 region right_wall -create_atoms 2 region bot_wall - -group fluid type 1 -group static_wall type 2 -group dyn_wall type 3 -group rig union static_wall dyn_wall - - -# ------ Model parameters ------ # - -variable rho0 equal 1.0 -variable mp equal ${rho0}/${n} -variable cs equal 10 -variable zeta equal 1 -variable Dr equal 0.1*${cut}*${cs} -variable dt_max equal 0.1*${cut}/${cs}/3 -variable g equal 0.0245 -variable fext equal ${g}/${n} -variable eta equal 0.05 - -mass * ${mp} -variable d0 atom (${rho0}*${g}*(20-y)/${cs}/${cs})+${rho0} -set group all rheo/rho ${rho0} -set group fluid rheo/rho v_d0 - -set group all rheo/status 0 -set group rig rheo/status 2 - -timestep ${dt_max} - -pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} -pair_coeff * * - - -# ------ Fixes & computes ------ # - -fix 1 all rheo ${cut} RK1 32 shift surface/detection coordination 26 -fix 2 all rheo/viscosity constant ${eta} -fix 3 all rheo/pressure linear -fix 4 rig setforce 0.0 0.0 0.0 -fix 5 fluid addforce 0.0 -${fext} 0.0 -fix 6 all balance 1000 1.1 rcb - -compute 1 all rheo/property/atom rho phase surface - - -# ------ Output & Run ------ # - -thermo 10 -thermo_style custom step time ke press - -variable skin equal 0.2*${cut} -neighbor ${skin} bin -neigh_modify one 5000 - -dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] - -run 400000 diff --git a/examples/rheo/balloon/in.rheo.balloon b/examples/rheo/balloon/in.rheo.balloon new file mode 100644 index 0000000000..d24573b0fb --- /dev/null +++ b/examples/rheo/balloon/in.rheo.balloon @@ -0,0 +1,74 @@ +# ------ 2D water balloon ------ # + +dimension 2 +units lj +atom_style hybrid rheo bond +boundary m m p +comm_modify vel yes +newton off + +region box block -40 40 0 80 -0.01 0.01 units box +create_box 1 box bond/types 1 extra/bond/per/atom 15 extra/special/per/atom 50 + +region fluid sphere -10 40 0 30 units box side in +lattice hex 1.0 +create_atoms 1 region fluid + +region shell sphere -10 40 0 27 units box side out +group shell region shell + +set group shell rheo/status 1 +set group all vx 0.005 vy -0.04 + +# ------ Model parameters ------# + +variable cut equal 3.0 +variable n equal 1.0 +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable zeta equal 0.05 +variable kappa equal 0.01*${rho0}/${mp} +variable dt_max equal 0.1*${cut}/${cs}/3 +variable eta equal 0.05 +variable Cv equal 1.0 +variable L equal 1.0 +variable Tf equal 1.0 + +mass * ${mp} +timestep 0.1 + +pair_style hybrid/overlay rheo ${cut} artificial/visc ${zeta} rheo/solid +pair_coeff * * rheo +pair_coeff * * rheo/solid 1.0 1.0 1.0 + +special_bonds lj 0.0 1.0 1.0 coul 0.0 1.0 1.0 +create_bonds many shell shell 1 0 1.5 +special_bonds lj 0.0 1.0 1.0 coul 1.0 1.0 1.0 + +bond_style bpm/spring +bond_coeff 1 1.0 1.0 1.0 + +# A lower critical strain allows the balloon to pop +#bond_coeff 1 1.0 0.05 1.0 + +# ------ Drop balloon ------# + +fix 1 all rheo ${cut} quintic 0 & + shift & + surface/detection coordination 22 8 +fix 2 all rheo/viscosity * constant ${eta} +fix 3 all rheo/pressure * linear +fix 4 all wall/harmonic ylo EDGE 2.0 1.0 1.0 + +compute rho all rheo/property/atom rho +compute phase all rheo/property/atom phase +compute nbond all nbond/atom + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press atoms + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_nbond c_rho +run 30000 diff --git a/examples/rheo/dam-break/in.rheo.dam.break b/examples/rheo/dam-break/in.rheo.dam.break new file mode 100644 index 0000000000..b59b710451 --- /dev/null +++ b/examples/rheo/dam-break/in.rheo.dam.break @@ -0,0 +1,81 @@ +# ------ 2D dam break ------ # + +dimension 2 +units lj +atom_style rheo +boundary f f p +comm_modify vel yes +newton off + +# ------ Create simulation box ------ # + +variable n equal 1.0 +variable cut equal 3.0 +variable dx equal 4.0 + +region box block -1 200 -1 80 -0.1 0.1 units box +#region box block -1 100 -1 40 -0.1 0.1 units box +create_box 2 box +lattice hex ${n} + +region fluid block $(xlo+v_dx) $(xlo+44.0) $(ylo+v_dx) $(yhi-16.0) EDGE EDGE units box +#region fluid block $(xlo+v_dx) $(xlo+20.0) $(ylo+v_dx) $(yhi-10.0) EDGE EDGE units box +region walls block $(xlo+v_dx) $(xhi-v_dx) $(ylo+v_dx) $(yhi-v_dx) EDGE EDGE units box side out + +create_atoms 1 region fluid +create_atoms 2 region walls + +group fluid type 1 +group rig type 2 + +# ------ Model parameters ------ # + +variable rho0 equal 1.0 +variable mp equal ${rho0}/${n} +variable cs equal 1.0 +variable zeta equal 0.05 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable eta equal 0.05 +variable Dr equal 0.05 + +mass * ${mp} +set group all rheo/rho ${rho0} + +set group all rheo/status 0 +set group rig rheo/status 1 + +timestep ${dt_max} + +pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} +pair_coeff * * + + +# ------ Fixes & computes ------ # + +fix 1 all rheo ${cut} quintic 10 & + shift & + surface/detection coordination 22 8 & + interface/reconstruct +#fix 1 all rheo ${cut} RK1 10 surface/detection coordination 36 10 interface/reconstruct shift +fix 2 all rheo/viscosity * constant ${eta} +fix 3 all rheo/pressure * linear +fix 4 all gravity 5e-4 vector 0 -1 0 +fix 5 rig setforce 0.0 0.0 0.0 + +compute rho all rheo/property/atom rho +compute phase all rheo/property/atom phase +compute p all rheo/property/atom pressure +compute surf all rheo/property/atom surface +compute sn all rheo/property/atom surface/n/x surface/n/y +compute vshift all rheo/property/atom shift/v/x shift/v/y + + +# ------ Output & Run ------ # + +thermo 100 +thermo_style custom step time ke press + +dump 1 all custom 20 atomDump id type x y vx vy fx fy c_rho c_phase c_surf c_p c_vshift[*] c_sn[*] + +#thermo 1 +run 300000 # 400000 diff --git a/examples/rheo/ice-cubes/in.rheo.ice.cubes b/examples/rheo/ice-cubes/in.rheo.ice.cubes new file mode 100644 index 0000000000..12eb54c32e --- /dev/null +++ b/examples/rheo/ice-cubes/in.rheo.ice.cubes @@ -0,0 +1,80 @@ +# ------ 2D Ice Cube Pour ------ # + +dimension 2 +units lj +atom_style hybrid rheo/thermal bond +boundary m m p +comm_modify vel yes +newton off +special_bonds lj 0.0 1.0 1.0 coul 1.0 1.0 1.0 + +region box block -25 25 0 100 -0.01 0.01 units box +create_box 1 box bond/types 1 extra/bond/per/atom 15 extra/special/per/atom 50 + +region fluid block $(xlo+1) $(xhi-1) $(ylo+1) $(ylo+30) EDGE EDGE units box +lattice sq 1.0 +create_atoms 1 region fluid + +set group all sph/e 8.0 + +# ------ Model parameters ------# + +variable cut equal 3.0 +variable n equal 1.0 +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable zeta equal 0.05 +variable kappa equal 0.01*${rho0}/${mp} +variable dt_max equal 0.1*${cut}/${cs}/3 +variable eta equal 0.05 +variable Cv equal 1.0 +variable L equal 1.0 +variable Tf equal 1.0 + +mass * ${mp} +timestep 0.1 + +pair_style hybrid/overlay rheo ${cut} artificial/visc ${zeta} rheo/solid +pair_coeff * * rheo +pair_coeff * * rheo/solid 1.0 1.0 1.0 + +bond_style bpm/spring +bond_coeff 1 1.0 1.0 1.0 + +# ------ Pour particles ------# + +molecule my_mol "square.mol" + +# Wall region extends far enough in z to avoid contact +region wall block EDGE EDGE EDGE EDGE -5 5 side in open 4 units box +region drop block -16 16 70 90 EDGE EDGE side in units box + +fix 1 all rheo ${cut} quintic 0 & + thermal & + shift & + surface/detection coordination 22 8 +fix 2 all rheo/viscosity * constant ${eta} +fix 3 all rheo/pressure * linear +fix 4 all rheo/thermal conductivity * constant ${kappa} & + specific/heat * constant ${Cv} & + Tfreeze * constant ${Tf} & + latent/heat * constant ${L} & + react 1.5 1 +fix 5 all wall/region wall harmonic 1.0 1.0 1.0 +fix 6 all gravity 5e-4 vector 0 -1 0 +fix 7 all deposit 8 0 1000 37241459 mol my_mol region drop near 2.0 vy -0.02 -0.02 + +compute rho all rheo/property/atom rho +compute phase all rheo/property/atom phase +compute temp all rheo/property/atom temperature +compute eng all rheo/property/atom energy +compute nbond all nbond/atom + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press atoms + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond c_rho +run 30000 diff --git a/examples/rheo/ice-cubes/square.mol b/examples/rheo/ice-cubes/square.mol new file mode 100644 index 0000000000..0344be7244 --- /dev/null +++ b/examples/rheo/ice-cubes/square.mol @@ -0,0 +1,658 @@ +#Made with create_mol.py + +100 atoms +342 bonds + +Coords +#ID x y z +1 -4 -4 0 +2 -3 -4 0 +3 -2 -4 0 +4 -1 -4 0 +5 0 -4 0 +6 1 -4 0 +7 2 -4 0 +8 3 -4 0 +9 4 -4 0 +10 5 -4 0 +11 -4 -3 0 +12 -3 -3 0 +13 -2 -3 0 +14 -1 -3 0 +15 0 -3 0 +16 1 -3 0 +17 2 -3 0 +18 3 -3 0 +19 4 -3 0 +20 5 -3 0 +21 -4 -2 0 +22 -3 -2 0 +23 -2 -2 0 +24 -1 -2 0 +25 0 -2 0 +26 1 -2 0 +27 2 -2 0 +28 3 -2 0 +29 4 -2 0 +30 5 -2 0 +31 -4 -1 0 +32 -3 -1 0 +33 -2 -1 0 +34 -1 -1 0 +35 0 -1 0 +36 1 -1 0 +37 2 -1 0 +38 3 -1 0 +39 4 -1 0 +40 5 -1 0 +41 -4 0 0 +42 -3 0 0 +43 -2 0 0 +44 -1 0 0 +45 0 0 0 +46 1 0 0 +47 2 0 0 +48 3 0 0 +49 4 0 0 +50 5 0 0 +51 -4 1 0 +52 -3 1 0 +53 -2 1 0 +54 -1 1 0 +55 0 1 0 +56 1 1 0 +57 2 1 0 +58 3 1 0 +59 4 1 0 +60 5 1 0 +61 -4 2 0 +62 -3 2 0 +63 -2 2 0 +64 -1 2 0 +65 0 2 0 +66 1 2 0 +67 2 2 0 +68 3 2 0 +69 4 2 0 +70 5 2 0 +71 -4 3 0 +72 -3 3 0 +73 -2 3 0 +74 -1 3 0 +75 0 3 0 +76 1 3 0 +77 2 3 0 +78 3 3 0 +79 4 3 0 +80 5 3 0 +81 -4 4 0 +82 -3 4 0 +83 -2 4 0 +84 -1 4 0 +85 0 4 0 +86 1 4 0 +87 2 4 0 +88 3 4 0 +89 4 4 0 +90 5 4 0 +91 -4 5 0 +92 -3 5 0 +93 -2 5 0 +94 -1 5 0 +95 0 5 0 +96 1 5 0 +97 2 5 0 +98 3 5 0 +99 4 5 0 +100 5 5 0 + +Types +#ID type +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +21 1 +22 1 +23 1 +24 1 +25 1 +26 1 +27 1 +28 1 +29 1 +30 1 +31 1 +32 1 +33 1 +34 1 +35 1 +36 1 +37 1 +38 1 +39 1 +40 1 +41 1 +42 1 +43 1 +44 1 +45 1 +46 1 +47 1 +48 1 +49 1 +50 1 +51 1 +52 1 +53 1 +54 1 +55 1 +56 1 +57 1 +58 1 +59 1 +60 1 +61 1 +62 1 +63 1 +64 1 +65 1 +66 1 +67 1 +68 1 +69 1 +70 1 +71 1 +72 1 +73 1 +74 1 +75 1 +76 1 +77 1 +78 1 +79 1 +80 1 +81 1 +82 1 +83 1 +84 1 +85 1 +86 1 +87 1 +88 1 +89 1 +90 1 +91 1 +92 1 +93 1 +94 1 +95 1 +96 1 +97 1 +98 1 +99 1 +100 1 + +Masses +#ID mass +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +21 1 +22 1 +23 1 +24 1 +25 1 +26 1 +27 1 +28 1 +29 1 +30 1 +31 1 +32 1 +33 1 +34 1 +35 1 +36 1 +37 1 +38 1 +39 1 +40 1 +41 1 +42 1 +43 1 +44 1 +45 1 +46 1 +47 1 +48 1 +49 1 +50 1 +51 1 +52 1 +53 1 +54 1 +55 1 +56 1 +57 1 +58 1 +59 1 +60 1 +61 1 +62 1 +63 1 +64 1 +65 1 +66 1 +67 1 +68 1 +69 1 +70 1 +71 1 +72 1 +73 1 +74 1 +75 1 +76 1 +77 1 +78 1 +79 1 +80 1 +81 1 +82 1 +83 1 +84 1 +85 1 +86 1 +87 1 +88 1 +89 1 +90 1 +91 1 +92 1 +93 1 +94 1 +95 1 +96 1 +97 1 +98 1 +99 1 +100 1 + +Bonds +#ID type atom1 atom2 +1 1 1 2 +2 1 1 11 +3 1 1 12 +4 1 2 3 +5 1 2 11 +6 1 2 12 +7 1 2 13 +8 1 3 4 +9 1 3 12 +10 1 3 13 +11 1 3 14 +12 1 4 5 +13 1 4 13 +14 1 4 14 +15 1 4 15 +16 1 5 6 +17 1 5 14 +18 1 5 15 +19 1 5 16 +20 1 6 7 +21 1 6 15 +22 1 6 16 +23 1 6 17 +24 1 7 8 +25 1 7 16 +26 1 7 17 +27 1 7 18 +28 1 8 9 +29 1 8 17 +30 1 8 18 +31 1 8 19 +32 1 9 10 +33 1 9 18 +34 1 9 19 +35 1 9 20 +36 1 10 19 +37 1 10 20 +38 1 11 21 +39 1 11 12 +40 1 11 22 +41 1 12 21 +42 1 12 13 +43 1 12 22 +44 1 12 23 +45 1 13 22 +46 1 13 23 +47 1 13 14 +48 1 13 24 +49 1 14 23 +50 1 14 24 +51 1 14 15 +52 1 14 25 +53 1 15 24 +54 1 15 16 +55 1 15 25 +56 1 15 26 +57 1 16 25 +58 1 16 26 +59 1 16 17 +60 1 16 27 +61 1 17 26 +62 1 17 18 +63 1 17 27 +64 1 17 28 +65 1 18 27 +66 1 18 28 +67 1 18 19 +68 1 18 29 +69 1 19 28 +70 1 19 29 +71 1 19 20 +72 1 19 30 +73 1 20 29 +74 1 20 30 +75 1 21 22 +76 1 21 31 +77 1 21 32 +78 1 22 23 +79 1 22 31 +80 1 22 32 +81 1 22 33 +82 1 23 24 +83 1 23 32 +84 1 23 33 +85 1 23 34 +86 1 24 25 +87 1 24 33 +88 1 24 34 +89 1 24 35 +90 1 25 26 +91 1 25 34 +92 1 25 35 +93 1 25 36 +94 1 26 27 +95 1 26 35 +96 1 26 36 +97 1 26 37 +98 1 27 28 +99 1 27 36 +100 1 27 37 +101 1 27 38 +102 1 28 29 +103 1 28 37 +104 1 28 38 +105 1 28 39 +106 1 29 30 +107 1 29 38 +108 1 29 39 +109 1 29 40 +110 1 30 39 +111 1 30 40 +112 1 31 32 +113 1 31 41 +114 1 31 42 +115 1 32 33 +116 1 32 41 +117 1 32 42 +118 1 32 43 +119 1 33 34 +120 1 33 42 +121 1 33 43 +122 1 33 44 +123 1 34 35 +124 1 34 43 +125 1 34 44 +126 1 34 45 +127 1 35 36 +128 1 35 44 +129 1 35 45 +130 1 35 46 +131 1 36 37 +132 1 36 45 +133 1 36 46 +134 1 36 47 +135 1 37 38 +136 1 37 46 +137 1 37 47 +138 1 37 48 +139 1 38 39 +140 1 38 47 +141 1 38 48 +142 1 38 49 +143 1 39 40 +144 1 39 48 +145 1 39 49 +146 1 39 50 +147 1 40 49 +148 1 40 50 +149 1 41 51 +150 1 41 42 +151 1 41 52 +152 1 42 51 +153 1 42 43 +154 1 42 52 +155 1 42 53 +156 1 43 52 +157 1 43 53 +158 1 43 44 +159 1 43 54 +160 1 44 53 +161 1 44 54 +162 1 44 45 +163 1 44 55 +164 1 45 54 +165 1 45 46 +166 1 45 55 +167 1 45 56 +168 1 46 55 +169 1 46 56 +170 1 46 47 +171 1 46 57 +172 1 47 56 +173 1 47 48 +174 1 47 57 +175 1 47 58 +176 1 48 57 +177 1 48 58 +178 1 48 49 +179 1 48 59 +180 1 49 58 +181 1 49 59 +182 1 49 50 +183 1 49 60 +184 1 50 59 +185 1 50 60 +186 1 51 52 +187 1 51 61 +188 1 51 62 +189 1 52 53 +190 1 52 61 +191 1 52 62 +192 1 52 63 +193 1 53 54 +194 1 53 62 +195 1 53 63 +196 1 53 64 +197 1 54 55 +198 1 54 63 +199 1 54 64 +200 1 54 65 +201 1 55 56 +202 1 55 64 +203 1 55 65 +204 1 55 66 +205 1 56 57 +206 1 56 65 +207 1 56 66 +208 1 56 67 +209 1 57 58 +210 1 57 66 +211 1 57 67 +212 1 57 68 +213 1 58 59 +214 1 58 67 +215 1 58 68 +216 1 58 69 +217 1 59 60 +218 1 59 68 +219 1 59 69 +220 1 59 70 +221 1 60 69 +222 1 60 70 +223 1 61 71 +224 1 61 62 +225 1 61 72 +226 1 62 71 +227 1 62 63 +228 1 62 72 +229 1 62 73 +230 1 63 72 +231 1 63 73 +232 1 63 64 +233 1 63 74 +234 1 64 73 +235 1 64 74 +236 1 64 65 +237 1 64 75 +238 1 65 74 +239 1 65 66 +240 1 65 75 +241 1 65 76 +242 1 66 75 +243 1 66 76 +244 1 66 67 +245 1 66 77 +246 1 67 76 +247 1 67 68 +248 1 67 77 +249 1 67 78 +250 1 68 77 +251 1 68 78 +252 1 68 69 +253 1 68 79 +254 1 69 78 +255 1 69 79 +256 1 69 70 +257 1 69 80 +258 1 70 79 +259 1 70 80 +260 1 71 72 +261 1 71 81 +262 1 71 82 +263 1 72 73 +264 1 72 81 +265 1 72 82 +266 1 72 83 +267 1 73 74 +268 1 73 82 +269 1 73 83 +270 1 73 84 +271 1 74 75 +272 1 74 83 +273 1 74 84 +274 1 74 85 +275 1 75 76 +276 1 75 84 +277 1 75 85 +278 1 75 86 +279 1 76 77 +280 1 76 85 +281 1 76 86 +282 1 76 87 +283 1 77 78 +284 1 77 86 +285 1 77 87 +286 1 77 88 +287 1 78 79 +288 1 78 87 +289 1 78 88 +290 1 78 89 +291 1 79 80 +292 1 79 88 +293 1 79 89 +294 1 79 90 +295 1 80 89 +296 1 80 90 +297 1 81 82 +298 1 81 91 +299 1 81 92 +300 1 82 83 +301 1 82 91 +302 1 82 92 +303 1 82 93 +304 1 83 84 +305 1 83 92 +306 1 83 93 +307 1 83 94 +308 1 84 85 +309 1 84 93 +310 1 84 94 +311 1 84 95 +312 1 85 86 +313 1 85 94 +314 1 85 95 +315 1 85 96 +316 1 86 87 +317 1 86 95 +318 1 86 96 +319 1 86 97 +320 1 87 88 +321 1 87 96 +322 1 87 97 +323 1 87 98 +324 1 88 89 +325 1 88 97 +326 1 88 98 +327 1 88 99 +328 1 89 90 +329 1 89 98 +330 1 89 99 +331 1 89 100 +332 1 90 99 +333 1 90 100 +334 1 91 92 +335 1 92 93 +336 1 93 94 +337 1 94 95 +338 1 95 96 +339 1 96 97 +340 1 97 98 +341 1 98 99 +342 1 99 100 diff --git a/examples/rheo/oxidation/in.rheo.oxidation b/examples/rheo/oxidation/in.rheo.oxidation new file mode 100644 index 0000000000..5c1456ad5a --- /dev/null +++ b/examples/rheo/oxidation/in.rheo.oxidation @@ -0,0 +1,102 @@ +# ------ 2D oxidizing bar ------ # + +dimension 2 +units lj +atom_style hybrid rheo/thermal bond +boundary m m p +comm_modify vel yes +newton off + +region box block -60 60 0 80 -0.01 0.01 units box +create_box 3 box bond/types 2 extra/bond/per/atom 20 extra/special/per/atom 50 + + +region lbar block -15 0 3 80 EDGE EDGE units box +region rbar block 0 15 3 80 EDGE EDGE units box +region bar union 2 lbar rbar +region floor block EDGE EDGE EDGE 3.0 EDGE EDGE units box + +lattice hex 1.0 +create_atoms 1 region bar +create_atoms 3 region floor + +set region rbar type 2 +group bar type 1 2 +group rbar type 2 +group floor type 3 + +set group all sph/e 0.0 +set group all rheo/status 1 + +# ------ Model parameters ------# + +variable cut equal 3.0 +variable n equal 1.0 +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable zeta equal 0.05 +variable kappa equal 0.1*${rho0}/${mp} +variable dt_max equal 0.1*${cut}/${cs}/3 +variable eta equal 0.05 +variable Cv equal 1.0 +variable L equal 0.1 +variable Tf equal 1.0 + +mass * ${mp} +timestep 0.1 + +pair_style hybrid/overlay rheo ${cut} artificial/visc ${zeta} rheo/solid +pair_coeff * * rheo +pair_coeff * * rheo/solid 1.0 1.0 1.0 + +special_bonds lj 0.0 1.0 1.0 coul 0.0 1.0 1.0 +create_bonds many bar bar 1 0 1.5 +special_bonds lj 0.0 1.0 1.0 coul 1.0 1.0 1.0 + +bond_style hybrid bpm/spring rheo/shell t/form 100 +bond_coeff 1 bpm/spring 1.0 1.0 1.0 +bond_coeff 2 rheo/shell 0.2 0.2 0.1 + +# ------ Apply dynamics ------# + +# Note: surface detection is not performed on solid bodies, so cannot use surface property +compute coord all rheo/property/atom coordination +variable surf atom c_coord<22 +group surf dynamic all var surf every 10 + +fix 1 all rheo ${cut} quintic 0 & + thermal & + shift & + surface/detection coordination 22 8 +fix 2 all rheo/viscosity * constant ${eta} +fix 3 all rheo/pressure * linear +fix 4 all rheo/thermal conductivity * constant ${kappa} & + specific/heat * constant ${Cv} & + Tfreeze * constant ${Tf} & + latent/heat * constant ${L} & + react 1.5 1 + +fix 5 rbar rheo/oxidation 1.5 2 1.0 +fix 6 all wall/harmonic ylo EDGE 2.0 1.0 1.0 +fix 7 all gravity 5e-5 vector 0 -1 0 +fix 8 floor setforce 0.0 0.0 0.0 +fix 9 surf add/heat linear 1.1 0.05 +fix 10 floor add/heat constant 0 overwrite yes # fix the temperature of the floor + +compute surf all rheo/property/atom surface +compute rho all rheo/property/atom rho +compute phase all rheo/property/atom phase +compute status all rheo/property/atom status +compute temp all rheo/property/atom temperature +compute eng all rheo/property/atom energy +compute nbond_shell all rheo/property/atom nbond/shell +compute nbond_solid all nbond/atom bond/type 1 + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press atoms + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond_solid c_nbond_shell c_rho c_surf c_status +run 40000 diff --git a/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille b/examples/rheo/poiseuille/in.rheo.poiseuille similarity index 55% rename from examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille rename to examples/rheo/poiseuille/in.rheo.poiseuille index 6f5ad91e73..ee8ad5523c 100644 --- a/examples/PACKAGES/rheo/poiseuille/in.rheo.poiseuille +++ b/examples/rheo/poiseuille/in.rheo.poiseuille @@ -9,28 +9,23 @@ comm_modify vel yes # ------ Create simulation box ------ # -variable sf equal 0.2 -variable n equal 1.0/(${sf}^2) -variable cut equal 3.5*${sf} +variable n equal 1.0 +variable cut equal 3.0 -region box block 0 20 -10 10 -0.01 0.01 units box +region box block 0 20 -10 10 -0.01 0.01 create_box 2 box lattice sq ${n} -region topwall block INF INF 7 10 INF INF units box -region block block INF INF -6.99 6.99 INF INF units box -region botwall block INF INF -10 -7 INF INF units box +region inner block INF INF -7.5 7.5 INF INF units box +region walls block INF INF -7.5 7.5 INF INF units box side out -create_atoms 2 region topwall -create_atoms 2 region botwall -create_atoms 1 region block +create_atoms 2 region walls +create_atoms 1 region inner group fluid type 1 group rig type 2 -variable dr equal 0.1*${sf} -displace_atoms fluid random $(0.1*v_sf) ${dr} 0 135414 units box - +displace_atoms fluid random 0.1 0.1 0 135414 units box # ------ Model parameters ------ # @@ -39,15 +34,19 @@ variable cs equal 1.0 variable mp equal ${rho0}/${n} variable zeta equal 1.0 variable kappa equal 1.0*${rho0}/${mp} -variable fext equal 1e-3/${n} -variable eta equal 0.1 +variable fext equal 1e-4/${n} variable dt_max equal 0.1*${cut}/${cs}/3 variable Dr equal 0.05*${cut}*${cs} +variable eta equal 0.1 +variable gd0 equal 5e-4 +variable npow equal 0.5 +variable K equal 0.001 + mass * ${mp} set group all rheo/rho ${rho0} set group all rheo/status 0 -set group rig rheo/status 2 +set group rig rheo/status 1 timestep ${dt_max} @@ -58,12 +57,13 @@ pair_coeff * * # ------ Fixes & computes ------ # fix 1 all rheo ${cut} quintic 0 shift -fix 2 all rheo/viscosity constant ${eta} -fix 3 all rheo/pressure linear +fix 2 all rheo/viscosity * constant ${eta} +#fix 2 all rheo/viscosity * power ${eta} ${gd0} ${K} ${npow} +fix 3 all rheo/pressure * linear fix 4 rig setforce 0.0 0.0 0.0 fix 5 fluid addforce ${fext} 0.0 0.0 -compute 1 all rheo/property/atom rho phase +compute rho all rheo/property/atom rho # ------ Output & Run ------ # @@ -71,11 +71,7 @@ compute 1 all rheo/property/atom rho phase thermo 200 thermo_style custom step time ke press -variable skin equal 0.2*${cut} -neighbor ${skin} bin -neigh_modify one 5000 - -#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho run 20000 diff --git a/examples/PACKAGES/rheo/taylor-green/in.rheo.taylor.green b/examples/rheo/taylor-green/in.rheo.taylor.green similarity index 68% rename from examples/PACKAGES/rheo/taylor-green/in.rheo.taylor.green rename to examples/rheo/taylor-green/in.rheo.taylor.green index 5367ceef13..e386d8262c 100644 --- a/examples/PACKAGES/rheo/taylor-green/in.rheo.taylor.green +++ b/examples/rheo/taylor-green/in.rheo.taylor.green @@ -10,19 +10,16 @@ newton off # ------ Create simulation box ------ # -variable sf equal 0.1 -variable n equal 1.0/(${sf}^2) -variable cut equal 3.5*${sf} +variable n equal 1.0 +variable cut equal 3.0 -region box block 0 10 0 10 -0.01 0.01 units box +region box block 0 40 0 40 -0.01 0.01 create_box 1 box lattice sq ${n} create_atoms 1 region box -variable dr equal 0.1*${sf} -displace_atoms all random ${dr} ${dr} 0 135414 units box - +displace_atoms all random 0.1 0.1 0 135414 units box # ------ Model parameters ------ # @@ -53,22 +50,17 @@ pair_coeff * * # ------ Fixes & computes ------ # -fix 1 all rheo ${cut} quintic 0 shift -fix 2 all rheo/viscosity constant ${eta} -fix 3 all rheo/pressure linear - -compute 1 all rheo/property/atom rho phase +fix 1 all rheo ${cut} RK1 8 shift +fix 2 all rheo/viscosity * constant ${eta} +fix 3 all rheo/pressure * linear +compute rho all rheo/property/atom rho # ------ Output & Run ------ # thermo 200 thermo_style custom step time ke press -variable skin equal 0.2*${cut} -neighbor ${skin} bin -neigh_modify one 10000 #increase number of allowed neighbors - -#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_1[*] +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho run 10000 \ No newline at end of file diff --git a/src/GRANULAR/fix_add_heat.cpp b/src/GRANULAR/fix_add_heat.cpp index 7109ffb01c..a68c9c2b95 100644 --- a/src/GRANULAR/fix_add_heat.cpp +++ b/src/GRANULAR/fix_add_heat.cpp @@ -68,7 +68,7 @@ FixAddHeat::FixAddHeat(LAMMPS *lmp, int narg, char **arg) : while (iarg < narg) { if (strcmp(arg[iarg], "overwrite") == 0) { if (iarg + 1 >= narg) utils::missing_cmd_args(FLERR, "fix add/heat", error); - overwrite_flag = utils::bnumeric(FLERR, arg[iarg + 1], false, lmp); + overwrite_flag = utils::logical(FLERR, arg[iarg + 1], false, lmp); iarg += 2; } else { error->all(FLERR, "Illegal fix add/heat command, invalid argument {}", arg[iarg]); diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index 6b464c4000..c8eee29438 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -227,7 +227,6 @@ void BondRHEOShell::compute(int eflag, int vflag) if (t < EPSILON || std::isnan(t)) t = store_bond(n, i1, i2); - delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 5ed43a421a..8b618e6e04 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -213,12 +213,10 @@ void ComputeRHEOGrad::compute_peratom() // Add corrections for walls if (interface_flag) { if (fluidi && (!fluidj)) { - compute_interface->correct_v(vi, vj, i, j); - //compute_interface->correct_v(vj, vi, j, i); + compute_interface->correct_v(vj, vi, j, i); rhoj = compute_interface->correct_rho(j, i); } else if ((!fluidi) && fluidj) { - compute_interface->correct_v(vj, vi, j, i); - //compute_interface->correct_v(vi, vj, i, j); + compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { rhoi = rho0[itype]; @@ -346,7 +344,7 @@ int ComputeRHEOGrad::pack_forward_comm(int n, int *list, double *buf, } else if (comm_stage == COMMFIELD) { if (velocity_flag) { - if (remap_v_flag & pbc_flag & (mask[j] & deform_groupbit)) { + if (remap_v_flag && pbc_flag && (mask[j] & deform_groupbit)) { for (k = 0; k < dim; k++) buf[m++] = v[j][k] + dv[k]; } else { diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 31930d655d..672c63ba29 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -165,11 +165,11 @@ void ComputeRHEOInterface::compute_peratom() fluidj = !(status[j] & PHASECHECK); w = compute_kernel->calc_w_quintic(i, j, dx[0], dx[1], dx[2], sqrt(rsq)); - status_match = 0; norm[i] += w; + + status_match = 0; if ((fluidi && fluidj) || ((!fluidi) && (!fluidj))) status_match = 1; - if (status_match) { chi[i] += w; } else { @@ -307,30 +307,26 @@ void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) /* ---------------------------------------------------------------------- */ -void ComputeRHEOInterface::correct_v(double *vi, double *vj, int i, int j) +void ComputeRHEOInterface::correct_v(double *v_solid, double *v_fluid, int i_solid, int i_fluid) { double wall_prefactor, wall_denom, wall_numer; - wall_numer = 2.0 * cut * (chi[i] - 0.5); - if (wall_numer < 0) wall_numer = 0; - wall_denom = 2.0 * cut * (chi[j] - 0.5); - if (wall_denom < wall_max) wall_denom = wall_max; + wall_numer = MAX(2.0 * cut * (chi[i_solid] - 0.5), 0.0); + wall_denom = MAX(2.0 * cut * (chi[i_fluid] - 0.5), wall_max); wall_prefactor = wall_numer / wall_denom; - vi[0] = (vi[0] - vj[0]) * wall_prefactor + vi[0]; - vi[1] = (vi[1] - vj[1]) * wall_prefactor + vi[1]; - vi[2] = (vi[2] - vj[2]) * wall_prefactor + vi[2]; + v_solid[0] = (v_solid[0] - v_fluid[0]) * wall_prefactor; + v_solid[1] = (v_solid[1] - v_fluid[1]) * wall_prefactor; + v_solid[2] = (v_solid[2] - v_fluid[2]) * wall_prefactor; } /* ---------------------------------------------------------------------- */ -double ComputeRHEOInterface::correct_rho(int i, int j) +double ComputeRHEOInterface::correct_rho(int i_solid, int i_fluid) { - // i is wall, j is fluid - //In future may depend on atom type j's pressure equation - int itype = atom->type[i]; - return MAX(rho0[itype], atom->rho[i]); + int itype = atom->type[i_solid]; + return MAX(rho0[itype], atom->rho[i_solid]); } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 11b03623b1..d6d8c2a07a 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -292,9 +292,14 @@ void ComputeRHEOPropertyAtom::pack_surface(int n) int *mask = atom->mask; int nlocal = atom->nlocal; + double label; for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = (status[i] & SURFACECHECK); - else buf[n] = 0.0; + label = 0; + if (mask[i] & groupbit) { + if (status[i] & STATUS_SURFACE) label = 1.0; + if (status[i] & STATUS_SPLASH) label = 2.0; + } + buf[n] = label; n += nvalues; } } diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 1ef69bb6f0..bf2f2a3297 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -50,23 +50,18 @@ ComputeRHEOSurface::ComputeRHEOSurface(LAMMPS *lmp, int narg, char **arg) : int dim = domain->dimension; comm_forward = 2; comm_reverse = dim * dim + 1; + + nmax_store = 0; + grow_arrays(atom->nmax); } /* ---------------------------------------------------------------------- */ ComputeRHEOSurface::~ComputeRHEOSurface() { - // Remove custom property if it exists - int tmp1, tmp2, index; - index = atom->find_custom("rheo_divr", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - - index = atom->find_custom("rheo_rsurface", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 0); - - index = atom->find_custom("rheo_nsurface", tmp1, tmp2); - if (index != -1) atom->remove_custom(index, 1, 3); - + memory->destroy(divr); + memory->destroy(rsurface); + memory->destroy(nsurface); memory->destroy(B); memory->destroy(gradC); } @@ -87,29 +82,6 @@ void ComputeRHEOSurface::init() cutsq = cut * cut; - // Create rsurface, divr, nsurface arrays as custom atom properties, - // can print with compute property/atom - // no grow callback as there's no reason to copy/exchange data, manually grow - // For B and gradC, create a local array since they are unlikely to be printed - - int dim = domain->dimension; - int tmp1, tmp2; - index_divr = atom->find_custom("rheo_divr", tmp1, tmp2); - if (index_divr == -1) index_divr = atom->add_custom("rheo_divr", 1, 0); - divr = atom->dvector[index_divr]; - - index_rsurf = atom->find_custom("rheo_rsurface", tmp1, tmp2); - if (index_rsurf == -1) index_rsurf = atom->add_custom("rheo_rsurface", 1, 0); - rsurface = atom->dvector[index_rsurf]; - - index_nsurf = atom->find_custom("rheo_nsurface", tmp1, tmp2); - if (index_nsurf == -1) index_nsurf = atom->add_custom("rheo_nsurface", 1, dim); - nsurface = atom->darray[index_nsurf]; - - nmax_store = atom->nmax; - memory->create(B, nmax_store, dim * dim, "rheo/surface:B"); - memory->create(gradC, nmax_store, dim * dim, "rheo/surface:gradC"); - // need an occasional half neighbor list neighbor->add_request(this, NeighConst::REQ_DEFAULT); } @@ -148,7 +120,7 @@ void ComputeRHEOSurface::compute_peratom() firstneigh = list->firstneigh; // Grow and zero arrays - if (nmax_store <= atom->nmax) + if (nmax_store < atom->nmax) grow_arrays(atom->nmax); size_t nbytes = nmax_store * sizeof(double); @@ -253,6 +225,10 @@ void ComputeRHEOSurface::compute_peratom() else test = coordination[i] < threshold_z; + // Treat nonfluid particles as bulk + if (status[i] & PHASECHECK) + test = 0; + if (test) { if (coordination[i] < threshold_splash) status[i] |= STATUS_SPLASH; @@ -272,6 +248,7 @@ void ComputeRHEOSurface::compute_peratom() xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; + fluidi = !(status[i] & PHASECHECK); jlist = firstneigh[i]; jnum = numneigh[i]; @@ -280,22 +257,25 @@ void ComputeRHEOSurface::compute_peratom() j = jlist[jj]; j &= NEIGHMASK; + fluidj = !(status[j] & PHASECHECK); + dx[0] = xtmp - x[j][0]; dx[1] = ytmp - x[j][1]; dx[2] = ztmp - x[j][2]; rsq = lensq3(dx); if (rsq < cutsq) { - if ((status[i] & STATUS_BULK) && (status[j] & STATUS_SURFACE)) { - status[i] &= SURFACEMASK; - status[i] |= STATUS_LAYER; + if (fluidi) { + if ((status[i] & STATUS_BULK) && (status[j] & STATUS_SURFACE)) { + status[i] &= SURFACEMASK; + status[i] |= STATUS_LAYER; + } + + if (status[j] & STATUS_SURFACE) + rsurface[i] = MIN(rsurface[i], sqrt(rsq)); } - if (status[j] & STATUS_SURFACE) - rsurface[i] = MIN(rsurface[i], sqrt(rsq)); - - - if (j < nlocal || newton) { - if ((status[j] & STATUS_BULK) && (status[i] & STATUS_SURFACE)) { + if (fluidj && (j < nlocal || newton)) { + if ((status[j] & STATUS_BULK) && (status[j] & PHASECHECK) && (status[i] & STATUS_SURFACE)) { status[j] &= SURFACEMASK; status[j] |= STATUS_LAYER; } @@ -307,6 +287,16 @@ void ComputeRHEOSurface::compute_peratom() } } + // clear normal vectors for non surface particles + + for (i = 0; i < nall; i++) { + if (mask[i] & groupbit) { + if (!(status[i] & STATUS_SURFACE)) + for (a = 0; a < dim; a++) + nsurface[i][a] = 0.0; + } + } + // forward/reverse status and rsurface comm_stage = 1; comm_reverse = 2; @@ -416,18 +406,11 @@ void ComputeRHEOSurface::grow_arrays(int nmax) { int dim = domain->dimension; - // Grow atom variables and reassign pointers - memory->grow(atom->dvector[index_divr], nmax, "atom:rheo_divr"); - memory->grow(atom->dvector[index_rsurf], nmax, "atom:rheo_rsurface"); - memory->grow(atom->darray[index_nsurf], nmax, dim, "atom:rheo_nsurface"); - - divr = atom->dvector[index_divr]; - rsurface = atom->dvector[index_rsurf]; - nsurface = atom->darray[index_nsurf]; - - // Grow local variables + memory->grow(divr, nmax, "rheo/surface:divr"); + memory->grow(rsurface, nmax, "rheo/surface:rsurface"); + memory->grow(nsurface, nmax, dim, "rheo/surface:nsurface"); memory->grow(B, nmax, dim * dim, "rheo/surface:B"); memory->grow(gradC, nmax, dim * dim, "rheo/surface:gradC"); - nmax_store = atom->nmax; + nmax_store = nmax; } diff --git a/src/RHEO/compute_rheo_surface.h b/src/RHEO/compute_rheo_surface.h index 6ef2428499..044ff470c6 100644 --- a/src/RHEO/compute_rheo_surface.h +++ b/src/RHEO/compute_rheo_surface.h @@ -42,7 +42,6 @@ class ComputeRHEOSurface : public Compute { private: int surface_style, nmax_store, threshold_z, threshold_splash, interface_flag; int threshold_style, comm_stage; - int index_divr, index_rsurf, index_nsurf; double cut, cutsq, *rho0, threshold_divr; double **B, **gradC; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 533287911a..6e858ca207 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -72,6 +72,7 @@ void ComputeRHEOVShift::init() compute_interface = fix_rheo->compute_interface; compute_surface = fix_rheo->compute_surface; + rho0 = fix_rheo->rho0; cut = fix_rheo->cut; cutsq = cut * cut; cutthird = cut / 3.0; @@ -174,16 +175,14 @@ void ComputeRHEOVShift::compute_peratom() // Add corrections for walls if (interface_flag) { if (fluidi && (!fluidj)) { - compute_interface->correct_v(vi, vj, i, j); - //compute_interface->correct_v(vj, vi, j, i); - rhoj = compute_interface->correct_rho(j,i); - } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vj, vi, j, i); - //compute_interface->correct_v(vi, vj, i, j); - rhoi = compute_interface->correct_rho(i,j); + rhoj = compute_interface->correct_rho(j, i); + } else if ((!fluidi) && fluidj) { + compute_interface->correct_v(vi, vj, i, j); + rhoi = compute_interface->correct_rho(i, j); } else if ((!fluidi) && (!fluidj)) { - rhoi = 1.0; - rhoj = 1.0; + rhoi = rho0[itype]; + rhoj = rho0[jtype]; } } @@ -196,7 +195,7 @@ void ComputeRHEOVShift::compute_peratom() w4 = w * w * w * w / (w0 * w0 * w0 * w0); dr = -2 * cutthird * (1 + 0.2 * w4) * wp * rinv; - if (mask[i] & groupbit) { + if ((mask[i] & groupbit) && fluidi) { vmag = sqrt(vi[0] * vi[0] + vi[1] * vi[1] + vi[2] * vi[2]); prefactor = vmag * volj * dr; @@ -206,7 +205,7 @@ void ComputeRHEOVShift::compute_peratom() } if (newton_pair || j < nlocal) { - if (mask[j] & groupbit) { + if ((mask[j] & groupbit) && fluidj) { vmag = sqrt(vj[0] * vj[0] + vj[1] * vj[1] + vj[2] * vj[2]); prefactor = vmag * voli * dr; @@ -241,7 +240,11 @@ void ComputeRHEOVShift::correct_surfaces() double nx, ny, nz, vx, vy, vz, dot; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { - if ((status[i] & STATUS_SURFACE) || (status[i] & STATUS_LAYER)) { + + if (status[i] & PHASECHECK) continue; + + //if ((status[i] & STATUS_SURFACE) || (status[i] & STATUS_LAYER)) { + if (status[i] & STATUS_SURFACE) { nx = nsurface[i][0]; ny = nsurface[i][1]; vx = vshift[i][0]; @@ -266,6 +269,10 @@ void ComputeRHEOVShift::correct_surfaces() } else { vshift[i][2] = 0.0; } + } else if (status[i] & STATUS_SPLASH) { + vshift[i][0] = 0.0; + vshift[i][1] = 0.0; + vshift[i][2] = 0.0; } } } diff --git a/src/RHEO/compute_rheo_vshift.h b/src/RHEO/compute_rheo_vshift.h index 9d3a0166d6..485c6525f3 100644 --- a/src/RHEO/compute_rheo_vshift.h +++ b/src/RHEO/compute_rheo_vshift.h @@ -43,6 +43,7 @@ class ComputeRHEOVShift : public Compute { int nmax_store; double dtv, cut, cutsq, cutthird; int surface_flag, interface_flag; + double *rho0; class NeighList *list; class ComputeRHEOInterface *compute_interface; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index a355aee5d8..cb2abfb938 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -125,7 +125,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : interface_flag = 1; } else if (strcmp(arg[iarg], "rho/sum") == 0) { rhosum_flag = 1; - } else if (strcmp(arg[iarg], "self/mass")) { + } else if (strcmp(arg[iarg], "self/mass") == 0) { self_mass_flag = 1; } else if (strcmp(arg[iarg], "density") == 0) { if (iarg + n >= narg) error->all(FLERR, "Illegal rho0 option in fix rheo"); @@ -145,7 +145,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : iarg += 1; } - if (self_mass_flag && !rhosum_flag) + if (self_mass_flag && (!rhosum_flag)) error->all(FLERR, "Cannot use self/mass setting without rho/sum"); if (lmp->citeme) lmp->citeme->add(cite_rheo); @@ -227,6 +227,26 @@ void FixRHEO::init() if (modify->get_fix_by_style("^rheo$").size() > 1) error->all(FLERR, "Can only specify one instance of fix rheo"); + + if (atom->status_flag != 1) + error->all(FLERR,"fix rheo command requires atom property status"); + if (atom->rho_flag != 1) + error->all(FLERR,"fix rheo command requires atom property rho"); + if (atom->pressure_flag != 1) + error->all(FLERR,"fix rheo command requires atom property pressure"); + if (atom->viscosity_flag != 1) + error->all(FLERR,"fix rheo command requires atom property viscosity"); + + if (thermal_flag) { + if (atom->esph_flag != 1) + error->all(FLERR,"fix rheo command requires atom property esph with thermal setting"); + if (atom->temperature_flag != 1) + error->all(FLERR,"fix rheo command requires atom property temperature with thermal setting"); + if (atom->heatflow_flag != 1) + error->all(FLERR,"fix rheo command requires atom property heatflow with thermal setting"); + if (atom->conductivity_flag != 1) + error->all(FLERR,"fix rheo command requires atom property conductivity with thermal setting"); + } } /* ---------------------------------------------------------------------- */ @@ -386,6 +406,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) for (i = 0; i < nlocal; i++) { if (status[i] & STATUS_NO_SHIFT) continue; + if (status[i] & PHASECHECK) continue; if (mask[i] & groupbit) { for (a = 0; a < dim; a++) { diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 89a0591824..0af9fa8d01 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -79,7 +79,7 @@ namespace RHEO_NS { enum Status{ // Phase status STATUS_SOLID = 1 << 0, - // STATUS_REACTIVE = 1 << 1, + // Gap for future phase: STATUS_ = 1 << 1, // Surface status STATUS_BULK = 1 << 2, diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index 9f19d4f4da..5b0a50b4a5 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -30,6 +30,7 @@ #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" +#include "update.h" using namespace LAMMPS_NS; using namespace RHEO_NS; @@ -55,6 +56,8 @@ FixRHEOOxidation::FixRHEOOxidation(LAMMPS *lmp, int narg, char **arg) : { if (narg != 6) error->all(FLERR,"Illegal fix command"); + force_reneighbor = 1; + next_reneighbor = -1; comm_forward = 3; cut = utils::numeric(FLERR, arg[3], false, lmp); @@ -82,8 +85,9 @@ FixRHEOOxidation::~FixRHEOOxidation() int FixRHEOOxidation::setmask() { int mask = 0; - mask |= PRE_FORCE; mask |= POST_INTEGRATE; + mask |= PRE_FORCE; + mask |= POST_FORCE; return mask; } @@ -133,25 +137,19 @@ void FixRHEOOxidation::setup_pre_force(int /*vflag*/) if (!fix_rheo->surface_flag) error->all(FLERR, "fix rheo/oxidation requires surface calculation in fix rheo"); compute_surface = fix_rheo->compute_surface; - - pre_force(0); } /* ---------------------------------------------------------------------- */ void FixRHEOOxidation::pre_force(int /*vflag*/) { - int *status = atom->status; - for (int i = 0; i < atom->nlocal; i++) - if (num_bond[i] != 0) - status[i] |= STATUS_NO_SHIFT; } /* ---------------------------------------------------------------------- */ void FixRHEOOxidation::post_integrate() { - int i, j, n, ii, jj, inum, jnum, bflag; + int i, j, n, ii, jj, inum, jnum, bflag, fluidi, fluidj; int *ilist, *jlist, *numneigh, **firstneigh; double delx, dely, delz, rsq; tagint tagi, tagj; @@ -163,6 +161,8 @@ void FixRHEOOxidation::post_integrate() tagint **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; + int *mask = atom->mask; + int *status = atom->status; double *rsurface = compute_surface->rsurface; double **x = atom->x; @@ -175,10 +175,15 @@ void FixRHEOOxidation::post_integrate() // Note: surface designation lags one timestep, acceptable error comm->forward_comm(this); + int added_bonds = 0; // loop over neighbors of my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; - if (rsurface[i] > rsurf) continue; + if (!(mask[i] & groupbit)) continue; + + // Exclude particles that aren't solid or surface + fluidi = !(status[i] & PHASECHECK); + if (fluidi && (rsurface[i] > rsurf)) continue; tagi = tag[i]; @@ -188,8 +193,13 @@ void FixRHEOOxidation::post_integrate() for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; + if (!(mask[j] & groupbit)) continue; - if (rsurface[j] > rsurf) continue; + fluidj = !(status[j] & PHASECHECK); + if (fluidj && (rsurface[j] > rsurf)) continue; + + // Skip solid-solid, leaves surface-surface or surface-solid + if ((!fluidi) && (!fluidj)) continue; tagj = tag[j]; @@ -218,6 +228,8 @@ void FixRHEOOxidation::post_integrate() } if (bflag) continue; + added_bonds += 1; + // Add bonds to owned atoms // If newton bond off, add to both, otherwise add to whichever has a smaller tag @@ -230,6 +242,23 @@ void FixRHEOOxidation::post_integrate() } } } + + int added_bonds_all; + MPI_Allreduce(&added_bonds, &added_bonds_all, 1, MPI_INT, MPI_SUM, world); + + if (added_bonds_all > 0) + next_reneighbor = update->ntimestep; +} + +/* ---------------------------------------------------------------------- */ + +void FixRHEOOxidation::post_force(int /*vflag*/) +{ + int *status = atom->status; + int *num_bond = atom->num_bond; + for (int i = 0; i < atom->nlocal; i++) + if (num_bond[i] != 0) + status[i] |= STATUS_NO_SHIFT; } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_oxidation.h b/src/RHEO/fix_rheo_oxidation.h index 5991a830c0..6dddea867a 100644 --- a/src/RHEO/fix_rheo_oxidation.h +++ b/src/RHEO/fix_rheo_oxidation.h @@ -34,8 +34,9 @@ class FixRHEOOxidation : public Fix { void init() override; void init_list(int, class NeighList *) override; void setup_pre_force(int) override; - void pre_force(int) override; void post_integrate() override; + void pre_force(int) override; + void post_force(int) override; int pack_forward_comm(int, int *, double *, int, int *) override; void unpack_forward_comm(int, int, double *) override; int *nbond; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 24a6a73021..321fee07e7 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -259,7 +259,8 @@ void FixRHEOThermal::init() compute_grad = fix_rheo->compute_grad; compute_vshift = fix_rheo->compute_vshift; - dtf = 0.5 * update->dt * force->ftm2v; + dt = update->dt; + dth = 0.5 * update->dt; if (atom->esph_flag != 1) error->all(FLERR,"fix rheo/thermal command requires atom property esph"); @@ -337,7 +338,7 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) for (i = 0; i < nlocal; i++) { if (status[i] & STATUS_NO_SHIFT) continue; for (a = 0; a < dim; a++) - energy[i] += dtv * vshift[i][a] * grade[i][a]; + energy[i] += dt * vshift[i][a] * grade[i][a]; } } @@ -363,7 +364,7 @@ void FixRHEOThermal::post_integrate() itype = type[i]; cvi = calc_cv(i, itype); - energy[i] += dtf * heatflow[i]; + energy[i] += dth * heatflow[i]; temperature[i] = energy[i] / cvi; if (Tc_style[itype] != NONE) { @@ -376,6 +377,8 @@ void FixRHEOThermal::post_integrate() temperature[i] = Ti; } + // Check phase change if Ti != Tci + if (Ti > Tci) { // If solid, melt if (status[i] & STATUS_SOLID) { @@ -383,7 +386,9 @@ void FixRHEOThermal::post_integrate() status[i] |= STATUS_MELTING; n_melt += 1; } - } else { + } + + if (Ti < Tci) { // If fluid, freeze if (!(status[i] & STATUS_SOLID)) { status[i] &= PHASEMASK; @@ -400,6 +405,23 @@ void FixRHEOThermal::post_integrate() MPI_Allreduce(&n_freeze, &n_freeze_all, 1, MPI_INT, MPI_SUM, world); if (cut_bond > 0 && (n_melt_all || n_freeze_all)) { + + // If a particle freezes, check if it already has bonds of that type + // If so, assume it was inserted as a solid particle + // Note: inserted solid particle may still shift one timestep + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; + for (i = 0; i < atom->nlocal; i++) { + if (status[i] & STATUS_FREEZING) { + for (int n = 0; n < num_bond[i]; n++) { + if (bond_type[i][n] == btype) { + status[i] &= ~STATUS_FREEZING; + break; + } + } + } + } + // Forward status + positions (after inititial integrate, before comm) comm->forward_comm(this); @@ -464,11 +486,6 @@ void FixRHEOThermal::pre_force(int /*vflag*/) } } } - - // Add temporary options, wiped by preceding fix rheo preforce - for (int i = 0; i < nall; i++) - if (status[i] & STATUS_SOLID) - status[i] |= STATUS_NO_SHIFT; } /* ---------------------------------------------------------------------- */ @@ -482,7 +499,7 @@ void FixRHEOThermal::final_integrate() //Integrate energy for (int i = 0; i < atom->nlocal; i++) { if (status[i] & STATUS_NO_INTEGRATION) continue; - energy[i] += dtf * heatflow[i]; + energy[i] += dth * heatflow[i]; } } @@ -490,8 +507,8 @@ void FixRHEOThermal::final_integrate() void FixRHEOThermal::reset_dt() { - dtv = update->dt; - dtf = 0.5 * update->dt * force->ftm2v; + dt = update->dt; + dth = 0.5 * update->dt; } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/fix_rheo_thermal.h b/src/RHEO/fix_rheo_thermal.h index c4c26eef6a..264bbdbce3 100644 --- a/src/RHEO/fix_rheo_thermal.h +++ b/src/RHEO/fix_rheo_thermal.h @@ -48,7 +48,7 @@ class FixRHEOThermal : public Fix { private: double *cv, *Tc, *kappa, *L; - double dtf, dtv; + double dt, dth; double cut_kernel, cut_bond, cutsq_bond; int *cv_style, *Tc_style, *kappa_style, *L_style; int btype; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 6e8c20a5d8..0a52bd53bc 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -208,14 +208,14 @@ void PairRHEO::compute(int eflag, int vflag) // Add corrections for walls rhoi = rho[i]; rhoj = rho[j]; - rho0i = rho[itype]; - rho0j = rho[jtype]; + rho0i = rho0[itype]; + rho0j = rho0[jtype]; Pi = pressure[i]; Pj = pressure[j]; fmag = 0; if (interface_flag) { if (fluidi && (!fluidj)) { - compute_interface->correct_v(vi, vj, i, j); + compute_interface->correct_v(vj, vi, j, i); rhoj = compute_interface->correct_rho(j, i); Pj = fix_pressure->calc_pressure(rhoj, jtype); @@ -223,7 +223,7 @@ void PairRHEO::compute(int eflag, int vflag) fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0j * csq_ave * h * rinv; } else if ((!fluidi) && fluidj) { - compute_interface->correct_v(vj, vi, j, i); + compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i, j); Pi = fix_pressure->calc_pressure(rhoi, itype); From 1792679bb849c3a9eb0b4b8351289b36135b75a3 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Mon, 3 Jun 2024 14:28:31 -0400 Subject: [PATCH 087/385] first draft of pair style lj/spica/coul/long/kk --- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 590 ++++++++++++++++++ src/KOKKOS/pair_lj_spica_coul_long_kokkos.h | 138 ++++ 2 files changed, 728 insertions(+) create mode 100644 src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp create mode 100644 src/KOKKOS/pair_lj_spica_coul_long_kokkos.h diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp new file mode 100644 index 0000000000..e0d6542418 --- /dev/null +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -0,0 +1,590 @@ +// 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 "pair_lj_spica_coul_long_kokkos.h" + +#include "atom_kokkos.h" +#include "atom_masks.h" +//#include "comm.h" +#include "error.h" +#include "ewald_const.h" +#include "force.h" +#include "kokkos.h" +#include "memory_kokkos.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "neighbor.h" +#include "respa.h" +#include "update.h" + +#include "lj_spica_common.h" + +#include +#include + +using namespace LAMMPS_NS; +using namespace LJSPICAParms; + +// FIXME: +using namespace EwaldConst; + +/* ---------------------------------------------------------------------- */ + +template +PairLJSPICACoulLongKokkos::PairLJSPICACoulLongKokkos(LAMMPS *lmp) : PairLJSPICACoulLong(lmp) +{ + respa_enable = 0; + + kokkosable = 1; + atomKK = (AtomKokkos *) atom; + execution_space = ExecutionSpaceFromDevice::space; + datamask_read = X_MASK | F_MASK | TYPE_MASK | ENERGY_MASK | VIRIAL_MASK; + datamask_modify = F_MASK | ENERGY_MASK | VIRIAL_MASK; +} + +/* ---------------------------------------------------------------------- */ + +template +PairLJSPICACoulLongKokkos::~PairLJSPICACoulLongKokkos() +{ + if (copymode) return; + + if (allocated) { + memoryKK->destroy_kokkos(k_eatom,eatom); + memoryKK->destroy_kokkos(k_vatom,vatom); + memoryKK->destroy_kokkos(k_cutsq,cutsq); + memoryKK->destroy_kokkos(k_cut_lj,cut_lj); + memoryKK->destroy_kokkos(k_cut_ljsq,cut_ljsq); + } +} + +/* ---------------------------------------------------------------------- */ + +template +void PairLJSPICACoulLongKokkos::compute(int eflag_in, int vflag_in) +{ + eflag = eflag_in; + vflag = vflag_in; + + + if (neighflag == FULL) no_virial_fdotr_compute = 1; + + ev_init(eflag,vflag,0); + + // reallocate per-atom arrays if necessary + + if (eflag_atom) { + memoryKK->destroy_kokkos(k_eatom,eatom); + memoryKK->create_kokkos(k_eatom,eatom,maxeatom,"pair:eatom"); + d_eatom = k_eatom.view(); + } + if (vflag_atom) { + memoryKK->destroy_kokkos(k_vatom,vatom); + memoryKK->create_kokkos(k_vatom,vatom,maxvatom,"pair:vatom"); + d_vatom = k_vatom.view(); + } + + atomKK->sync(execution_space,datamask_read); + k_cutsq.template sync(); + k_params.template sync(); + if (eflag || vflag) atomKK->modified(execution_space,datamask_modify); + else atomKK->modified(execution_space,F_MASK); + + x = atomKK->k_x.view(); + c_x = atomKK->k_x.view(); + f = atomKK->k_f.view(); + q = atomKK->k_q.view(); + type = atomKK->k_type.view(); + nlocal = atom->nlocal; + nall = atom->nlocal + atom->nghost; + special_lj[0] = force->special_lj[0]; + special_lj[1] = force->special_lj[1]; + special_lj[2] = force->special_lj[2]; + special_lj[3] = force->special_lj[3]; + special_coul[0] = force->special_coul[0]; + special_coul[1] = force->special_coul[1]; + special_coul[2] = force->special_coul[2]; + special_coul[3] = force->special_coul[3]; + qqrd2e = force->qqrd2e; + newton_pair = force->newton_pair; + + // loop over neighbors of my atoms + + // FIXME: taken from pair_lj_charmmfsw_coul_long, is it needed ??? + copymode = 1; + + //EV_FLOAT ev = pair_compute,void >(this,(NeighListKokkos*)list); + + EV_FLOAT ev; + if (ncoultablebits) + ev = pair_compute,CoulLongTable<1> > + (this,(NeighListKokkos*)list); + else + ev = pair_compute,CoulLongTable<0> > + (this,(NeighListKokkos*)list); + + if (eflag) { + eng_vdwl += ev.evdwl; + eng_coul += ev.ecoul; + } + + if (vflag_global) { + virial[0] += ev.v[0]; + virial[1] += ev.v[1]; + virial[2] += ev.v[2]; + virial[3] += ev.v[3]; + virial[4] += ev.v[4]; + virial[5] += ev.v[5]; + } + + if (eflag_atom) { + k_eatom.template modify(); + k_eatom.template sync(); + } + + if (vflag_atom) { + k_vatom.template modify(); + k_vatom.template sync(); + } + + if (vflag_fdotr) pair_virial_fdotr_compute(this); + +} + +/* ---------------------------------------------------------------------- + compute pair force between atoms i and j + ---------------------------------------------------------------------- */ + +template +template +KOKKOS_INLINE_FUNCTION +F_FLOAT PairLJSPICACoulLongKokkos:: +compute_fpair(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, const int& jtype) const { + (void) i; + (void) j; + const F_FLOAT r2inv = 1.0/rsq; + const int ljt = (STACKPARAMS?m_params[itype][jtype].lj_type:params(itype,jtype).lj_type); + + const F_FLOAT lj_1 = (STACKPARAMS?m_params[itype][jtype].lj1:params(itype,jtype).lj1); + const F_FLOAT lj_2 = (STACKPARAMS?m_params[itype][jtype].lj2:params(itype,jtype).lj2); + + /*if (ljt == LJ12_4) { + + const F_FLOAT r4inv=r2inv*r2inv; + return r4inv*(lj_1*r4inv*r4inv - lj_2) * r2inv; + + } else if (ljt == LJ9_6) { + + const F_FLOAT r3inv = r2inv*sqrt(r2inv); + const F_FLOAT r6inv = r3inv*r3inv; + return r6inv*(lj_1*r3inv - lj_2) * r2inv; + + } else if (ljt == LJ12_6) { + + const double r6inv = r2inv*r2inv*r2inv; + return r6inv*(lj_1*r6inv - lj_2) * r2inv; + + } else if (ljt == LJ12_5) { + + const F_FLOAT r5inv = r2inv*r2inv*sqrt(r2inv); + const F_FLOAT r7inv = r5inv*r2inv; + return r5inv*(lj_1*r7inv - lj_2) * r2inv; + + } + if (ljt!=LJ12_4 && ljt!=LJ9_6 && ljt!=LJ12_6 && ljt!=LJ12_5) return 0.0;*/ + const F_FLOAT r4inv=r2inv*r2inv; + const F_FLOAT r6inv=r2inv*r4inv; + const F_FLOAT a = ljt==LJ12_4?r4inv:(ljt==LJ12_5?r4inv*sqrt(r2inv):r6inv); + const F_FLOAT b = ljt==LJ12_4?r4inv:(ljt==LJ9_6?1.0/sqrt(r2inv):(ljt==LJ12_5?r2inv*sqrt(r2inv):r2inv)); + return a* ( lj_1*r6inv*b - lj_2 * r2inv); +} + + +/* ---------------------------------------------------------------------- + compute pair potential energy between atoms i and j + ---------------------------------------------------------------------- */ + +template +template +KOKKOS_INLINE_FUNCTION +F_FLOAT PairLJSPICACoulLongKokkos:: +compute_evdwl(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, const int& jtype) const { + (void) i; + (void) j; + const F_FLOAT r2inv = 1.0/rsq; + const int ljt = (STACKPARAMS?m_params[itype][jtype].lj_type:params(itype,jtype).lj_type); + + const F_FLOAT lj_3 = (STACKPARAMS?m_params[itype][jtype].lj3:params(itype,jtype).lj3); + const F_FLOAT lj_4 = (STACKPARAMS?m_params[itype][jtype].lj4:params(itype,jtype).lj4); + const F_FLOAT offset = (STACKPARAMS?m_params[itype][jtype].offset:params(itype,jtype).offset); + + if (ljt == LJ12_4) { + const F_FLOAT r4inv=r2inv*r2inv; + + return r4inv*(lj_3*r4inv*r4inv - lj_4) - offset; + + } else if (ljt == LJ9_6) { + const F_FLOAT r3inv = r2inv*sqrt(r2inv); + const F_FLOAT r6inv = r3inv*r3inv; + return r6inv*(lj_3*r3inv - lj_4) - offset; + + } else if (ljt == LJ12_6) { + const double r6inv = r2inv*r2inv*r2inv; + return r6inv*(lj_3*r6inv - lj_4) - offset; + + } else if (ljt == LJ12_5) { + const F_FLOAT r5inv = r2inv*r2inv*sqrt(r2inv); + const F_FLOAT r7inv = r5inv*r2inv; + return r5inv*(lj_3*r7inv - lj_4) - offset; + } else + return 0.0; +} + +/* ---------------------------------------------------------------------- + compute coulomb pair force between atoms i and j +------------------------------------------------------------------------- */ + +template +template +KOKKOS_INLINE_FUNCTION +F_FLOAT PairLJSPICACoulLongKokkos:: +compute_fcoul(const F_FLOAT& rsq, const int& /*i*/, const int&j, + const int& /*itype*/, const int& /*jtype*/, + const F_FLOAT& factor_coul, const F_FLOAT& qtmp) const { + +/* + + r2inv = 1.0 / rsq; + const int ljt = lj_type[itype][jtype]; + + if (rsq < cut_coulsq) { + if (!ncoultablebits || rsq <= tabinnersq) { + r = sqrt(rsq); + grij = g_ewald * r; + expm2 = exp(-grij * grij); + t = 1.0 / (1.0 + EWALD_P * grij); + erfc = t * (A1 + t * (A2 + t * (A3 + t * (A4 + t * A5)))) * expm2; + prefactor = qqrd2e * qtmp * q[j] / r; + forcecoul = prefactor * (erfc + EWALD_F * grij * expm2); + if (EFLAG) ecoul = prefactor * erfc; + if (factor_coul < 1.0) { + forcecoul -= (1.0 - factor_coul) * prefactor; + if (EFLAG) ecoul -= (1.0 - factor_coul) * prefactor; + } + } else { + union_int_float_t rsq_lookup; + rsq_lookup.f = rsq; + itable = rsq_lookup.i & ncoulmask; + itable >>= ncoulshiftbits; + fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; + table = ftable[itable] + fraction * dftable[itable]; + forcecoul = qtmp * q[j] * table; + if (EFLAG) ecoul = qtmp * q[j] * (etable[itable] + fraction * detable[itable]); + if (factor_coul < 1.0) { + table = ctable[itable] + fraction * dctable[itable]; + prefactor = qtmp * q[j] * table; + forcecoul -= (1.0 - factor_coul) * prefactor; + if (EFLAG) ecoul -= (1.0 - factor_coul) * prefactor; + } + } + } + +*/ + + + + if (Specialisation::DoTable && rsq > tabinnersq) { + union_int_float_t rsq_lookup; + rsq_lookup.f = rsq; + const int itable = (rsq_lookup.i & ncoulmask) >> ncoulshiftbits; + const F_FLOAT fraction = (rsq_lookup.f - d_rtable[itable]) * d_drtable[itable]; + const F_FLOAT table = d_ftable[itable] + fraction*d_dftable[itable]; + F_FLOAT forcecoul = qtmp*q[j] * table; + if (factor_coul < 1.0) { + const F_FLOAT table = d_ctable[itable] + fraction*d_dctable[itable]; + const F_FLOAT prefactor = qtmp*q[j] * table; + forcecoul -= (1.0-factor_coul)*prefactor; + } + return forcecoul/rsq; + } else { + const F_FLOAT r = sqrt(rsq); + const F_FLOAT grij = g_ewald * r; + const F_FLOAT expm2 = exp(-grij*grij); + const F_FLOAT t = 1.0 / (1.0 + EWALD_P*grij); + const F_FLOAT rinv = 1.0/r; + const F_FLOAT erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; + const F_FLOAT prefactor = qqrd2e * qtmp*q[j]*rinv; + F_FLOAT forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); + if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; + + return forcecoul*rinv*rinv; + } +} + + +/* ---------------------------------------------------------------------- + compute coulomb pair potential energy between atoms i and j +------------------------------------------------------------------------- */ + +template +template +KOKKOS_INLINE_FUNCTION +F_FLOAT PairLJSPICACoulLongKokkos:: +compute_ecoul(const F_FLOAT& rsq, const int& /*i*/, const int&j, + const int& /*itype*/, const int& /*jtype*/, const F_FLOAT& factor_coul, const F_FLOAT& qtmp) const { + if (Specialisation::DoTable && rsq > tabinnersq) { + union_int_float_t rsq_lookup; + rsq_lookup.f = rsq; + const int itable = (rsq_lookup.i & ncoulmask) >> ncoulshiftbits; + const F_FLOAT fraction = (rsq_lookup.f - d_rtable[itable]) * d_drtable[itable]; + const F_FLOAT table = d_etable[itable] + fraction*d_detable[itable]; + F_FLOAT ecoul = qtmp*q[j] * table; + if (factor_coul < 1.0) { + const F_FLOAT table = d_ctable[itable] + fraction*d_dctable[itable]; + const F_FLOAT prefactor = qtmp*q[j] * table; + ecoul -= (1.0-factor_coul)*prefactor; + } + return ecoul; + } else { + const F_FLOAT r = sqrt(rsq); + const F_FLOAT grij = g_ewald * r; + const F_FLOAT expm2 = exp(-grij*grij); + const F_FLOAT t = 1.0 / (1.0 + EWALD_P*grij); + const F_FLOAT erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; + const F_FLOAT prefactor = qqrd2e * qtmp*q[j]/r; + F_FLOAT ecoul = prefactor * erfc; + if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; + return ecoul; + } +} + + + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +template +void PairLJSPICACoulLongKokkos::allocate() +{ + PairLJSPICACoulLong::allocate(); + + int n = atom->ntypes; + //memory->destroy(cutsq); + //memory->destroy(cut_lj); + //memory->destroy(cut_ljsq); + memoryKK->create_kokkos(k_cutsq,cutsq,n+1,n+1,"pair:cutsq"); + memoryKK->create_kokkos(k_cut_lj,cut_lj,n+1,n+1,"pair:cut_lj"); + memoryKK->create_kokkos(k_cut_ljsq,cut_ljsq,n+1,n+1,"pair:cut_ljsq"); + d_cutsq = k_cutsq.template view(); + d_cut_lj = k_cut_lj.template view(); + d_cut_ljsq = k_cut_ljsq.template view(); + k_params = Kokkos::DualView("PairLJSPICACoulLong::params",n+1,n+1); + params = k_params.template view(); +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +template +void PairLJSPICACoulLongKokkos::settings(int narg, char **arg) +{ + if (narg > 2) error->all(FLERR,"Illegal pair_style command"); + + PairLJSPICACoulLong::settings(1,arg); +} + + +/* ---------------------------------------------------------------------- + init tables +------------------------------------------------------------------------- */ + +/* +template +void PairLJSPICACoulLongKokkos::init_tables(double cut_coul, double *cut_respa) +{ + Pair::init_tables(cut_coul,cut_respa); + + typedef typename ArrayTypes::t_ffloat_1d table_type; + typedef typename ArrayTypes::t_ffloat_1d host_table_type; + + int ntable = 1; + for (int i = 0; i < ncoultablebits; i++) ntable *= 2; + + + // Copy rtable and drtable + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + for (int i = 0; i < ntable; i++) { + h_table(i) = rtable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_rtable = d_table; + } + + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + for (int i = 0; i < ntable; i++) { + h_table(i) = drtable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_drtable = d_table; + } + + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + + // Copy ftable and dftable + for (int i = 0; i < ntable; i++) { + h_table(i) = ftable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_ftable = d_table; + } + + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + + for (int i = 0; i < ntable; i++) { + h_table(i) = dftable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_dftable = d_table; + } + + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + + // Copy ctable and dctable + for (int i = 0; i < ntable; i++) { + h_table(i) = ctable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_ctable = d_table; + } + + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + + for (int i = 0; i < ntable; i++) { + h_table(i) = dctable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_dctable = d_table; + } + + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + + // Copy etable and detable + for (int i = 0; i < ntable; i++) { + h_table(i) = etable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_etable = d_table; + } + + { + host_table_type h_table("HostTable",ntable); + table_type d_table("DeviceTable",ntable); + + for (int i = 0; i < ntable; i++) { + h_table(i) = detable[i]; + } + Kokkos::deep_copy(d_table,h_table); + d_detable = d_table; + } +} +*/ + + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +template +void PairLJSPICACoulLongKokkos::init_style() +{ + PairLJSPICACoulLong::init_style(); + + // error if rRESPA with inner levels + + if (update->whichflag == 1 && utils::strmatch(update->integrate_style,"^respa")) { + int respa = 0; + if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; + if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; + if (respa) + error->all(FLERR,"Cannot use Kokkos pair style with rRESPA inner/middle"); + } + + // adjust neighbor list request for KOKKOS + + neighflag = lmp->kokkos->neighflag; + auto request = neighbor->find_request(this); + request->set_kokkos_host(std::is_same_v && + !std::is_same_v); + request->set_kokkos_device(std::is_same_v); + if (neighflag == FULL) request->enable_full(); +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +template +double PairLJSPICACoulLongKokkos::init_one(int i, int j) +{ + double cutone = PairLJSPICACoulLong::init_one(i,j); + + k_params.h_view(i,j).lj1 = lj1[i][j]; + k_params.h_view(i,j).lj2 = lj2[i][j]; + k_params.h_view(i,j).lj3 = lj3[i][j]; + k_params.h_view(i,j).lj4 = lj4[i][j]; + k_params.h_view(i,j).offset = offset[i][j]; + k_params.h_view(i,j).cutsq = cutone*cutone; + k_params.h_view(i,j).cut_ljsq = cut_ljsq[i][j]; + k_params.h_view(i,j).cut_coulsq = cut_coulsq[i][j]; + k_params.h_view(i,j).lj_type = lj_type[i][j]; + k_params.h_view(j,i) = k_params.h_view(i,j); + if (i(); + k_params.template modify(); + + return cutone; +} + + + +namespace LAMMPS_NS { +template class PairLJSPICACoulLongKokkos; +#ifdef LMP_KOKKOS_GPU +template class PairLJSPICACoulLongKokkos; +#endif +} + diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h new file mode 100644 index 0000000000..8a57753bae --- /dev/null +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h @@ -0,0 +1,138 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS +// clang-format off +PairStyle(lj/spica/coul/long/kk,PairLJSPICACoulLongKokkos); +PairStyle(lj/spica/coul/long/kk/device,PairLJSPICACoulLongKokkos); +PairStyle(lj/spica/coul/long/kk/host,PairLJSPICACoulLongKokkos); +PairStyle(lj/sdk/coul/long/kk,PairLJSPICACoulLongKokkos); +PairStyle(lj/sdk/coul/long/kk/device,PairLJSPICACoulLongKokkos); +PairStyle(lj/sdk/coul/long/kk/host,PairLJSPICACoulLongKokkos); +// clang-format on +#else + +// clang-format off +#ifndef LMP_PAIR_LJ_SPICA_COUL_LONG_KOKKOS_H +#define LMP_PAIR_LJ_SPICA_COUL_LONG_KOKKOS_H + +#include "pair_kokkos.h" +#include "pair_lj_spica_coul_long.h" +#include "neigh_list_kokkos.h" + +namespace LAMMPS_NS { + +template +class PairLJSPICACoulLongKokkos : public PairLJSPICACoulLong { + public: + enum {EnabledNeighFlags=FULL|HALFTHREAD|HALF}; + enum {COUL_FLAG=1}; + typedef DeviceType device_type; + typedef ArrayTypes AT; + PairLJSPICACoulLongKokkos(class LAMMPS *); + ~PairLJSPICACoulLongKokkos() override; + + void compute(int, int) override; + + void settings(int, char **) override; + void init_tables(double cut_coul, double *cut_respa) override; + void init_style() override; + double init_one(int, int) override; + + struct params_lj{ + KOKKOS_INLINE_FUNCTION + params_lj() {cutsq=0;cut_lj=0;cut_ljsq=0;lj1=0;lj2=0;lj3=0;lj4=0;offset=0;lj_type=0;}; + KOKKOS_INLINE_FUNCTION + params_lj(int /*i*/) {cutsq=0;cut_lj=0;cut_ljsq=0;lj1=0;lj2=0;lj3=0;lj4=0;offset=0;lj_type=0;}; + F_FLOAT cutsq,cut_lj,cut_ljsq,lj1,lj2,lj3,lj4,offset; + int lj_type; + }; + + protected: + template + KOKKOS_INLINE_FUNCTION + F_FLOAT compute_fpair(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, const int& jtype) const; + + template + KOKKOS_INLINE_FUNCTION + F_FLOAT compute_evdwl(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, const int& jtype) const; + + //template + //KOKKOS_INLINE_FUNCTION + //F_FLOAT compute_ecoul(const F_FLOAT& /*rsq*/, const int& /*i*/, const int& /*j*/, + // const int& /*itype*/, const int& /*jtype*/) const { return 0; } + + template + KOKKOS_INLINE_FUNCTION + F_FLOAT compute_fcoul(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, + const int& jtype, const F_FLOAT& factor_coul, const F_FLOAT& qtmp) const; + + template + KOKKOS_INLINE_FUNCTION + F_FLOAT compute_ecoul(const F_FLOAT& rsq, const int& i, const int&j, + const int& itype, const int& jtype, const F_FLOAT& factor_coul, const F_FLOAT& qtmp) const; + + Kokkos::DualView k_params; + typename Kokkos::DualView::t_dev_const_um params; + params_lj m_params[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; // hardwired to space for 12 atom types + F_FLOAT m_cutsq[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; + F_FLOAT m_cut_lj[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; + F_FLOAT m_cut_ljsq[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; + typename AT::t_x_array_randomread x; + typename AT::t_x_array c_x; + typename AT::t_f_array f; + typename AT::t_int_1d_randomread type; + typename AT::t_float_1d_randomread q; + + DAT::tdual_efloat_1d k_eatom; + DAT::tdual_virial_array k_vatom; + typename AT::t_efloat_1d d_eatom; + typename AT::t_virial_array d_vatom; + + int newton_pair; + double special_lj[4]; + double special_coul[4]; + double qqrd2e; + + typename AT::tdual_ffloat_2d k_cutsq, k_cut_lj, k_cut_ljsq; + typename AT::t_ffloat_2d d_cutsq, d_cut_lj, d_cut_ljsq; + + typename AT::t_ffloat_1d_randomread + d_rtable, d_drtable, d_ftable, d_dftable, + d_ctable, d_dctable, d_etable, d_detable; + + int neighflag; + int nlocal,nall,eflag,vflag; + + void allocate() override; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend void pair_virial_fdotr_compute(PairLJSPICACoulLongKokkos*); +}; + +} + +#endif +#endif + From fc0b155de9829003c18ea6040e63f17f306a4a57 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 3 Jun 2024 15:04:24 -0600 Subject: [PATCH 088/385] Dam example, generalizing non-quintic kernels --- doc/src/Howto_rheo.rst | 4 + examples/rheo/balloon/in.rheo.balloon | 1 + examples/rheo/dam-break/in.rheo.dam.break | 45 ++++---- examples/rheo/ice-cubes/in.rheo.ice.cubes | 1 + examples/rheo/oxidation/in.rheo.oxidation | 2 +- examples/rheo/poiseuille/in.rheo.poiseuille | 4 +- .../rheo/taylor-green/in.rheo.taylor.green | 3 +- src/RHEO/compute_rheo_kernel.cpp | 100 ++++++++++++++++-- src/RHEO/compute_rheo_kernel.h | 3 + src/RHEO/compute_rheo_rho_sum.cpp | 2 +- src/RHEO/fix_rheo.cpp | 2 + src/RHEO/fix_rheo.h | 2 +- 12 files changed, 129 insertions(+), 40 deletions(-) diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index b09925d6ac..939754aa95 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -17,6 +17,10 @@ these calculations. Additional numerical details can be found in :ref:`(Palermo) ` and :ref:`(Clemmer) `. +Note, if you simply want to run a traditional SPH simulation, the SPH package +is likely better suited for your application. It has fewer advanced features +and therefore benefits from improved performance. + ---------- At the core of the package is :doc:`fix rheo ` which integrates diff --git a/examples/rheo/balloon/in.rheo.balloon b/examples/rheo/balloon/in.rheo.balloon index d24573b0fb..c82fa39df3 100644 --- a/examples/rheo/balloon/in.rheo.balloon +++ b/examples/rheo/balloon/in.rheo.balloon @@ -60,6 +60,7 @@ fix 1 all rheo ${cut} quintic 0 & fix 2 all rheo/viscosity * constant ${eta} fix 3 all rheo/pressure * linear fix 4 all wall/harmonic ylo EDGE 2.0 1.0 1.0 +fix 5 all enforce2d compute rho all rheo/property/atom rho compute phase all rheo/property/atom phase diff --git a/examples/rheo/dam-break/in.rheo.dam.break b/examples/rheo/dam-break/in.rheo.dam.break index b59b710451..870b3529b6 100644 --- a/examples/rheo/dam-break/in.rheo.dam.break +++ b/examples/rheo/dam-break/in.rheo.dam.break @@ -3,24 +3,24 @@ dimension 2 units lj atom_style rheo -boundary f f p +boundary f s p comm_modify vel yes newton off # ------ Create simulation box ------ # variable n equal 1.0 -variable cut equal 3.0 -variable dx equal 4.0 +variable cut equal 2.2 +variable dx equal 3.0 -region box block -1 200 -1 80 -0.1 0.1 units box -#region box block -1 100 -1 40 -0.1 0.1 units box +region box block -1 150 -1 80 -0.1 0.1 units box create_box 2 box lattice hex ${n} -region fluid block $(xlo+v_dx) $(xlo+44.0) $(ylo+v_dx) $(yhi-16.0) EDGE EDGE units box -#region fluid block $(xlo+v_dx) $(xlo+20.0) $(ylo+v_dx) $(yhi-10.0) EDGE EDGE units box -region walls block $(xlo+v_dx) $(xhi-v_dx) $(ylo+v_dx) $(yhi-v_dx) EDGE EDGE units box side out +region fluid block $(xlo+v_dx+1.0) $(xlo+40.0) $(ylo+v_dx+1.0) $(yhi-20.0) EDGE EDGE units box +region walls1 block $(xlo+v_dx) $(xhi-v_dx) $(ylo+v_dx) $(yhi-v_dx) EDGE EDGE side out units box +region walls2 block EDGE EDGE EDGE $(yhi-v_dx) EDGE EDGE side in units box +region walls intersect 2 walls1 walls2 create_atoms 1 region fluid create_atoms 2 region walls @@ -33,12 +33,13 @@ group rig type 2 variable rho0 equal 1.0 variable mp equal ${rho0}/${n} variable cs equal 1.0 -variable zeta equal 0.05 +variable zeta equal 0.1 variable dt_max equal 0.1*${cut}/${cs}/3 -variable eta equal 0.05 -variable Dr equal 0.05 +variable eta equal 0.1 +variable Dr equal 0.1 -mass * ${mp} +mass 1 ${mp} +mass 2 $(2*v_mp) set group all rheo/rho ${rho0} set group all rheo/status 0 @@ -46,36 +47,30 @@ set group rig rheo/status 1 timestep ${dt_max} -pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} +pair_style rheo ${cut} artificial/visc ${zeta} #rho/damp ${Dr} pair_coeff * * - # ------ Fixes & computes ------ # fix 1 all rheo ${cut} quintic 10 & - shift & surface/detection coordination 22 8 & - interface/reconstruct -#fix 1 all rheo ${cut} RK1 10 surface/detection coordination 36 10 interface/reconstruct shift + rho/sum fix 2 all rheo/viscosity * constant ${eta} fix 3 all rheo/pressure * linear -fix 4 all gravity 5e-4 vector 0 -1 0 +fix 4 all gravity 1e-3 vector 0 -1 0 fix 5 rig setforce 0.0 0.0 0.0 +fix 6 all enforce2d compute rho all rheo/property/atom rho -compute phase all rheo/property/atom phase compute p all rheo/property/atom pressure compute surf all rheo/property/atom surface compute sn all rheo/property/atom surface/n/x surface/n/y -compute vshift all rheo/property/atom shift/v/x shift/v/y - # ------ Output & Run ------ # -thermo 100 +thermo 20 thermo_style custom step time ke press -dump 1 all custom 20 atomDump id type x y vx vy fx fy c_rho c_phase c_surf c_p c_vshift[*] c_sn[*] +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho c_surf c_p c_sn[*] -#thermo 1 -run 300000 # 400000 +run 30000 diff --git a/examples/rheo/ice-cubes/in.rheo.ice.cubes b/examples/rheo/ice-cubes/in.rheo.ice.cubes index 12eb54c32e..b023a8bac9 100644 --- a/examples/rheo/ice-cubes/in.rheo.ice.cubes +++ b/examples/rheo/ice-cubes/in.rheo.ice.cubes @@ -64,6 +64,7 @@ fix 4 all rheo/thermal conductivity * constant ${kappa} & fix 5 all wall/region wall harmonic 1.0 1.0 1.0 fix 6 all gravity 5e-4 vector 0 -1 0 fix 7 all deposit 8 0 1000 37241459 mol my_mol region drop near 2.0 vy -0.02 -0.02 +fix 8 all enforce2d compute rho all rheo/property/atom rho compute phase all rheo/property/atom phase diff --git a/examples/rheo/oxidation/in.rheo.oxidation b/examples/rheo/oxidation/in.rheo.oxidation index 5c1456ad5a..d26b379adb 100644 --- a/examples/rheo/oxidation/in.rheo.oxidation +++ b/examples/rheo/oxidation/in.rheo.oxidation @@ -10,7 +10,6 @@ newton off region box block -60 60 0 80 -0.01 0.01 units box create_box 3 box bond/types 2 extra/bond/per/atom 20 extra/special/per/atom 50 - region lbar block -15 0 3 80 EDGE EDGE units box region rbar block 0 15 3 80 EDGE EDGE units box region bar union 2 lbar rbar @@ -83,6 +82,7 @@ fix 7 all gravity 5e-5 vector 0 -1 0 fix 8 floor setforce 0.0 0.0 0.0 fix 9 surf add/heat linear 1.1 0.05 fix 10 floor add/heat constant 0 overwrite yes # fix the temperature of the floor +fix 11 all enforce2d compute surf all rheo/property/atom surface compute rho all rheo/property/atom rho diff --git a/examples/rheo/poiseuille/in.rheo.poiseuille b/examples/rheo/poiseuille/in.rheo.poiseuille index ee8ad5523c..7c38c8a6e0 100644 --- a/examples/rheo/poiseuille/in.rheo.poiseuille +++ b/examples/rheo/poiseuille/in.rheo.poiseuille @@ -6,7 +6,6 @@ atom_style rheo boundary p p p comm_modify vel yes - # ------ Create simulation box ------ # variable n equal 1.0 @@ -53,7 +52,6 @@ timestep ${dt_max} pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} pair_coeff * * - # ------ Fixes & computes ------ # fix 1 all rheo ${cut} quintic 0 shift @@ -62,10 +60,10 @@ fix 2 all rheo/viscosity * constant ${eta} fix 3 all rheo/pressure * linear fix 4 rig setforce 0.0 0.0 0.0 fix 5 fluid addforce ${fext} 0.0 0.0 +fix 6 all enforce2d compute rho all rheo/property/atom rho - # ------ Output & Run ------ # thermo 200 diff --git a/examples/rheo/taylor-green/in.rheo.taylor.green b/examples/rheo/taylor-green/in.rheo.taylor.green index e386d8262c..4485387440 100644 --- a/examples/rheo/taylor-green/in.rheo.taylor.green +++ b/examples/rheo/taylor-green/in.rheo.taylor.green @@ -7,7 +7,6 @@ boundary p p p comm_modify vel yes newton off - # ------ Create simulation box ------ # variable n equal 1.0 @@ -47,12 +46,12 @@ timestep ${dt_max} pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} pair_coeff * * - # ------ Fixes & computes ------ # fix 1 all rheo ${cut} RK1 8 shift fix 2 all rheo/viscosity * constant ${eta} fix 3 all rheo/pressure * linear +fix 4 all enforce2d compute rho all rheo/property/atom rho diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index bd16a89b6a..d0f24850bd 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -25,6 +25,7 @@ #include "error.h" #include "fix_rheo.h" #include "force.h" +#include "math_const.h" #include "math_extra.h" #include "memory.h" #include "modify.h" @@ -43,6 +44,7 @@ using namespace LAMMPS_NS; using namespace RHEO_NS; +using namespace MathConst; using namespace MathExtra; static constexpr int DELTA = 2000; @@ -57,8 +59,7 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : kernel_style = utils::inumeric(FLERR,arg[3],false,lmp); - - if (kernel_style == QUINTIC) { + if (kernel_style == QUINTIC || kernel_style == WENDLANDC4) { correction_order = -1; } else if (kernel_style == RK0) { correction_order = 0; @@ -115,12 +116,22 @@ void ComputeRHEOKernel::init() hsqinv = hinv * hinv; - if (dim == 3) { - pre_w = 0.002652582384864922 * 27.0 * hsqinv * hinv; - pre_wp = pre_w * 3.0 * hinv; + if (kernel_style != WENDLANDC4) { + if (dim == 3) { + pre_w = 1.0 / (120.0 * MY_PI) * 27.0 * hsqinv * hinv; + pre_wp = pre_w * 3.0 * hinv; + } else { + pre_w = 7.0 / (478.0 * MY_PI) * 9 * hsqinv; + pre_wp = pre_w * 3.0 * hinv; + } } else { - pre_w = 0.004661441847879780 * 9 * hsqinv; - pre_wp = pre_w * 3.0 * hinv; + if (dim == 3) { + pre_w = 495.0 / (32.0 * MY_PI * hsq * h); + pre_wp = pre_w * hinv; + } else { + pre_w = 9.0 / (MY_PI * hsq); + pre_wp = pre_w * hinv; + } } nmax_store = atom->nmax; @@ -163,11 +174,27 @@ int ComputeRHEOKernel::check_corrections(int i) /* ---------------------------------------------------------------------- */ +double ComputeRHEOKernel::calc_w_self(int i, int j) +{ + double w; + if (kernel_style == WENDLANDC4) + w = calc_w_wendlandc4(i, j, 0.0, 0.0, 0.0, 0.0); + else + w = calc_w_quintic(i, j, 0.0, 0.0, 0.0, 0.0); + + return w; +} + +/* ---------------------------------------------------------------------- */ + double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double delz, double r) { double w; int corrections_i, corrections_j, corrections; + if (kernel_style == WENDLANDC4) + return calc_w_wendlandc4(i,j,delx,dely,delz,r); + if (kernel_style != QUINTIC) { corrections_i = check_corrections(i); corrections_j = check_corrections(j); @@ -191,6 +218,9 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double double wp; int corrections_i, corrections_j; + if (kernel_style == WENDLANDC4) + return calc_dw_wendlandc4(i,j,delx,dely,delz,r,dWij,dWji); + if (kernel_style != QUINTIC) { corrections_i = check_corrections(i); corrections_j = check_corrections(j); @@ -288,6 +318,62 @@ double ComputeRHEOKernel::calc_dw_quintic(int i, int j, double delx, double dely return wp; } +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_w_wendlandc4(int i, int j, double delx, double dely, double delz, double r) +{ + double w, tmp6, s; + s = r * hinv; + + if (s > 1.0) { + w = 0.0; + } else { + tmp6 = (1.0 - s) * (1.0 - s); + tmp6 *= tmp6 * tmp6; + w = tmp6 * (1.0 + 6.0 * s + 35.0 * THIRD * s * s); + } + + w *= pre_w; + + Wij = w; + Wji = w; + + return w; +} + +/* ---------------------------------------------------------------------- */ + +double ComputeRHEOKernel::calc_dw_wendlandc4(int i, int j, double delx, double dely, double delz, double r, double *dW1, double *dW2) +{ + double wp, tmp1, tmp5, tmp6, s, wprinv; + double *mass = atom->mass; + int *type = atom->type; + + s = r * hinv; + + if (s > 1.0) { + wp = 0.0; + } else { + tmp1 = 1.0 - s; + tmp5 = tmp1 * tmp1; + tmp5 = tmp5 * tmp5 * tmp1; + tmp6 = tmp5 * tmp1; + wp = tmp6 * (6.0 + 70.0 * THIRD * s); + wp -= 6 * tmp5 * (1.0 + 6.0 * s + 35.0 * THIRD * s * s); + } + + wp *= pre_wp; + wprinv = wp / r; + dW1[0] = delx * wprinv; + dW1[1] = dely * wprinv; + dW1[2] = delz * wprinv; + + dW2[0] = -delx * wprinv; + dW2[1] = -dely * wprinv; + dW2[2] = -delz * wprinv; + + return wp; +} /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index ed190c19ce..543e5d88c0 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -36,10 +36,13 @@ class ComputeRHEOKernel : public Compute { void unpack_forward_comm(int, int, double *) override; double memory_usage() override; void compute_coordination(); + double calc_w_self(int,int); double calc_w(int,int,double,double,double,double); double calc_dw(int,int,double,double,double,double); double calc_w_quintic(int,int,double,double,double,double); double calc_dw_quintic(int,int,double,double,double,double,double *,double *); + double calc_w_wendlandc4(int,int,double,double,double,double); + double calc_dw_wendlandc4(int,int,double,double,double,double,double *,double *); void grow_arrays(int); double dWij[3], dWji[3], Wij, Wji; diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp index c7270897a4..d7f432a03d 100644 --- a/src/RHEO/compute_rheo_rho_sum.cpp +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -94,7 +94,7 @@ void ComputeRHEORhoSum::compute_peratom() // initialize arrays, local with quintic self-contribution, ghosts are zeroed for (i = 0; i < nlocal; i++) { - w = compute_kernel->calc_w_quintic(i, i, 0.0, 0.0, 0.0, 0.0); + w = compute_kernel->calc_w_self(i, i); rho[i] = w * mass[type[i]]; } diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index cb2abfb938..c704677bec 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -90,6 +90,8 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : cut = h; if (strcmp(arg[4], "quintic") == 0) { kernel_style = QUINTIC; + } else if (strcmp(arg[4], "wendland/c4") == 0) { + kernel_style = WENDLANDC4; } else if (strcmp(arg[4], "RK0") == 0) { kernel_style = RK0; } else if (strcmp(arg[4], "RK1") == 0) { diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 0af9fa8d01..251f82a99a 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -72,7 +72,7 @@ class FixRHEO : public Fix { namespace RHEO_NS { - enum {QUINTIC, RK0, RK1, RK2}; + enum {QUINTIC, WENDLANDC4, RK0, RK1, RK2}; enum {COORDINATION, DIVR}; // Status variables From b1570fc855beba285a06e53999c7bd41da970944 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Mon, 3 Jun 2024 18:56:39 -0400 Subject: [PATCH 089/385] first draft angle_spica_kokkos based on angle_harmonic_kokkos --- src/KOKKOS/angle_spica_kokkos.cpp | 413 ++++++++++++++++++++++++++++++ src/KOKKOS/angle_spica_kokkos.h | 91 +++++++ 2 files changed, 504 insertions(+) create mode 100644 src/KOKKOS/angle_spica_kokkos.cpp create mode 100644 src/KOKKOS/angle_spica_kokkos.h diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp new file mode 100644 index 0000000000..d7be418326 --- /dev/null +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -0,0 +1,413 @@ +// 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Stan Moore (SNL) +------------------------------------------------------------------------- */ + +#include "angle_harmonic_kokkos.h" + +#include "atom_kokkos.h" +#include "atom_masks.h" +#include "comm.h" +#include "force.h" +#include "math_const.h" +#include "memory_kokkos.h" +#include "neighbor_kokkos.h" + +#include + +using namespace LAMMPS_NS; +using namespace MathConst; + +static constexpr double SMALL = 0.001; + +/* ---------------------------------------------------------------------- */ + +template +AngleHarmonicKokkos::AngleHarmonicKokkos(LAMMPS *lmp) : AngleHarmonic(lmp) +{ + atomKK = (AtomKokkos *) atom; + neighborKK = (NeighborKokkos *) neighbor; + execution_space = ExecutionSpaceFromDevice::space; + datamask_read = X_MASK | F_MASK | ENERGY_MASK | VIRIAL_MASK; + datamask_modify = F_MASK | ENERGY_MASK | VIRIAL_MASK; + + centroidstressflag = CENTROID_NOTAVAIL; +} + +/* ---------------------------------------------------------------------- */ + +template +AngleHarmonicKokkos::~AngleHarmonicKokkos() +{ + if (!copymode) { + memoryKK->destroy_kokkos(k_eatom,eatom); + memoryKK->destroy_kokkos(k_vatom,vatom); + } +} + +/* ---------------------------------------------------------------------- */ + +template +void AngleHarmonicKokkos::compute(int eflag_in, int vflag_in) +{ + eflag = eflag_in; + vflag = vflag_in; + + ev_init(eflag,vflag,0); + + // reallocate per-atom arrays if necessary + + if (eflag_atom) { + memoryKK->destroy_kokkos(k_eatom,eatom); + memoryKK->create_kokkos(k_eatom,eatom,maxeatom,"angle:eatom"); + d_eatom = k_eatom.template view(); + } + if (vflag_atom) { + memoryKK->destroy_kokkos(k_vatom,vatom); + memoryKK->create_kokkos(k_vatom,vatom,maxvatom,"angle:vatom"); + d_vatom = k_vatom.template view(); + } + + //atomKK->sync(execution_space,datamask_read); + k_k.template sync(); + k_theta0.template sync(); + // if (eflag || vflag) atomKK->modified(execution_space,datamask_modify); + // else atomKK->modified(execution_space,F_MASK); + + x = atomKK->k_x.template view(); + f = atomKK->k_f.template view(); + neighborKK->k_anglelist.template sync(); + anglelist = neighborKK->k_anglelist.template view(); + int nanglelist = neighborKK->nanglelist; + nlocal = atom->nlocal; + newton_bond = force->newton_bond; + + copymode = 1; + + // loop over neighbors of my atoms + + EV_FLOAT ev; + + if (evflag) { + if (newton_bond) { + Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nanglelist),*this,ev); + } else { + Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nanglelist),*this,ev); + } + } else { + if (newton_bond) { + Kokkos::parallel_for(Kokkos::RangePolicy >(0,nanglelist),*this); + } else { + Kokkos::parallel_for(Kokkos::RangePolicy >(0,nanglelist),*this); + } + } + + if (eflag_global) energy += ev.evdwl; + if (vflag_global) { + virial[0] += ev.v[0]; + virial[1] += ev.v[1]; + virial[2] += ev.v[2]; + virial[3] += ev.v[3]; + virial[4] += ev.v[4]; + virial[5] += ev.v[5]; + } + + if (eflag_atom) { + k_eatom.template modify(); + k_eatom.template sync(); + } + + if (vflag_atom) { + k_vatom.template modify(); + k_vatom.template sync(); + } + + copymode = 0; +} + +template +template +KOKKOS_INLINE_FUNCTION +void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute, const int &n, EV_FLOAT& ev) const { + + // The f array is atomic + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; + + const int i1 = anglelist(n,0); + const int i2 = anglelist(n,1); + const int i3 = anglelist(n,2); + const int type = anglelist(n,3); + + // 1st bond + + const F_FLOAT delx1 = x(i1,0) - x(i2,0); + const F_FLOAT dely1 = x(i1,1) - x(i2,1); + const F_FLOAT delz1 = x(i1,2) - x(i2,2); + + const F_FLOAT rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1; + const F_FLOAT r1 = sqrt(rsq1); + + // 2nd bond + + const F_FLOAT delx2 = x(i3,0) - x(i2,0); + const F_FLOAT dely2 = x(i3,1) - x(i2,1); + const F_FLOAT delz2 = x(i3,2) - x(i2,2); + + const F_FLOAT rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2; + const F_FLOAT r2 = sqrt(rsq2); + + // angle (cos and sin) + + F_FLOAT c = delx1*delx2 + dely1*dely2 + delz1*delz2; + c /= r1*r2; + + if (c > 1.0) c = 1.0; + if (c < -1.0) c = -1.0; + + F_FLOAT s = sqrt(1.0 - c*c); + if (s < SMALL) s = SMALL; + s = 1.0/s; + + // force & energy + + const F_FLOAT dtheta = acos(c) - d_theta0[type]; + const F_FLOAT tk = d_k[type] * dtheta; + + F_FLOAT eangle = 0.0; + if (eflag) eangle = tk*dtheta; + + const F_FLOAT a = -2.0 * tk * s; + const F_FLOAT a11 = a*c / rsq1; + const F_FLOAT a12 = -a / (r1*r2); + const F_FLOAT a22 = a*c / rsq2; + + F_FLOAT f1[3],f3[3]; + f1[0] = a11*delx1 + a12*delx2; + f1[1] = a11*dely1 + a12*dely2; + f1[2] = a11*delz1 + a12*delz2; + f3[0] = a22*delx2 + a12*delx1; + f3[1] = a22*dely2 + a12*dely1; + f3[2] = a22*delz2 + a12*delz1; + + // apply force to each of 3 atoms + + if (NEWTON_BOND || i1 < nlocal) { + a_f(i1,0) += f1[0]; + a_f(i1,1) += f1[1]; + a_f(i1,2) += f1[2]; + } + + if (NEWTON_BOND || i2 < nlocal) { + a_f(i2,0) -= f1[0] + f3[0]; + a_f(i2,1) -= f1[1] + f3[1]; + a_f(i2,2) -= f1[2] + f3[2]; + } + + if (NEWTON_BOND || i3 < nlocal) { + a_f(i3,0) += f3[0]; + a_f(i3,1) += f3[1]; + a_f(i3,2) += f3[2]; + } + + if (EVFLAG) ev_tally(ev,i1,i2,i3,eangle,f1,f3, + delx1,dely1,delz1,delx2,dely2,delz2); +} + +template +template +KOKKOS_INLINE_FUNCTION +void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute, const int &n) const { + EV_FLOAT ev; + this->template operator()(TagAngleHarmonicCompute(), n, ev); +} + +/* ---------------------------------------------------------------------- */ + +template +void AngleHarmonicKokkos::allocate() +{ + AngleHarmonic::allocate(); + + int n = atom->nangletypes; + k_k = typename ArrayTypes::tdual_ffloat_1d("AngleHarmonic::k",n+1); + k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleHarmonic::theta0",n+1); + + d_k = k_k.template view(); + d_theta0 = k_theta0.template view(); +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more types +------------------------------------------------------------------------- */ + +template +void AngleHarmonicKokkos::coeff(int narg, char **arg) +{ + AngleHarmonic::coeff(narg, arg); + + int n = atom->nangletypes; + for (int i = 1; i <= n; i++) { + k_k.h_view[i] = k[i]; + k_theta0.h_view[i] = theta0[i]; + } + + k_k.template modify(); + k_theta0.template modify(); +} + +/* ---------------------------------------------------------------------- + proc 0 reads coeffs from restart file, bcasts them +------------------------------------------------------------------------- */ + +template +void AngleHarmonicKokkos::read_restart(FILE *fp) +{ + AngleHarmonic::read_restart(fp); + + int n = atom->nangletypes; + for (int i = 1; i <= n; i++) { + k_k.h_view[i] = k[i]; + k_theta0.h_view[i] = theta0[i]; + } + + k_k.template modify(); + k_theta0.template modify(); +} + +/* ---------------------------------------------------------------------- + tally energy and virial into global and per-atom accumulators + virial = r1F1 + r2F2 + r3F3 = (r1-r2) F1 + (r3-r2) F3 = del1*f1 + del2*f3 +------------------------------------------------------------------------- */ + +template +//template +KOKKOS_INLINE_FUNCTION +void AngleHarmonicKokkos::ev_tally(EV_FLOAT &ev, const int i, const int j, const int k, + F_FLOAT &eangle, F_FLOAT *f1, F_FLOAT *f3, + const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, + const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const +{ + E_FLOAT eanglethird; + F_FLOAT v[6]; + + // The eatom and vatom arrays are atomic + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.template view(); + + if (eflag_either) { + if (eflag_global) { + if (newton_bond) ev.evdwl += eangle; + else { + eanglethird = THIRD*eangle; + + if (i < nlocal) ev.evdwl += eanglethird; + if (j < nlocal) ev.evdwl += eanglethird; + if (k < nlocal) ev.evdwl += eanglethird; + } + } + if (eflag_atom) { + eanglethird = THIRD*eangle; + + if (newton_bond || i < nlocal) v_eatom[i] += eanglethird; + if (newton_bond || j < nlocal) v_eatom[j] += eanglethird; + if (newton_bond || k < nlocal) v_eatom[k] += eanglethird; + } + } + + if (vflag_either) { + v[0] = delx1*f1[0] + delx2*f3[0]; + v[1] = dely1*f1[1] + dely2*f3[1]; + v[2] = delz1*f1[2] + delz2*f3[2]; + v[3] = delx1*f1[1] + delx2*f3[1]; + v[4] = delx1*f1[2] + delx2*f3[2]; + v[5] = dely1*f1[2] + dely2*f3[2]; + + if (vflag_global) { + if (newton_bond) { + ev.v[0] += v[0]; + ev.v[1] += v[1]; + ev.v[2] += v[2]; + ev.v[3] += v[3]; + ev.v[4] += v[4]; + ev.v[5] += v[5]; + } else { + if (i < nlocal) { + ev.v[0] += THIRD*v[0]; + ev.v[1] += THIRD*v[1]; + ev.v[2] += THIRD*v[2]; + ev.v[3] += THIRD*v[3]; + ev.v[4] += THIRD*v[4]; + ev.v[5] += THIRD*v[5]; + } + if (j < nlocal) { + ev.v[0] += THIRD*v[0]; + ev.v[1] += THIRD*v[1]; + ev.v[2] += THIRD*v[2]; + ev.v[3] += THIRD*v[3]; + ev.v[4] += THIRD*v[4]; + ev.v[5] += THIRD*v[5]; + } + if (k < nlocal) { + ev.v[0] += THIRD*v[0]; + + ev.v[1] += THIRD*v[1]; + ev.v[2] += THIRD*v[2]; + ev.v[3] += THIRD*v[3]; + ev.v[4] += THIRD*v[4]; + ev.v[5] += THIRD*v[5]; + } + } + } + + if (vflag_atom) { + if (newton_bond || i < nlocal) { + v_vatom(i,0) += THIRD*v[0]; + v_vatom(i,1) += THIRD*v[1]; + v_vatom(i,2) += THIRD*v[2]; + v_vatom(i,3) += THIRD*v[3]; + v_vatom(i,4) += THIRD*v[4]; + v_vatom(i,5) += THIRD*v[5]; + } + if (newton_bond || j < nlocal) { + v_vatom(j,0) += THIRD*v[0]; + v_vatom(j,1) += THIRD*v[1]; + v_vatom(j,2) += THIRD*v[2]; + v_vatom(j,3) += THIRD*v[3]; + v_vatom(j,4) += THIRD*v[4]; + v_vatom(j,5) += THIRD*v[5]; + } + if (newton_bond || k < nlocal) { + v_vatom(k,0) += THIRD*v[0]; + v_vatom(k,1) += THIRD*v[1]; + v_vatom(k,2) += THIRD*v[2]; + v_vatom(k,3) += THIRD*v[3]; + v_vatom(k,4) += THIRD*v[4]; + v_vatom(k,5) += THIRD*v[5]; + + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +namespace LAMMPS_NS { +template class AngleHarmonicKokkos; +#ifdef LMP_KOKKOS_GPU +template class AngleHarmonicKokkos; +#endif +} + diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h new file mode 100644 index 0000000000..c12bba78e0 --- /dev/null +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -0,0 +1,91 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef ANGLE_CLASS +// clang-format off +AngleStyle(spica/kk,AngleHarmonicKokkos); +AngleStyle(spica/kk/device,AngleHarmonicKokkos); +AngleStyle(spica/kk/host,AngleHarmonicKokkos); +// clang-format on +#else + +// clang-format off +#ifndef LMP_ANGLE_SPICA_KOKKOS_H +#define LMP_ANGLE_SPICA_KOKKOS_H + +#include "angle_spica.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +template +struct TagAngleSPICACompute{}; + +template +class AngleSPICAKokkos : public AngleSPICA { + + public: + typedef DeviceType device_type; + typedef EV_FLOAT value_type; + + AngleSPICAKokkos(class LAMMPS *); + ~AngleSPICAKokkos() override; + void compute(int, int) override; + void coeff(int, char **) override; + void read_restart(FILE *) override; + + template + KOKKOS_INLINE_FUNCTION + void operator()(TagAngleSPICACompute, const int&, EV_FLOAT&) const; + + template + KOKKOS_INLINE_FUNCTION + void operator()(TagAngleSPICACompute, const int&) const; + + //template + KOKKOS_INLINE_FUNCTION + void ev_tally(EV_FLOAT &ev, const int i, const int j, const int k, + F_FLOAT &eangle, F_FLOAT *f1, F_FLOAT *f3, + const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, + const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const; + + protected: + + class NeighborKokkos *neighborKK; + + typename ArrayTypes::t_x_array_randomread x; + typename ArrayTypes::t_f_array f; + typename ArrayTypes::t_int_2d anglelist; + + typename ArrayTypes::tdual_efloat_1d k_eatom; + typename ArrayTypes::tdual_virial_array k_vatom; + typename ArrayTypes::t_efloat_1d d_eatom; + typename ArrayTypes::t_virial_array d_vatom; + + int nlocal,newton_bond; + int eflag,vflag; + + typename ArrayTypes::tdual_ffloat_1d k_k; + typename ArrayTypes::tdual_ffloat_1d k_theta0; + + typename ArrayTypes::t_ffloat_1d d_k; + typename ArrayTypes::t_ffloat_1d d_theta0; + + void allocate(); +}; + +} + +#endif +#endif + From cd04de58dc93779ac0fca64c003286d59e9c2945 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Mon, 3 Jun 2024 19:07:58 -0400 Subject: [PATCH 090/385] pair_lj_spica_coul_long fixes, now passes unit test --- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 38 ++++++----- src/KOKKOS/pair_lj_spica_coul_long_kokkos.h | 66 ++++++++++++------- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp index e0d6542418..37cbe7d17f 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -16,7 +16,7 @@ #include "atom_kokkos.h" #include "atom_masks.h" -//#include "comm.h" +#include "comm.h" #include "error.h" #include "ewald_const.h" #include "force.h" @@ -35,8 +35,6 @@ using namespace LAMMPS_NS; using namespace LJSPICAParms; - -// FIXME: using namespace EwaldConst; /* ---------------------------------------------------------------------- */ @@ -299,11 +297,8 @@ compute_fcoul(const F_FLOAT& rsq, const int& /*i*/, const int&j, } } } - */ - - if (Specialisation::DoTable && rsq > tabinnersq) { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; @@ -330,6 +325,8 @@ compute_fcoul(const F_FLOAT& rsq, const int& /*i*/, const int&j, return forcecoul*rinv*rinv; } + + } @@ -381,16 +378,16 @@ void PairLJSPICACoulLongKokkos::allocate() PairLJSPICACoulLong::allocate(); int n = atom->ntypes; - //memory->destroy(cutsq); - //memory->destroy(cut_lj); - //memory->destroy(cut_ljsq); + + memory->destroy(cutsq); memoryKK->create_kokkos(k_cutsq,cutsq,n+1,n+1,"pair:cutsq"); - memoryKK->create_kokkos(k_cut_lj,cut_lj,n+1,n+1,"pair:cut_lj"); - memoryKK->create_kokkos(k_cut_ljsq,cut_ljsq,n+1,n+1,"pair:cut_ljsq"); d_cutsq = k_cutsq.template view(); - d_cut_lj = k_cut_lj.template view(); - d_cut_ljsq = k_cut_ljsq.template view(); - k_params = Kokkos::DualView("PairLJSPICACoulLong::params",n+1,n+1); + + d_cut_lj = typename AT::t_ffloat_2d("pair:cut_lj",n+1,n+1); + d_cut_ljsq = typename AT::t_ffloat_2d("pair:cut_ljsq",n+1,n+1); + d_cut_coulsq = typename AT::t_ffloat_2d("pair:cut_coulsq",n+1,n+1); + + k_params = Kokkos::DualView("PairLJSPICACoulLong::params",n+1,n+1); params = k_params.template view(); } @@ -411,7 +408,7 @@ void PairLJSPICACoulLongKokkos::settings(int narg, char **arg) init tables ------------------------------------------------------------------------- */ -/* + template void PairLJSPICACoulLongKokkos::init_tables(double cut_coul, double *cut_respa) { @@ -514,7 +511,7 @@ void PairLJSPICACoulLongKokkos::init_tables(double cut_coul, double d_detable = d_table; } } -*/ + /* ---------------------------------------------------------------------- @@ -526,6 +523,9 @@ void PairLJSPICACoulLongKokkos::init_style() { PairLJSPICACoulLong::init_style(); + //Kokkos::deep_copy(d_cut_ljsq,cut_ljsq); + //Kokkos::deep_copy(d_cut_coulsq,cut_coulsq); + // error if rRESPA with inner levels if (update->whichflag == 1 && utils::strmatch(update->integrate_style,"^respa")) { @@ -561,15 +561,17 @@ double PairLJSPICACoulLongKokkos::init_one(int i, int j) k_params.h_view(i,j).lj4 = lj4[i][j]; k_params.h_view(i,j).offset = offset[i][j]; k_params.h_view(i,j).cutsq = cutone*cutone; + k_params.h_view(i,j).cut_lj = cut_lj[i][j]; k_params.h_view(i,j).cut_ljsq = cut_ljsq[i][j]; - k_params.h_view(i,j).cut_coulsq = cut_coulsq[i][j]; + k_params.h_view(i,j).cut_coulsq = cut_coulsq; k_params.h_view(i,j).lj_type = lj_type[i][j]; k_params.h_view(j,i) = k_params.h_view(i,j); if (i k_params; - typename Kokkos::DualView::t_dev_const_um params; - params_lj m_params[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; // hardwired to space for 12 atom types + Kokkos::DualView k_params; + typename Kokkos::DualView::t_dev_const_um params; + params_lj_coul m_params[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; // hardwired to space for 12 atom types F_FLOAT m_cutsq[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; F_FLOAT m_cut_lj[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; F_FLOAT m_cut_ljsq[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; + F_FLOAT m_cut_coulsq[MAX_TYPES_STACKPARAMS+1][MAX_TYPES_STACKPARAMS+1]; typename AT::t_x_array_randomread x; typename AT::t_x_array c_x; typename AT::t_f_array f; @@ -100,12 +101,9 @@ class PairLJSPICACoulLongKokkos : public PairLJSPICACoulLong { typename AT::t_virial_array d_vatom; int newton_pair; - double special_lj[4]; - double special_coul[4]; - double qqrd2e; typename AT::tdual_ffloat_2d k_cutsq, k_cut_lj, k_cut_ljsq; - typename AT::t_ffloat_2d d_cutsq, d_cut_lj, d_cut_ljsq; + typename AT::t_ffloat_2d d_cutsq, d_cut_lj, d_cut_ljsq, d_cut_coulsq; typename AT::t_ffloat_1d_randomread d_rtable, d_drtable, d_ftable, d_dftable, @@ -114,20 +112,40 @@ class PairLJSPICACoulLongKokkos : public PairLJSPICACoulLong { int neighflag; int nlocal,nall,eflag,vflag; + double special_lj[4]; + double special_coul[4]; + double qqrd2e; + void allocate() override; - friend struct PairComputeFunctor; - friend struct PairComputeFunctor; - friend struct PairComputeFunctor; - friend struct PairComputeFunctor; - friend struct PairComputeFunctor; - friend struct PairComputeFunctor; - friend struct PairComputeFunctor; - friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJSPICACoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); + + friend void pair_virial_fdotr_compute(PairLJSPICACoulLongKokkos*); }; From e42c2b7bb51daf449b5e741ab775d72a49f4ced8 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Mon, 3 Jun 2024 19:21:15 -0400 Subject: [PATCH 091/385] more fixes --- src/CG-SPICA/pair_lj_spica_coul_long.cpp | 5 ++++- src/CG-SPICA/pair_lj_spica_coul_long.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CG-SPICA/pair_lj_spica_coul_long.cpp b/src/CG-SPICA/pair_lj_spica_coul_long.cpp index 9e0d4dc276..ed6cb17e7c 100644 --- a/src/CG-SPICA/pair_lj_spica_coul_long.cpp +++ b/src/CG-SPICA/pair_lj_spica_coul_long.cpp @@ -55,6 +55,8 @@ PairLJSPICACoulLong::PairLJSPICACoulLong(LAMMPS *lmp) : PairLJSPICACoulLong::~PairLJSPICACoulLong() { + if (copymode) return; + if (allocated) { memory->destroy(setflag); memory->destroy(lj_type); @@ -385,7 +387,8 @@ double PairLJSPICACoulLong::init_one(int i, int j) const int ljt = lj_type[i][j]; - if (ljt == LJ_NOT_SET) error->all(FLERR, "unrecognized LJ parameter flag"); + if (ljt == LJ_NOT_SET) + error->all(FLERR,"unrecognized LJ parameter flag"); double cut = MAX(cut_lj[i][j], cut_coul); cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; diff --git a/src/CG-SPICA/pair_lj_spica_coul_long.h b/src/CG-SPICA/pair_lj_spica_coul_long.h index e6ef5ea539..48b2aaa37f 100644 --- a/src/CG-SPICA/pair_lj_spica_coul_long.h +++ b/src/CG-SPICA/pair_lj_spica_coul_long.h @@ -64,7 +64,7 @@ class PairLJSPICACoulLong : public Pair { double cut_lj_global; double g_ewald; - void allocate(); + virtual void allocate(); private: template void eval(); From 657befa9599e6fb521205d268d154cfb1e8f6923 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 20:24:33 -0400 Subject: [PATCH 092/385] second version angle_spica_kokkos and added kokkos_omp test to test_angle_style --- src/KOKKOS/angle_spica_kokkos.cpp | 107 ++++++++++++++---- src/KOKKOS/angle_spica_kokkos.h | 6 +- unittest/force-styles/test_angle_style.cpp | 120 +++++++++++++++++++++ 3 files changed, 209 insertions(+), 24 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index d7be418326..28e909eb82 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -13,10 +13,10 @@ ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- - Contributing author: Stan Moore (SNL) + Contributing author: Mitch Murphy (alphataubio@gmail.com) ------------------------------------------------------------------------- */ -#include "angle_harmonic_kokkos.h" +#include "angle_spica_kokkos.h" #include "atom_kokkos.h" #include "atom_masks.h" @@ -36,7 +36,7 @@ static constexpr double SMALL = 0.001; /* ---------------------------------------------------------------------- */ template -AngleHarmonicKokkos::AngleHarmonicKokkos(LAMMPS *lmp) : AngleHarmonic(lmp) +AngleSPICAKokkos::AngleSPICAKokkos(LAMMPS *lmp) : AngleHarmonic(lmp) { atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; @@ -50,7 +50,7 @@ AngleHarmonicKokkos::AngleHarmonicKokkos(LAMMPS *lmp) : AngleHarmoni /* ---------------------------------------------------------------------- */ template -AngleHarmonicKokkos::~AngleHarmonicKokkos() +AngleSPICAKokkos::~AngleSPICAKokkos() { if (!copymode) { memoryKK->destroy_kokkos(k_eatom,eatom); @@ -61,7 +61,7 @@ AngleHarmonicKokkos::~AngleHarmonicKokkos() /* ---------------------------------------------------------------------- */ template -void AngleHarmonicKokkos::compute(int eflag_in, int vflag_in) +void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) { eflag = eflag_in; vflag = vflag_in; @@ -141,7 +141,7 @@ void AngleHarmonicKokkos::compute(int eflag_in, int vflag_in) template template KOKKOS_INLINE_FUNCTION -void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute, const int &n, EV_FLOAT& ev) const { +void AngleSPICAKokkos::operator()(TagAngleHarmonicCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; @@ -180,6 +180,67 @@ void AngleHarmonicKokkos::operator()(TagAngleHarmonicComputetype[i1]; + const int type3 = atom->type[i3]; + + f13=0.0; + e13=0.0; + + if (rsq3 < rminsq[type1][type3]) { + const int ljt = lj_type[type1][type3]; + const double r2inv = 1.0/rsq3; + + if (ljt == LJ12_4) { + const double r4inv=r2inv*r2inv; + + f13 = r4inv*(lj1[type1][type3]*r4inv*r4inv - lj2[type1][type3]); + if (eflag) e13 = r4inv*(lj3[type1][type3]*r4inv*r4inv - lj4[type1][type3]); + + } else if (ljt == LJ9_6) { + const double r3inv = r2inv*sqrt(r2inv); + const double r6inv = r3inv*r3inv; + + f13 = r6inv*(lj1[type1][type3]*r3inv - lj2[type1][type3]); + if (eflag) e13 = r6inv*(lj3[type1][type3]*r3inv - lj4[type1][type3]); + + } else if (ljt == LJ12_6) { + const double r6inv = r2inv*r2inv*r2inv; + + f13 = r6inv*(lj1[type1][type3]*r6inv - lj2[type1][type3]); + if (eflag) e13 = r6inv*(lj3[type1][type3]*r6inv - lj4[type1][type3]); + + } else if (ljt == LJ12_5) { + const double r5inv = r2inv*r2inv*sqrt(r2inv); + const double r7inv = r5inv*r2inv; + + f13 = r5inv*(lj1[type1][type3]*r7inv - lj2[type1][type3]); + if (eflag) e13 = r5inv*(lj3[type1][type3]*r7inv - lj4[type1][type3]); + } + + // make sure energy is 0.0 at the cutoff. + if (eflag) e13 -= emin[type1][type3]; + + f13 *= r2inv; + } + } + // force & energy @@ -205,9 +266,9 @@ void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute::operator()(TagAngleHarmonicCompute template KOKKOS_INLINE_FUNCTION -void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute, const int &n) const { +void AngleSPICAKokkos::operator()(TagAngleHarmonicCompute, const int &n) const { EV_FLOAT ev; this->template operator()(TagAngleHarmonicCompute(), n, ev); } @@ -237,7 +302,7 @@ void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute -void AngleHarmonicKokkos::allocate() +void AngleSPICAKokkos::allocate() { AngleHarmonic::allocate(); @@ -254,7 +319,7 @@ void AngleHarmonicKokkos::allocate() ------------------------------------------------------------------------- */ template -void AngleHarmonicKokkos::coeff(int narg, char **arg) +void AngleSPICAKokkos::coeff(int narg, char **arg) { AngleHarmonic::coeff(narg, arg); @@ -273,7 +338,7 @@ void AngleHarmonicKokkos::coeff(int narg, char **arg) ------------------------------------------------------------------------- */ template -void AngleHarmonicKokkos::read_restart(FILE *fp) +void AngleSPICAKokkos::read_restart(FILE *fp) { AngleHarmonic::read_restart(fp); @@ -295,7 +360,7 @@ void AngleHarmonicKokkos::read_restart(FILE *fp) template //template KOKKOS_INLINE_FUNCTION -void AngleHarmonicKokkos::ev_tally(EV_FLOAT &ev, const int i, const int j, const int k, +void AngleSPICAKokkos::ev_tally(EV_FLOAT &ev, const int i, const int j, const int k, F_FLOAT &eangle, F_FLOAT *f1, F_FLOAT *f3, const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const @@ -405,9 +470,9 @@ void AngleHarmonicKokkos::ev_tally(EV_FLOAT &ev, const int i, const /* ---------------------------------------------------------------------- */ namespace LAMMPS_NS { -template class AngleHarmonicKokkos; +template class AngleSPICAKokkos; #ifdef LMP_KOKKOS_GPU -template class AngleHarmonicKokkos; +template class AngleSPICAKokkos; #endif } diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index c12bba78e0..925777b014 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -13,9 +13,9 @@ #ifdef ANGLE_CLASS // clang-format off -AngleStyle(spica/kk,AngleHarmonicKokkos); -AngleStyle(spica/kk/device,AngleHarmonicKokkos); -AngleStyle(spica/kk/host,AngleHarmonicKokkos); +AngleStyle(spica/kk,AngleSPICAKokkos); +AngleStyle(spica/kk/device,AngleSPICAKokkos); +AngleStyle(spica/kk/host,AngleSPICAKokkos); // clang-format on #else diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index 010fabd6e2..ec4e6541c2 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -529,6 +529,126 @@ TEST(AngleStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; +TEST(AngleStyle, kokkos_omp) +{ + if (!LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); + if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); + if (!Info::has_accelerator_feature("KOKKOS", "api", "openmp")) GTEST_SKIP(); + + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite", + "-k", "on", "t", "4", "-sf", "kk"}; + + ::testing::internal::CaptureStdout(); + LAMMPS *lmp = init_lammps(args, test_config, true); + + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + + if (!lmp) { + std::cerr << "One or more prerequisite styles with /kk suffix\n" + "are not available in this LAMMPS configuration:\n"; + for (auto &prerequisite : test_config.prerequisites) { + std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; + } + GTEST_SKIP(); + } + + EXPECT_THAT(output, StartsWith("LAMMPS (")); + EXPECT_THAT(output, HasSubstr("Loop time")); + + // abort if running in parallel and not all atoms are local + const int nlocal = lmp->atom->nlocal; + ASSERT_EQ(lmp->atom->natoms, nlocal); + + // relax error a bit for KOKKOS package + double epsilon = 5.0 * test_config.epsilon; + + ErrorStats stats; + auto angle = lmp->force->angle; + + EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton on)", angle->virial, test_config.init_stress, epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton on)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton on)", angle->virial, test_config.run_stress, epsilon); + + stats.reset(); + int id = lmp->modify->find_compute("sum"); + double energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.run_energy, epsilon); + EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); + if (print_stats) std::cerr << "run_energy stats, newton on: " << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + lmp = init_lammps(args, test_config, false); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + // skip over these tests if newton bond is forced to be on + if (lmp->force->newton_bond == 0) { + angle = lmp->force->angle; + + EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("init_stress (newton off)", angle->virial, test_config.init_stress, + 2 * epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "init_energy stats, newton off:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + run_lammps(lmp); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + EXPECT_FORCES("run_forces (newton off)", lmp->atom, test_config.run_forces, 10 * epsilon); + EXPECT_STRESS("run_stress (newton off)", angle->virial, test_config.run_stress, epsilon); + + stats.reset(); + id = lmp->modify->find_compute("sum"); + energy = lmp->modify->compute[id]->compute_scalar(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.run_energy, epsilon); + EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); + if (print_stats) std::cerr << "run_energy stats, newton off:" << stats << std::endl; + } + + if (!verbose) ::testing::internal::CaptureStdout(); + restart_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + angle = lmp->force->angle; + EXPECT_FORCES("restart_forces", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("restart_stress", angle->virial, test_config.init_stress, epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "restart_energy stats:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + data_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + angle = lmp->force->angle; + EXPECT_FORCES("data_forces", lmp->atom, test_config.init_forces, epsilon); + EXPECT_STRESS("data_stress", angle->virial, test_config.init_stress, epsilon); + + stats.reset(); + EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); + if (print_stats) std::cerr << "data_energy stats:" << stats << std::endl; + + if (!verbose) ::testing::internal::CaptureStdout(); + cleanup_lammps(lmp, test_config); + if (!verbose) ::testing::internal::GetCapturedStdout(); +}; + + TEST(AngleStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP(); From 6bbd3be1a90eeca969a905a85630d9dc02ccffa2 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 20:45:47 -0400 Subject: [PATCH 093/385] fixes --- src/KOKKOS/angle_spica_kokkos.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 28e909eb82..fbe5f75385 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -36,7 +36,7 @@ static constexpr double SMALL = 0.001; /* ---------------------------------------------------------------------- */ template -AngleSPICAKokkos::AngleSPICAKokkos(LAMMPS *lmp) : AngleHarmonic(lmp) +AngleSPICAKokkos::AngleSPICAKokkos(LAMMPS *lmp) : AngleSPICA(lmp) { atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; @@ -103,15 +103,15 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) if (evflag) { if (newton_bond) { - Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nanglelist),*this,ev); + Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nanglelist),*this,ev); } else { - Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nanglelist),*this,ev); + Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nanglelist),*this,ev); } } else { if (newton_bond) { - Kokkos::parallel_for(Kokkos::RangePolicy >(0,nanglelist),*this); + Kokkos::parallel_for(Kokkos::RangePolicy >(0,nanglelist),*this); } else { - Kokkos::parallel_for(Kokkos::RangePolicy >(0,nanglelist),*this); + Kokkos::parallel_for(Kokkos::RangePolicy >(0,nanglelist),*this); } } @@ -141,7 +141,7 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) template template KOKKOS_INLINE_FUNCTION -void AngleSPICAKokkos::operator()(TagAngleHarmonicCompute, const int &n, EV_FLOAT& ev) const { +void AngleSPICAKokkos::operator()(TagAngleSPICACompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; @@ -294,9 +294,9 @@ void AngleSPICAKokkos::operator()(TagAngleHarmonicCompute template KOKKOS_INLINE_FUNCTION -void AngleSPICAKokkos::operator()(TagAngleHarmonicCompute, const int &n) const { +void AngleSPICAKokkos::operator()(TagAngleSPICACompute, const int &n) const { EV_FLOAT ev; - this->template operator()(TagAngleHarmonicCompute(), n, ev); + this->template operator()(TagAngleSPICACompute(), n, ev); } /* ---------------------------------------------------------------------- */ @@ -304,11 +304,11 @@ void AngleSPICAKokkos::operator()(TagAngleHarmonicCompute void AngleSPICAKokkos::allocate() { - AngleHarmonic::allocate(); + AngleSPICA::allocate(); int n = atom->nangletypes; - k_k = typename ArrayTypes::tdual_ffloat_1d("AngleHarmonic::k",n+1); - k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleHarmonic::theta0",n+1); + k_k = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::k",n+1); + k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",n+1); d_k = k_k.template view(); d_theta0 = k_theta0.template view(); @@ -321,7 +321,7 @@ void AngleSPICAKokkos::allocate() template void AngleSPICAKokkos::coeff(int narg, char **arg) { - AngleHarmonic::coeff(narg, arg); + AngleSPICA::coeff(narg, arg); int n = atom->nangletypes; for (int i = 1; i <= n; i++) { @@ -340,7 +340,7 @@ void AngleSPICAKokkos::coeff(int narg, char **arg) template void AngleSPICAKokkos::read_restart(FILE *fp) { - AngleHarmonic::read_restart(fp); + AngleSPICA::read_restart(fp); int n = atom->nangletypes; for (int i = 1; i <= n; i++) { From e2a819e399fa655fee693a9d652553bef35b87f3 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 20:53:41 -0400 Subject: [PATCH 094/385] fixes --- src/KOKKOS/angle_spica_kokkos.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index fbe5f75385..9116dafe1d 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -192,9 +192,9 @@ void AngleSPICAKokkos::operator()(TagAngleSPICAComputetype[i1]; @@ -286,8 +286,8 @@ void AngleSPICAKokkos::operator()(TagAngleSPICACompute Date: Tue, 4 Jun 2024 20:58:42 -0400 Subject: [PATCH 095/385] fixes --- src/KOKKOS/angle_spica_kokkos.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 9116dafe1d..67c1c7b628 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -26,10 +26,13 @@ #include "memory_kokkos.h" #include "neighbor_kokkos.h" +#include "lj_spica_common.h" + #include using namespace LAMMPS_NS; using namespace MathConst; +using namespace LJSPICAParms; static constexpr double SMALL = 0.001; From 42a3c754ec90182c25961bdd1431b7ccfd568cfe Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 21:26:58 -0400 Subject: [PATCH 096/385] fixes --- unittest/force-styles/test_angle_style.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index ec4e6541c2..422253defe 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -138,8 +138,10 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton } command("run 0 post no"); + command("variable write_data_pair index ii"); command("write_restart " + cfg.basename + ".restart"); command("write_data " + cfg.basename + ".data"); + command("write_data " + cfg.basename + ".data pair ${write_data_pair}"); command("write_coeff " + cfg.basename + "-coeffs.in"); return lmp; From 261f0e0bb4ebc0d6ed68df813a627181df0eab43 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 21:29:44 -0400 Subject: [PATCH 097/385] Update test_angle_style.cpp --- unittest/force-styles/test_angle_style.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index 422253defe..dbf175c801 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -140,7 +140,6 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("run 0 post no"); command("variable write_data_pair index ii"); command("write_restart " + cfg.basename + ".restart"); - command("write_data " + cfg.basename + ".data"); command("write_data " + cfg.basename + ".data pair ${write_data_pair}"); command("write_coeff " + cfg.basename + "-coeffs.in"); From a093ddf3fdde4a117cbdf260966ce28765263253 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 22:20:27 -0400 Subject: [PATCH 098/385] fixes --- src/KOKKOS/angle_spica_kokkos.cpp | 8 +++++++- src/KOKKOS/angle_spica_kokkos.h | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 67c1c7b628..5d2813545b 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -312,9 +312,11 @@ void AngleSPICAKokkos::allocate() int n = atom->nangletypes; k_k = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::k",n+1); k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",n+1); - + k_repscale = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::repscale",n+1); + d_k = k_k.template view(); d_theta0 = k_theta0.template view(); + d_repscale = k_repscale.template view(); } /* ---------------------------------------------------------------------- @@ -330,10 +332,12 @@ void AngleSPICAKokkos::coeff(int narg, char **arg) for (int i = 1; i <= n; i++) { k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; + k_repscale.h_view[i] = repscale[i]; } k_k.template modify(); k_theta0.template modify(); + k_repscale.template modify(); } /* ---------------------------------------------------------------------- @@ -349,10 +353,12 @@ void AngleSPICAKokkos::read_restart(FILE *fp) for (int i = 1; i <= n; i++) { k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; + k_repscale.h_view[i] = repscale[i]; } k_k.template modify(); k_theta0.template modify(); + k_repscale.template modify(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index 925777b014..da1264551e 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -77,10 +77,12 @@ class AngleSPICAKokkos : public AngleSPICA { typename ArrayTypes::tdual_ffloat_1d k_k; typename ArrayTypes::tdual_ffloat_1d k_theta0; - + typename ArrayTypes::tdual_ffloat_1d k_repscale; + typename ArrayTypes::t_ffloat_1d d_k; typename ArrayTypes::t_ffloat_1d d_theta0; - + typename ArrayTypes::t_ffloat_1d d_repscale; + void allocate(); }; From e7581af0f531191eedd0658ee56344f877b5abd3 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 22:43:53 -0400 Subject: [PATCH 099/385] fixes --- src/KOKKOS/angle_spica_kokkos.cpp | 6 ++++++ src/KOKKOS/angle_spica_kokkos.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 5d2813545b..06a3b6de2e 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -313,10 +313,12 @@ void AngleSPICAKokkos::allocate() k_k = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::k",n+1); k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",n+1); k_repscale = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::repscale",n+1); + k_setflag = typename ArrayTypes::tdual_int_1d("AngleSPICA::setflag",n+1); d_k = k_k.template view(); d_theta0 = k_theta0.template view(); d_repscale = k_repscale.template view(); + d_setflag = k_setflag.template view(); } /* ---------------------------------------------------------------------- @@ -333,11 +335,13 @@ void AngleSPICAKokkos::coeff(int narg, char **arg) k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; k_repscale.h_view[i] = repscale[i]; + k_setflag.h_view[i] = setflag[i]; } k_k.template modify(); k_theta0.template modify(); k_repscale.template modify(); + k_setflag.template modify(); } /* ---------------------------------------------------------------------- @@ -354,11 +358,13 @@ void AngleSPICAKokkos::read_restart(FILE *fp) k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; k_repscale.h_view[i] = repscale[i]; + k_setflag.h_view[i] = setflag[i]; } k_k.template modify(); k_theta0.template modify(); k_repscale.template modify(); + k_setflag.template modify(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index da1264551e..b3d6f7b9e2 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -78,10 +78,12 @@ class AngleSPICAKokkos : public AngleSPICA { typename ArrayTypes::tdual_ffloat_1d k_k; typename ArrayTypes::tdual_ffloat_1d k_theta0; typename ArrayTypes::tdual_ffloat_1d k_repscale; + typename ArrayTypes::tdual_int_1d k_setflag; typename ArrayTypes::t_ffloat_1d d_k; typename ArrayTypes::t_ffloat_1d d_theta0; typename ArrayTypes::t_ffloat_1d d_repscale; + typename ArrayTypes::t_int_1d d_setflag; void allocate(); }; From 860c190712f298f335108bd3878e719286dc7da6 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 22:56:09 -0400 Subject: [PATCH 100/385] fixes --- src/CG-SPICA/angle_spica.h | 2 +- src/KOKKOS/angle_spica_kokkos.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CG-SPICA/angle_spica.h b/src/CG-SPICA/angle_spica.h index f0085fe2fd..539512c0e9 100644 --- a/src/CG-SPICA/angle_spica.h +++ b/src/CG-SPICA/angle_spica.h @@ -52,7 +52,7 @@ class AngleSPICA : public Angle { void ev_tally13(int, int, int, int, double, double, double, double, double); - void allocate(); + virtual void allocate(); }; } // namespace LAMMPS_NS diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index b3d6f7b9e2..d35a877122 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -85,7 +85,7 @@ class AngleSPICAKokkos : public AngleSPICA { typename ArrayTypes::t_ffloat_1d d_repscale; typename ArrayTypes::t_int_1d d_setflag; - void allocate(); + void allocate() override; }; } From 7990da4ee8f1e712f82499bfd63f92a09f25eccb Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 4 Jun 2024 23:00:17 -0400 Subject: [PATCH 101/385] Update angle_spica.cpp --- src/CG-SPICA/angle_spica.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CG-SPICA/angle_spica.cpp b/src/CG-SPICA/angle_spica.cpp index 45b28d812a..bf86a6ec45 100644 --- a/src/CG-SPICA/angle_spica.cpp +++ b/src/CG-SPICA/angle_spica.cpp @@ -54,7 +54,7 @@ AngleSPICA::AngleSPICA(LAMMPS *lmp) : AngleSPICA::~AngleSPICA() { - if (allocated) { + if (allocated && !copymode) { memory->destroy(setflag); memory->destroy(k); memory->destroy(theta0); From 43d94985fa8eac88089f3ab1cf735e5cb748aef4 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Wed, 5 Jun 2024 19:13:16 -0400 Subject: [PATCH 102/385] angle-spica.yaml using in.spica and data.spica in.spica and data.spica based on in.fourmol and data.fourmol with pair style lj_spica instead of pair style zero --- unittest/force-styles/test_angle_style.cpp | 3 + unittest/force-styles/tests/angle-spica.yaml | 87 +++++++ unittest/force-styles/tests/data.spica | 233 +++++++++++++++++++ unittest/force-styles/tests/in.spica | 32 +++ 4 files changed, 355 insertions(+) create mode 100644 unittest/force-styles/tests/angle-spica.yaml create mode 100644 unittest/force-styles/tests/data.spica create mode 100644 unittest/force-styles/tests/in.spica diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index dbf175c801..47c475e884 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -706,6 +706,9 @@ TEST(AngleStyle, numdiff) TEST(AngleStyle, single) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); + + // angle-spica test not compatible with pair zero + if (utils::strmatch(test_config.angle_style, "^spica")) GTEST_SKIP(); LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; diff --git a/unittest/force-styles/tests/angle-spica.yaml b/unittest/force-styles/tests/angle-spica.yaml new file mode 100644 index 0000000000..7654be0345 --- /dev/null +++ b/unittest/force-styles/tests/angle-spica.yaml @@ -0,0 +1,87 @@ +--- +lammps_version: 7 Feb 2024 +tags: generated +date_generated: Wed Jun 5 18:31:11 2024 +epsilon: 1e-12 +skip_tests: +prerequisites: ! | + atom full + angle spica + pair lj/spica +pre_commands: ! | + variable write_data_pair index ij +post_commands: ! | + pair_style lj/spica 8.0 +input_file: in.spica +angle_style: spica +angle_coeff: ! "1 33.5 110.1 \n2 46.1 111.3 \n3 40.0 120.0 \n4 33.0 108.5 \n" +equilibrium: 4 1.9216075064457565 1.9425514574696887 2.0943951023931953 1.8936822384138474 +extract: ! "" +natoms: 29 +init_energy: 38.36438529349082 +init_stress: ! |2- + 6.2288484633192937e+01 -2.4958587357033732e+01 1.5261156310077459e+02 2.7527094178009044e+01 4.2708401447133369e+01 -2.5265950282815652e+01 +init_forces: ! |2 + 1 1.7230431704651284e+01 4.0071311825737794e+01 2.5153895595391262e+01 + 2 1.4681450443715043e+01 9.4049099264163125e+00 -2.0102364558934152e+01 + 3 -1.9308548347980725e+01 -2.8460741684874360e+01 6.4339170989100403e+00 + 4 -5.2290857572683347e+00 -9.4927850504411957e+00 1.8003472602849664e+00 + 5 -1.6382493884699279e+01 -1.4784175400797803e+01 -6.1931262199840624e+00 + 6 -5.4493064751680564e+01 7.5613258287794565e+01 6.9941734306087866e+01 + 7 -4.7395486031142198e+01 3.7640428970968820e+00 -2.4566126298992822e+02 + 8 4.8960191044380039e+01 -4.5712855041323763e+01 1.9415466008820243e+02 + 9 -8.3924213860655783e+00 2.4590103192063562e+01 3.2878160380265854e+01 + 10 6.8038129570966305e+01 -4.6569300903873433e+01 -7.6671701712056688e+01 + 11 -2.1258622382772373e+01 -7.4008599257925383e+00 8.3610564111488799e+00 + 12 5.9901920466154710e+00 -3.0542621446562030e+00 -7.5713636171526382e+00 + 13 1.4189850824692691e+00 1.0835451791895949e+00 4.9993493214959894e-01 + 14 1.1355220599075533e+01 2.4997321466757656e+00 -5.2256561116849181e+00 + 15 1.3933035015335755e+00 -2.0786326583247088e+00 8.7283364302611144e+00 + 16 4.5875574605935235e+01 -2.7754880718666161e+01 -1.0582764215323260e+02 + 17 -4.2451226361036497e+01 2.8306085448648393e+01 1.1928362036932688e+02 + 18 5.2926497658556788e-02 7.0441277800577096e-01 -2.9584690206819020e+00 + 19 -8.6276212064612834e-01 -1.0756990560638664e+00 1.2826229074637665e+00 + 20 7.9148971075772434e-01 3.3735689913016514e-01 1.7102043999486722e+00 + 21 -5.9956840446092086e+00 -6.6440354071373493e+00 1.8013592125677949e+01 + 22 -1.4065918957775763e+01 -4.6031498182035513e+00 -1.5782854315475038e+01 + 23 2.0049558879496164e+01 1.1260925334020174e+01 -2.2177902350101499e+00 + 24 3.2508269160599186e+00 -1.9979416528015960e+01 1.0409971951734974e+01 + 25 -1.6060493526274090e+01 9.4218054960789366e-01 -1.2854339891002313e+01 + 26 1.2797730884335980e+01 1.9024610945429981e+01 2.4201678955447798e+00 + 27 5.3169168679178105e+00 -2.2776165356368182e+01 9.1726846500285717e+00 + 28 -1.9217628865768805e+01 7.5096140408582208e+00 -1.2798872429928149e+01 + 29 1.3910508062151619e+01 1.5274870243863951e+01 3.6205364526432242e+00 +run_energy: 38.176417113761396 +run_stress: ! |2- + 6.1357382915550481e+01 -2.4715660959892247e+01 1.5186466302604836e+02 2.7218614858138846e+01 4.2112515489269541e+01 -2.5607593286714120e+01 +run_forces: ! |2 + 1 1.7145760907927180e+01 4.0174672565571342e+01 2.5205552180237635e+01 + 2 1.4615170171901832e+01 9.2708448155131897e+00 -2.0078351161345097e+01 + 3 -1.9027637897644411e+01 -2.8642960432918144e+01 6.2314807077302952e+00 + 4 -5.2736618463889080e+00 -9.3424901289763778e+00 1.9422015848783882e+00 + 5 -1.6468832074580213e+01 -1.4729606520686309e+01 -6.2023333708615995e+00 + 6 -5.3718294227422540e+01 7.4801671388546964e+01 6.8368190594240389e+01 + 7 -4.7118098933035071e+01 3.8739803262288781e+00 -2.4290995583077535e+02 + 8 4.7876325968669121e+01 -4.4923173742504034e+01 1.9297993934786507e+02 + 9 -8.3824572561250399e+00 2.4542635562122975e+01 3.2839238074098198e+01 + 10 6.8198580866574645e+01 -4.6830380612887495e+01 -7.6629764788623447e+01 + 11 -2.1232237676690062e+01 -7.3683045541850962e+00 8.3643364257797792e+00 + 12 5.6908584692226185e+00 -2.9956405260312478e+00 -7.3282063658600993e+00 + 13 1.3684378256951288e+00 9.7105537426706034e-01 5.7801503997630133e-01 + 14 1.1379285236061559e+01 2.6704814459393837e+00 -5.2142720262734468e+00 + 15 1.5246096380310767e+00 -1.9886210527177606e+00 8.4529064022347313e+00 + 16 4.5766629638536287e+01 -2.7729192853260034e+01 -1.0555847936417963e+02 + 17 -4.2311907917867423e+01 2.8269504758036135e+01 1.1894203420097222e+02 + 18 4.5978604531469895e-02 6.0605282956542328e-01 -2.5489959663795330e+00 + 19 -7.4282409641952973e-01 -9.2821937232343465e-01 1.1099668747784261e+00 + 20 6.7850316938866917e-01 2.8824602749664086e-01 1.4733945401265087e+00 + 21 -6.1707359561298754e+00 -6.7761831890615607e+00 1.8428059527969836e+01 + 22 -1.3998960882672469e+01 -4.5334962854737153e+00 -1.5964259983712697e+01 + 23 2.0157648747423554e+01 1.1323428247127397e+01 -2.4508469770619676e+00 + 24 3.5283602170234043e+00 -2.0588385440875950e+01 1.0846305899711011e+01 + 25 -1.6431076320543696e+01 1.1358029038847810e+00 -1.3239288833419160e+01 + 26 1.2890779580326928e+01 1.9439960296533382e+01 2.3687830191265684e+00 + 27 5.4188347979018312e+00 -2.2961492507008920e+01 9.2221110477962096e+00 + 28 -1.9337322641186159e+01 7.5984768842531718e+00 -1.2868573316667142e+01 + 29 1.3928283887490117e+01 1.5371333793823325e+01 3.6408125176375652e+00 +... diff --git a/unittest/force-styles/tests/data.spica b/unittest/force-styles/tests/data.spica new file mode 100644 index 0000000000..33b8c21ae7 --- /dev/null +++ b/unittest/force-styles/tests/data.spica @@ -0,0 +1,233 @@ +LAMMPS data file via write_data, version 5 May 2020, timestep = 0 + +29 atoms +5 atom types +24 bonds +5 bond types +30 angles +4 angle types +31 dihedrals +5 dihedral types +2 impropers +2 improper types + + -6.024572 8.975428 xlo xhi + -7.692866 7.307134 ylo yhi + -8.086924 6.913076 zlo zhi + +Masses + +1 12.0107 +2 4.00794 +3 14.0067 +4 15.9994 +5 15.9994 + +PairIJ Coeffs # lj/spica + +1 1 lj9_6 0.02 2.5 +1 2 lj9_6 0.01 1.58114 +1 3 lj9_6 0.02 2.82843 +1 4 lj9_6 0.0173205 2.78388 +1 5 lj9_6 0.0173205 2.78388 +2 2 lj12_4 0.005 1.0 +2 3 lj12_4 0.01 1.78885 +2 4 lj12_4 0.005 0.5 +2 5 lj12_4 0.00866025 1.76068 8 +3 3 lj12_6 0.02 3.2 8 +3 4 lj12_6 0.0173205 3.1496 8 +3 5 lj12_6 0.0173205 3.1496 8 +4 4 lj9_6 0.015 3.1 8 +4 5 lj9_6 0.015 3.1 8 +5 5 lj9_6 0.015 3.1 8 + +Bond Coeffs # zero + +1 1.5 +2 1.1 +3 1.3 +4 1.2 +5 1 + +Angle Coeffs # spica + +1 33.5 110.1 +2 46.1 111.3 +3 40 120 +4 33 108.5 + +Dihedral Coeffs # zero + +1 +2 +3 +4 +5 + +Improper Coeffs # zero + +1 +2 + +Atoms # full + +10 2 1 7.0000000000000007e-02 2.0185283555536988e+00 -1.4283966846517357e+00 -9.6733527271133024e-01 0 0 0 +11 2 2 8.9999999999999997e-02 1.7929780509347666e+00 -1.9871047540768743e+00 -1.8840626643185674e+00 0 0 0 +12 2 1 -2.7000000000000002e-01 3.0030247876861225e+00 -4.8923319967572748e-01 -1.6188658531537248e+00 0 0 0 +13 2 2 8.9999999999999997e-02 4.0447273787895934e+00 -9.0131998547446246e-01 -1.6384447268320836e+00 0 0 0 +14 2 2 8.9999999999999997e-02 2.6033152817257075e+00 -4.0789761505963579e-01 -2.6554413538823063e+00 0 0 0 + 2 1 2 3.1000000000000000e-01 3.0197083955402204e-01 2.9515239068888608e+00 -8.5689735572907566e-01 0 0 0 + 3 1 1 -2.0000000000000000e-02 -6.9435377880558602e-01 1.2440473127136711e+00 -6.2233801468892025e-01 0 0 0 + 4 1 2 8.9999999999999997e-02 -1.5771614164685133e+00 1.4915333140468066e+00 -1.2487126845040522e+00 0 0 0 + 6 1 1 5.1000000000000001e-01 2.9412607937706009e-01 2.2719282656652909e-01 -1.2843094067857870e+00 0 0 0 + 7 1 4 -5.1000000000000001e-01 3.4019871062879609e-01 -9.1277350075786561e-03 -2.4633113224304561e+00 0 0 0 +19 3 2 4.2359999999999998e-01 1.5349125211132961e+00 2.6315969880333707e+00 -4.2472859440220647e+00 0 0 0 +15 2 2 8.9999999999999997e-02 2.9756315249791303e+00 5.6334269722969288e-01 -1.2437650754599008e+00 0 0 0 +18 3 4 -8.4719999999999995e-01 2.1384791188033843e+00 3.0177261773770208e+00 -3.5160827596876225e+00 0 0 0 +20 3 2 4.2359999999999998e-01 2.7641167828863153e+00 3.6833419064000221e+00 -3.9380850623312638e+00 0 0 0 + 8 2 3 -4.6999999999999997e-01 1.1641187171852805e+00 -4.8375305955385234e-01 -6.7659823767368688e-01 0 0 0 + 9 2 2 3.1000000000000000e-01 1.3777459838125838e+00 -2.5366338669522998e-01 2.6877644730326306e-01 0 0 0 +16 2 1 5.1000000000000001e-01 2.6517554244980306e+00 -2.3957110424978438e+00 3.2908335999178327e-02 0 0 0 +17 2 4 -5.1000000000000001e-01 2.2309964792710639e+00 -2.1022918943319384e+00 1.1491948328949437e+00 0 0 0 + 1 1 3 -4.6999999999999997e-01 -2.7993683669226832e-01 2.4726588069312840e+00 -1.7200860244148433e-01 0 0 0 + 5 1 2 8.9999999999999997e-02 -8.9501761359359255e-01 9.3568128743071344e-01 4.0227731871484346e-01 0 0 0 +21 4 5 -8.4719999999999995e-01 4.9064454390208301e+00 -4.0751205255383196e+00 -3.6215576073601046e+00 0 0 0 +22 4 2 4.2359999999999998e-01 4.3687453488627543e+00 -4.2054270536772504e+00 -4.4651491269372565e+00 0 0 0 +23 4 2 4.2359999999999998e-01 5.7374928154769504e+00 -3.5763355905184966e+00 -3.8820297194230728e+00 0 0 0 +24 5 5 -8.4719999999999995e-01 2.0684115301174013e+00 3.1518221747664397e+00 3.1554242678474576e+00 0 0 0 +25 5 2 4.2359999999999998e-01 1.2998381073113014e+00 3.2755513587518097e+00 2.5092990173114837e+00 0 0 0 +26 5 2 4.2359999999999998e-01 2.5807438597688113e+00 4.0120175892854135e+00 3.2133398379059099e+00 0 0 0 +27 6 5 -8.4719999999999995e-01 -1.9613581876744359e+00 -4.3556300596085160e+00 2.1101467673534788e+00 0 0 0 +28 6 2 4.2359999999999998e-01 -2.7406520384725965e+00 -4.0207251278130975e+00 1.5828689861678511e+00 0 0 0 +29 6 2 4.2359999999999998e-01 -1.3108232656499081e+00 -3.5992986322410760e+00 2.2680459788743503e+00 0 0 0 + +Velocities + +1 7.7867804888392077e-04 5.8970331623292821e-04 -2.2179517633030531e-04 +2 2.7129529964126462e-03 4.6286427111164284e-03 3.5805549693846352e-03 +3 -1.2736791029204805e-03 1.6108674226414498e-03 -3.3618185901550799e-04 +4 -9.2828595122009308e-04 -1.2537885319521818e-03 -4.1204974953432108e-03 +5 -1.1800848061603740e-03 7.5424401975844038e-04 6.9023177964912290e-05 +6 -3.0914004879905335e-04 1.2755385764678133e-03 7.9574303350202582e-04 +7 -1.1037894966874103e-04 -7.6764845099077425e-04 -7.7217630460203659e-04 +8 3.9060281273221989e-04 -8.1444231918053418e-04 1.5134641148324972e-04 +9 1.2475530960659720e-03 -2.6608454451432528e-03 1.1117602907112732e-03 +10 4.5008983776042893e-04 4.9530197647538077e-04 -2.3336234361093645e-04 +11 -3.6977669078869707e-04 -1.5289071951960539e-03 -2.9176389881837113e-03 +12 1.0850834530183159e-03 -6.4965897903201833e-04 -1.2971152622619948e-03 +13 4.0754559196230639e-03 3.5043502394946119e-03 -7.8324487687854666e-04 +14 -1.3837220448746613e-04 -4.0656048637594394e-03 -3.9333461173944500e-03 +15 -4.3301707382721859e-03 -3.1802661664634938e-03 3.2037919043360571e-03 +16 -9.6715751018414326e-05 -5.0016572678960377e-04 1.4945658875149626e-03 +17 6.5692180538157174e-04 3.6635779995305095e-04 8.3495414466050911e-04 +18 -6.0936815808025862e-04 -9.3774557532468582e-04 -3.3558072507805731e-04 +19 -6.9919768291957119e-04 -3.6060777270430031e-03 4.2833405289822791e-03 +20 4.7777805013736515e-03 5.1003745845520452e-03 1.8002873923729241e-03 +21 -9.5568188553430398e-04 1.6594630943762931e-04 -1.8199788009966615e-04 +22 -3.3137518957653462e-03 -2.8683968287936054e-03 3.6384389958326871e-03 +23 2.4209481134686401e-04 -4.5457709985051130e-03 2.7663581642115042e-03 +24 2.5447450568861086e-04 4.8412447786110117e-04 -4.8021914527341357e-04 +25 4.3722771097312743e-03 -4.5184411669545515e-03 2.5200952006556795e-03 +26 -1.9250110555001179e-03 -3.0342169883610837e-03 3.5062814567984532e-03 +27 -2.6510179146429716e-04 3.6306203629019116e-04 -5.6235585400647747e-04 +28 -2.3068708109787484e-04 -8.5663070212203200e-04 2.1302563179109169e-03 +29 -2.5054744388303732e-03 -1.6773997805290820e-04 2.8436699761004796e-03 + +Bonds + +1 5 1 2 +2 3 1 3 +3 2 3 4 +4 2 3 5 +5 1 3 6 +6 3 6 8 +7 4 6 7 +8 5 8 9 +9 3 8 10 +10 2 10 11 +11 1 10 12 +12 1 10 16 +13 2 12 13 +14 2 12 14 +15 2 12 15 +16 4 16 17 +17 5 18 19 +18 5 18 20 +19 5 21 22 +20 5 21 23 +21 5 24 25 +22 5 24 26 +23 5 27 28 +24 5 27 29 + +Angles + +1 4 2 1 3 +2 4 1 3 5 +3 4 1 3 4 +4 4 1 3 6 +5 4 4 3 5 +6 2 5 3 6 +7 2 4 3 6 +8 3 3 6 7 +9 3 3 6 8 +10 3 7 6 8 +11 2 6 8 9 +12 2 9 8 10 +13 3 6 8 10 +14 2 8 10 11 +15 3 8 10 16 +16 2 11 10 12 +17 1 12 10 16 +18 1 8 10 12 +19 2 11 10 16 +20 2 10 12 15 +21 2 10 12 14 +22 2 10 12 13 +23 4 13 12 15 +24 4 13 12 14 +25 4 14 12 15 +26 4 10 16 17 +27 1 19 18 20 +28 1 22 21 23 +29 1 25 24 26 +30 1 28 27 29 + +Dihedrals + +1 2 2 1 3 6 +2 2 2 1 3 4 +3 3 2 1 3 5 +4 1 1 3 6 8 +5 1 1 3 6 7 +6 5 4 3 6 8 +7 5 4 3 6 7 +8 5 5 3 6 8 +9 5 5 3 6 7 +10 4 3 6 8 9 +11 3 3 6 8 10 +12 3 7 6 8 9 +13 4 7 6 8 10 +14 2 6 8 10 12 +15 2 6 8 10 16 +16 2 6 8 10 11 +17 2 9 8 10 12 +18 4 9 8 10 16 +19 5 9 8 10 11 +20 5 8 10 12 13 +21 1 8 10 12 14 +22 5 8 10 12 15 +23 4 8 10 16 17 +24 5 11 10 12 13 +25 5 11 10 12 14 +26 5 11 10 12 15 +27 2 11 10 16 17 +28 2 12 10 16 17 +29 5 16 10 12 13 +30 5 16 10 12 14 +31 5 16 10 12 15 + +Impropers + +1 1 6 3 8 7 +2 2 8 6 10 9 diff --git a/unittest/force-styles/tests/in.spica b/unittest/force-styles/tests/in.spica new file mode 100644 index 0000000000..1a80b2aac9 --- /dev/null +++ b/unittest/force-styles/tests/in.spica @@ -0,0 +1,32 @@ +variable newton_pair index on +variable newton_bond index on +variable bond_factor index 0.10 +variable angle_factor index 0.25 +variable dihedral_factor index 0.50 +variable units index real +variable input_dir index . +variable data_file index ${input_dir}/data.spica +variable pair_style index 'lj/spica 8.0' +variable bond_style index zero +variable angle_style index spica +variable dihedral_style index zero +variable improper_style index zero +variable t_target index 100.0 + +echo both + +atom_style full +atom_modify map array +neigh_modify delay 2 every 2 check no +units ${units} +timestep 0.1 +newton ${newton_pair} ${newton_bond} +special_bonds lj/coul ${bond_factor} ${angle_factor} ${dihedral_factor} + +pair_style ${pair_style} +bond_style ${bond_style} +angle_style ${angle_style} +dihedral_style ${dihedral_style} +improper_style ${improper_style} + +read_data ${data_file} From 235c1179b1ab393fb77929a5550bffd70fc803d8 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Wed, 5 Jun 2024 19:13:57 -0400 Subject: [PATCH 103/385] implemented evtally13 --- src/KOKKOS/angle_spica_kokkos.cpp | 94 ++++++++++++++++++++++++++++++- src/KOKKOS/angle_spica_kokkos.h | 5 ++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 06a3b6de2e..15c80e5cd5 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -289,8 +289,8 @@ void AngleSPICAKokkos::operator()(TagAngleSPICACompute::ev_tally(EV_FLOAT &ev, const int i, const int /* ---------------------------------------------------------------------- */ +//void AngleSPICA::ev_tally13(int i, int j, int nlocal, int newton_bond, +// double evdwl, double fpair, +// double delx, double dely, double delz) +template +KOKKOS_INLINE_FUNCTION +void AngleSPICAKokkos::ev_tally13(EV_FLOAT &ev, const int i, const int j, + const F_FLOAT &evdwl, const F_FLOAT &fpair, + const F_FLOAT &delx, const F_FLOAT &dely, const F_FLOAT &delz) const +{ + double v[6]; + + // The eatom and vatom arrays are atomic + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.template view(); + + if (eflag_either) { + if (eflag_global) { + if (newton_bond) { + ev.evdwl += evdwl; + } else { + if (i < nlocal) + ev.evdwl += 0.5*evdwl; + if (j < nlocal) + ev.evdwl += 0.5*evdwl; + } + } + if (eflag_atom) { + if (newton_bond || i < nlocal) v_eatom[i] += 0.5*evdwl; + if (newton_bond || j < nlocal) v_eatom[j] += 0.5*evdwl; + } + } + + if (vflag_either) { + v[0] = delx*delx*fpair; + v[1] = dely*dely*fpair; + v[2] = delz*delz*fpair; + v[3] = delx*dely*fpair; + v[4] = delx*delz*fpair; + v[5] = dely*delz*fpair; + + if (vflag_global) { + if (newton_bond) { + ev.v[0] += v[0]; + ev.v[1] += v[1]; + ev.v[2] += v[2]; + ev.v[3] += v[3]; + ev.v[4] += v[4]; + ev.v[5] += v[5]; + } else { + if (i < nlocal) { + ev.v[0] += 0.5*v[0]; + ev.v[1] += 0.5*v[1]; + ev.v[2] += 0.5*v[2]; + ev.v[3] += 0.5*v[3]; + ev.v[4] += 0.5*v[4]; + ev.v[5] += 0.5*v[5]; + } + if (j < nlocal) { + ev.v[0] += 0.5*v[0]; + ev.v[1] += 0.5*v[1]; + ev.v[2] += 0.5*v[2]; + ev.v[3] += 0.5*v[3]; + ev.v[4] += 0.5*v[4]; + ev.v[5] += 0.5*v[5]; + } + } + } + + if (vflag_atom) { + if (newton_bond || i < nlocal) { + v_vatom(i,0) += 0.5*v[0]; + v_vatom(i,1) += 0.5*v[1]; + v_vatom(i,2) += 0.5*v[2]; + v_vatom(i,3) += 0.5*v[3]; + v_vatom(i,4) += 0.5*v[4]; + v_vatom(i,5) += 0.5*v[5]; + } + if (newton_bond || j < nlocal) { + v_vatom(j,0) += 0.5*v[0]; + v_vatom(j,1) += 0.5*v[1]; + v_vatom(j,2) += 0.5*v[2]; + v_vatom(j,3) += 0.5*v[3]; + v_vatom(j,4) += 0.5*v[4]; + v_vatom(j,5) += 0.5*v[5]; + } + } + } +} +/* ---------------------------------------------------------------------- */ + namespace LAMMPS_NS { template class AngleSPICAKokkos; #ifdef LMP_KOKKOS_GPU diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index d35a877122..193e60eab3 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -59,6 +59,11 @@ class AngleSPICAKokkos : public AngleSPICA { const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const; + KOKKOS_INLINE_FUNCTION + void ev_tally13(EV_FLOAT &ev, const int i, const int j, + const F_FLOAT &evdwl, const F_FLOAT &fpair, + const F_FLOAT &delx, const F_FLOAT &dely, const F_FLOAT &delz) const; + protected: class NeighborKokkos *neighborKK; From f2db99193e01090b20284f7b66ca1f2588114657 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Wed, 5 Jun 2024 19:31:12 -0400 Subject: [PATCH 104/385] removed whitespaces --- src/KOKKOS/angle_spica_kokkos.cpp | 37 +++++++------- src/KOKKOS/angle_spica_kokkos.h | 6 +-- src/KOKKOS/pair_lj_spica_coul_long_kokkos.h | 3 +- unittest/force-styles/test_angle_style.cpp | 54 ++++++++++----------- 4 files changed, 48 insertions(+), 52 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 15c80e5cd5..a5b15d7a46 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -183,63 +183,63 @@ void AngleSPICAKokkos::operator()(TagAngleSPICAComputetype[i1]; const int type3 = atom->type[i3]; - + f13=0.0; e13=0.0; - + if (rsq3 < rminsq[type1][type3]) { const int ljt = lj_type[type1][type3]; const double r2inv = 1.0/rsq3; - + if (ljt == LJ12_4) { const double r4inv=r2inv*r2inv; - + f13 = r4inv*(lj1[type1][type3]*r4inv*r4inv - lj2[type1][type3]); if (eflag) e13 = r4inv*(lj3[type1][type3]*r4inv*r4inv - lj4[type1][type3]); - + } else if (ljt == LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; - + f13 = r6inv*(lj1[type1][type3]*r3inv - lj2[type1][type3]); if (eflag) e13 = r6inv*(lj3[type1][type3]*r3inv - lj4[type1][type3]); - + } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; - + f13 = r6inv*(lj1[type1][type3]*r6inv - lj2[type1][type3]); if (eflag) e13 = r6inv*(lj3[type1][type3]*r6inv - lj4[type1][type3]); - + } else if (ljt == LJ12_5) { const double r5inv = r2inv*r2inv*sqrt(r2inv); const double r7inv = r5inv*r2inv; - + f13 = r5inv*(lj1[type1][type3]*r7inv - lj2[type1][type3]); if (eflag) e13 = r5inv*(lj3[type1][type3]*r7inv - lj4[type1][type3]); } - + // make sure energy is 0.0 at the cutoff. if (eflag) e13 -= emin[type1][type3]; - + f13 *= r2inv; } } @@ -484,9 +484,6 @@ void AngleSPICAKokkos::ev_tally(EV_FLOAT &ev, const int i, const int /* ---------------------------------------------------------------------- */ -//void AngleSPICA::ev_tally13(int i, int j, int nlocal, int newton_bond, -// double evdwl, double fpair, -// double delx, double dely, double delz) template KOKKOS_INLINE_FUNCTION void AngleSPICAKokkos::ev_tally13(EV_FLOAT &ev, const int i, const int j, diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index 193e60eab3..2a35d62e83 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -63,7 +63,7 @@ class AngleSPICAKokkos : public AngleSPICA { void ev_tally13(EV_FLOAT &ev, const int i, const int j, const F_FLOAT &evdwl, const F_FLOAT &fpair, const F_FLOAT &delx, const F_FLOAT &dely, const F_FLOAT &delz) const; - + protected: class NeighborKokkos *neighborKK; @@ -84,12 +84,12 @@ class AngleSPICAKokkos : public AngleSPICA { typename ArrayTypes::tdual_ffloat_1d k_theta0; typename ArrayTypes::tdual_ffloat_1d k_repscale; typename ArrayTypes::tdual_int_1d k_setflag; - + typename ArrayTypes::t_ffloat_1d d_k; typename ArrayTypes::t_ffloat_1d d_theta0; typename ArrayTypes::t_ffloat_1d d_repscale; typename ArrayTypes::t_int_1d d_setflag; - + void allocate() override; }; diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h index 2f8fc68949..73ebf82b23 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h @@ -94,7 +94,7 @@ class PairLJSPICACoulLongKokkos : public PairLJSPICACoulLong { typename AT::t_f_array f; typename AT::t_int_1d_randomread type; typename AT::t_float_1d_randomread q; - + DAT::tdual_efloat_1d k_eatom; DAT::tdual_virial_array k_vatom; typename AT::t_efloat_1d d_eatom; @@ -145,7 +145,6 @@ class PairLJSPICACoulLongKokkos : public PairLJSPICACoulLong { friend EV_FLOAT pair_compute_neighlist>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute>(PairLJSPICACoulLongKokkos*,NeighListKokkos*); - friend void pair_virial_fdotr_compute(PairLJSPICACoulLongKokkos*); }; diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index 47c475e884..016cdbcf7b 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -535,16 +535,16 @@ TEST(AngleStyle, kokkos_omp) if (!LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); if (!Info::has_accelerator_feature("KOKKOS", "api", "openmp")) GTEST_SKIP(); - + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite", "-k", "on", "t", "4", "-sf", "kk"}; - + ::testing::internal::CaptureStdout(); LAMMPS *lmp = init_lammps(args, test_config, true); - + std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; - + if (!lmp) { std::cerr << "One or more prerequisite styles with /kk suffix\n" "are not available in this LAMMPS configuration:\n"; @@ -553,65 +553,65 @@ TEST(AngleStyle, kokkos_omp) } GTEST_SKIP(); } - + EXPECT_THAT(output, StartsWith("LAMMPS (")); EXPECT_THAT(output, HasSubstr("Loop time")); - + // abort if running in parallel and not all atoms are local const int nlocal = lmp->atom->nlocal; ASSERT_EQ(lmp->atom->natoms, nlocal); - + // relax error a bit for KOKKOS package double epsilon = 5.0 * test_config.epsilon; - + ErrorStats stats; auto angle = lmp->force->angle; - + EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", angle->virial, test_config.init_stress, epsilon); - + stats.reset(); EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); if (print_stats) std::cerr << "init_energy stats, newton on: " << stats << std::endl; - + if (!verbose) ::testing::internal::CaptureStdout(); run_lammps(lmp); if (!verbose) ::testing::internal::GetCapturedStdout(); - + EXPECT_FORCES("run_forces (newton on)", lmp->atom, test_config.run_forces, 10 * epsilon); EXPECT_STRESS("run_stress (newton on)", angle->virial, test_config.run_stress, epsilon); - + stats.reset(); int id = lmp->modify->find_compute("sum"); double energy = lmp->modify->compute[id]->compute_scalar(); EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.run_energy, epsilon); EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); if (print_stats) std::cerr << "run_energy stats, newton on: " << stats << std::endl; - + if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); - + // skip over these tests if newton bond is forced to be on if (lmp->force->newton_bond == 0) { angle = lmp->force->angle; - + EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton off)", angle->virial, test_config.init_stress, 2 * epsilon); - + stats.reset(); EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); if (print_stats) std::cerr << "init_energy stats, newton off:" << stats << std::endl; - + if (!verbose) ::testing::internal::CaptureStdout(); run_lammps(lmp); if (!verbose) ::testing::internal::GetCapturedStdout(); - + EXPECT_FORCES("run_forces (newton off)", lmp->atom, test_config.run_forces, 10 * epsilon); EXPECT_STRESS("run_stress (newton off)", angle->virial, test_config.run_stress, epsilon); - + stats.reset(); id = lmp->modify->find_compute("sum"); energy = lmp->modify->compute[id]->compute_scalar(); @@ -619,31 +619,31 @@ TEST(AngleStyle, kokkos_omp) EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); if (print_stats) std::cerr << "run_energy stats, newton off:" << stats << std::endl; } - + if (!verbose) ::testing::internal::CaptureStdout(); restart_lammps(lmp, test_config); if (!verbose) ::testing::internal::GetCapturedStdout(); - + angle = lmp->force->angle; EXPECT_FORCES("restart_forces", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("restart_stress", angle->virial, test_config.init_stress, epsilon); - + stats.reset(); EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); if (print_stats) std::cerr << "restart_energy stats:" << stats << std::endl; - + if (!verbose) ::testing::internal::CaptureStdout(); data_lammps(lmp, test_config); if (!verbose) ::testing::internal::GetCapturedStdout(); - + angle = lmp->force->angle; EXPECT_FORCES("data_forces", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("data_stress", angle->virial, test_config.init_stress, epsilon); - + stats.reset(); EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); if (print_stats) std::cerr << "data_energy stats:" << stats << std::endl; - + if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); if (!verbose) ::testing::internal::GetCapturedStdout(); From 44e13d97c6574f5ee011d99ff50774fe4cc9951f Mon Sep 17 00:00:00 2001 From: alphataubio Date: Wed, 5 Jun 2024 19:55:38 -0400 Subject: [PATCH 105/385] removed more whitespace --- src/KOKKOS/angle_spica_kokkos.cpp | 4 ++-- unittest/force-styles/test_angle_style.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index a5b15d7a46..25cbc1dced 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -243,7 +243,7 @@ void AngleSPICAKokkos::operator()(TagAngleSPICACompute::allocate() k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",n+1); k_repscale = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::repscale",n+1); k_setflag = typename ArrayTypes::tdual_int_1d("AngleSPICA::setflag",n+1); - + d_k = k_k.template view(); d_theta0 = k_theta0.template view(); d_repscale = k_repscale.template view(); diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index 016cdbcf7b..683ce48877 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -706,7 +706,7 @@ TEST(AngleStyle, numdiff) TEST(AngleStyle, single) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - + // angle-spica test not compatible with pair zero if (utils::strmatch(test_config.angle_style, "^spica")) GTEST_SKIP(); From a2560215888e41cf7772530528fc966de0faaae4 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Wed, 5 Jun 2024 19:56:09 -0400 Subject: [PATCH 106/385] added 2 kokkos styles to legacy make system --- src/KOKKOS/Install.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index 462c0cbe57..a068537d80 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -53,6 +53,7 @@ action angle_cosine_kokkos.cpp angle_cosine.cpp action angle_cosine_kokkos.h angle_cosine.h action angle_harmonic_kokkos.cpp angle_harmonic.cpp action angle_harmonic_kokkos.h angle_harmonic.h +action angle_spica_kokkos.h angle_spica.h action atom_kokkos.cpp action atom_kokkos.h action atom_map_kokkos.cpp @@ -340,6 +341,8 @@ action pair_lj_gromacs_coul_gromacs_kokkos.cpp pair_lj_gromacs_coul_gromacs.cpp action pair_lj_gromacs_coul_gromacs_kokkos.h pair_lj_gromacs_coul_gromacs.h action pair_lj_gromacs_kokkos.cpp pair_lj_gromacs.cpp action pair_lj_gromacs_kokkos.h pair_lj_gromacs.h +action pair_lj_spica_coul_long_kokkos.cpp pair_lj_coul_long_spica.cpp +action pair_lj_spica_coul_long_kokkos.h pair_lj_coul_long_spica.h action pair_lj_spica_kokkos.cpp pair_lj_spica.cpp action pair_lj_spica_kokkos.h pair_lj_spica.h action pair_meam_kokkos.cpp pair_meam.cpp From 1fa67290c3c4395939ede55b8c03b730fb2e2936 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Wed, 5 Jun 2024 19:56:29 -0400 Subject: [PATCH 107/385] updated pair style and angle style /kk in docs --- doc/src/angle_spica.rst | 3 ++- doc/src/pair_spica.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/src/angle_spica.rst b/doc/src/angle_spica.rst index 4162ce5608..2659dd4fc0 100644 --- a/doc/src/angle_spica.rst +++ b/doc/src/angle_spica.rst @@ -1,10 +1,11 @@ .. index:: angle_style spica .. index:: angle_style spica/omp +.. index:: angle_style spica/kk angle_style spica command ========================= -Accelerator Variants: *spica/omp* +Accelerator Variants: *spica/omp*, *spica/kk* Syntax """""" diff --git a/doc/src/pair_spica.rst b/doc/src/pair_spica.rst index 859506593f..b86639e806 100644 --- a/doc/src/pair_spica.rst +++ b/doc/src/pair_spica.rst @@ -5,6 +5,7 @@ .. index:: pair_style lj/spica/coul/long .. index:: pair_style lj/spica/coul/long/gpu .. index:: pair_style lj/spica/coul/long/omp +.. index:: pair_style lj/spica/coul/long/kk .. index:: pair_style lj/spica/coul/msm .. index:: pair_style lj/spica/coul/msm/omp @@ -16,7 +17,7 @@ Accelerator Variants: *lj/spica/gpu*, *lj/spica/kk*, *lj/spica/omp* pair_style lj/spica/coul/long command ===================================== -Accelerator Variants: *lj/spica/coul/long/gpu*, *lj/spica/coul/long/omp* +Accelerator Variants: *lj/spica/coul/long/gpu*, *lj/spica/coul/long/omp*, *lj/spica/coul/long/kk* pair_style lj/spica/coul/msm command ==================================== From 91c718c46774386a29f166e2fe3b4dac741df506 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Thu, 6 Jun 2024 12:47:11 -0400 Subject: [PATCH 108/385] Update Install.sh --- src/KOKKOS/Install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index a068537d80..cc9671b759 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -53,6 +53,7 @@ action angle_cosine_kokkos.cpp angle_cosine.cpp action angle_cosine_kokkos.h angle_cosine.h action angle_harmonic_kokkos.cpp angle_harmonic.cpp action angle_harmonic_kokkos.h angle_harmonic.h +action angle_spica_kokkos.cpp angle_spica.cpp action angle_spica_kokkos.h angle_spica.h action atom_kokkos.cpp action atom_kokkos.h From 42b4ff4cc5570d6bdd5afaddbcca214d27bbbb91 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sat, 8 Jun 2024 21:31:31 -0400 Subject: [PATCH 109/385] revert to develop test_angle_style, kokkos_omp test is in kokkos-unit-testing branch --- unittest/force-styles/test_angle_style.cpp | 126 +-------------------- 1 file changed, 1 insertion(+), 125 deletions(-) diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index 683ce48877..010fabd6e2 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -138,9 +138,8 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton } command("run 0 post no"); - command("variable write_data_pair index ii"); command("write_restart " + cfg.basename + ".restart"); - command("write_data " + cfg.basename + ".data pair ${write_data_pair}"); + command("write_data " + cfg.basename + ".data"); command("write_coeff " + cfg.basename + "-coeffs.in"); return lmp; @@ -530,126 +529,6 @@ TEST(AngleStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; -TEST(AngleStyle, kokkos_omp) -{ - if (!LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); - if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - if (!Info::has_accelerator_feature("KOKKOS", "api", "openmp")) GTEST_SKIP(); - - LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite", - "-k", "on", "t", "4", "-sf", "kk"}; - - ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(args, test_config, true); - - std::string output = ::testing::internal::GetCapturedStdout(); - if (verbose) std::cout << output; - - if (!lmp) { - std::cerr << "One or more prerequisite styles with /kk suffix\n" - "are not available in this LAMMPS configuration:\n"; - for (auto &prerequisite : test_config.prerequisites) { - std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; - } - GTEST_SKIP(); - } - - EXPECT_THAT(output, StartsWith("LAMMPS (")); - EXPECT_THAT(output, HasSubstr("Loop time")); - - // abort if running in parallel and not all atoms are local - const int nlocal = lmp->atom->nlocal; - ASSERT_EQ(lmp->atom->natoms, nlocal); - - // relax error a bit for KOKKOS package - double epsilon = 5.0 * test_config.epsilon; - - ErrorStats stats; - auto angle = lmp->force->angle; - - EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); - EXPECT_STRESS("init_stress (newton on)", angle->virial, test_config.init_stress, epsilon); - - stats.reset(); - EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); - if (print_stats) std::cerr << "init_energy stats, newton on: " << stats << std::endl; - - if (!verbose) ::testing::internal::CaptureStdout(); - run_lammps(lmp); - if (!verbose) ::testing::internal::GetCapturedStdout(); - - EXPECT_FORCES("run_forces (newton on)", lmp->atom, test_config.run_forces, 10 * epsilon); - EXPECT_STRESS("run_stress (newton on)", angle->virial, test_config.run_stress, epsilon); - - stats.reset(); - int id = lmp->modify->find_compute("sum"); - double energy = lmp->modify->compute[id]->compute_scalar(); - EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.run_energy, epsilon); - EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); - if (print_stats) std::cerr << "run_energy stats, newton on: " << stats << std::endl; - - if (!verbose) ::testing::internal::CaptureStdout(); - cleanup_lammps(lmp, test_config); - lmp = init_lammps(args, test_config, false); - if (!verbose) ::testing::internal::GetCapturedStdout(); - - // skip over these tests if newton bond is forced to be on - if (lmp->force->newton_bond == 0) { - angle = lmp->force->angle; - - EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); - EXPECT_STRESS("init_stress (newton off)", angle->virial, test_config.init_stress, - 2 * epsilon); - - stats.reset(); - EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); - if (print_stats) std::cerr << "init_energy stats, newton off:" << stats << std::endl; - - if (!verbose) ::testing::internal::CaptureStdout(); - run_lammps(lmp); - if (!verbose) ::testing::internal::GetCapturedStdout(); - - EXPECT_FORCES("run_forces (newton off)", lmp->atom, test_config.run_forces, 10 * epsilon); - EXPECT_STRESS("run_stress (newton off)", angle->virial, test_config.run_stress, epsilon); - - stats.reset(); - id = lmp->modify->find_compute("sum"); - energy = lmp->modify->compute[id]->compute_scalar(); - EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.run_energy, epsilon); - EXPECT_FP_LE_WITH_EPS(angle->energy, energy, epsilon); - if (print_stats) std::cerr << "run_energy stats, newton off:" << stats << std::endl; - } - - if (!verbose) ::testing::internal::CaptureStdout(); - restart_lammps(lmp, test_config); - if (!verbose) ::testing::internal::GetCapturedStdout(); - - angle = lmp->force->angle; - EXPECT_FORCES("restart_forces", lmp->atom, test_config.init_forces, epsilon); - EXPECT_STRESS("restart_stress", angle->virial, test_config.init_stress, epsilon); - - stats.reset(); - EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); - if (print_stats) std::cerr << "restart_energy stats:" << stats << std::endl; - - if (!verbose) ::testing::internal::CaptureStdout(); - data_lammps(lmp, test_config); - if (!verbose) ::testing::internal::GetCapturedStdout(); - - angle = lmp->force->angle; - EXPECT_FORCES("data_forces", lmp->atom, test_config.init_forces, epsilon); - EXPECT_STRESS("data_stress", angle->virial, test_config.init_stress, epsilon); - - stats.reset(); - EXPECT_FP_LE_WITH_EPS(angle->energy, test_config.init_energy, epsilon); - if (print_stats) std::cerr << "data_energy stats:" << stats << std::endl; - - if (!verbose) ::testing::internal::CaptureStdout(); - cleanup_lammps(lmp, test_config); - if (!verbose) ::testing::internal::GetCapturedStdout(); -}; - - TEST(AngleStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP(); @@ -707,9 +586,6 @@ TEST(AngleStyle, single) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - // angle-spica test not compatible with pair zero - if (utils::strmatch(test_config.angle_style, "^spica")) GTEST_SKIP(); - LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; // create a LAMMPS instance with standard settings to detect the number of atom types From ca8eb4fb68299f6007f11a4a6902a6699191bcce Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sat, 8 Jun 2024 21:57:24 -0400 Subject: [PATCH 110/385] update angle spica test --- unittest/force-styles/test_angle_style.cpp | 12 +++++++++--- unittest/force-styles/tests/in.spica | 2 -- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index 010fabd6e2..afee85d263 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -138,8 +138,9 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton } command("run 0 post no"); + command("variable write_data_pair index ii"); command("write_restart " + cfg.basename + ".restart"); - command("write_data " + cfg.basename + ".data"); + command("write_data " + cfg.basename + ".data pair ${write_data_pair}"); command("write_coeff " + cfg.basename + "-coeffs.in"); return lmp; @@ -644,8 +645,13 @@ TEST(AngleStyle, single) "extra/angle/per/atom 2 extra/special/per/atom 2", nangletypes)); - command("pair_style zero 8.0"); - command("pair_coeff * *"); + if (utils::strmatch(test_config.angle_style, "spica")) { + command("pair_style lj/spica 8.0"); + command("pair_coeff * * lj9_6 0.02 2.5"); + } else { + command("pair_style zero 8.0"); + command("pair_coeff * *"); + } command("angle_style " + test_config.angle_style); Angle *angle = lmp->force->angle; diff --git a/unittest/force-styles/tests/in.spica b/unittest/force-styles/tests/in.spica index 1a80b2aac9..6739409759 100644 --- a/unittest/force-styles/tests/in.spica +++ b/unittest/force-styles/tests/in.spica @@ -13,8 +13,6 @@ variable dihedral_style index zero variable improper_style index zero variable t_target index 100.0 -echo both - atom_style full atom_modify map array neigh_modify delay 2 every 2 check no From 2aacc017cbdb93ee8c461605da05f63f9c5e7c1e Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 12 Jun 2024 17:29:30 -0600 Subject: [PATCH 111/385] Changes to CMake to hopefully match Sachith's suggestions --- cmake/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index dd5fac30c6..d80e7df46c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -440,7 +440,7 @@ if((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") AND (CMAKE_CXX_STANDARD GREATER_EQUA PROPERTIES COMPILE_OPTIONS "-std=c++14") endif() -if(PKG_ATC OR PKG_AWPMD OR PKG_ML-QUIP OR PKG_ML-POD OR PKG_ELECTRODE OR BUILD_TOOLS OR PKG_RHEO) +if(PKG_ATC OR PKG_AWPMD OR PKG_ML-QUIP OR PKG_ML-POD OR PKG_ELECTRODE OR BUILD_TOOLS) enable_language(C) if (NOT USE_INTERNAL_LINALG) find_package(LAPACK) @@ -515,7 +515,7 @@ else() endif() foreach(PKG_WITH_INCL KSPACE PYTHON ML-IAP VORONOI COLVARS ML-HDNNP MDI MOLFILE NETCDF - PLUMED QMMM ML-QUIP SCAFACOS MACHDYN VTK KIM COMPRESS ML-PACE LEPTON) + PLUMED QMMM ML-QUIP SCAFACOS MACHDYN VTK KIM COMPRESS ML-PACE LEPTON RHEO) if(PKG_${PKG_WITH_INCL}) include(Packages/${PKG_WITH_INCL}) endif() From 80e96d8c9b8bcdf2df7bc5605c17e7b9de37a1df Mon Sep 17 00:00:00 2001 From: Ludwig Ahrens-Iwers Date: Thu, 13 Jun 2024 17:00:01 +0200 Subject: [PATCH 112/385] Bugfix electrode piston example --- .../electrode/piston/data.piston.final | 4064 ++++++++--------- examples/PACKAGES/electrode/piston/in.piston | 6 +- ...iston.g++.1 => log.22May2024.piston.g++.1} | 97 +- ...iston.g++.4 => log.22May2024.piston.g++.4} | 109 +- 4 files changed, 2147 insertions(+), 2129 deletions(-) rename examples/PACKAGES/electrode/piston/{log.1Dec2022.piston.g++.1 => log.22May2024.piston.g++.1} (64%) rename examples/PACKAGES/electrode/piston/{log.1Dec2022.piston.g++.4 => log.22May2024.piston.g++.4} (61%) diff --git a/examples/PACKAGES/electrode/piston/data.piston.final b/examples/PACKAGES/electrode/piston/data.piston.final index 8549261a3f..60570ec163 100644 --- a/examples/PACKAGES/electrode/piston/data.piston.final +++ b/examples/PACKAGES/electrode/piston/data.piston.final @@ -1,4 +1,4 @@ -LAMMPS data file via write_data, version 3 Nov 2022, timestep = 100000 +LAMMPS data file via write_data, version 7 Feb 2024, timestep = 100000, units = real 726 atoms 4 atom types @@ -35,732 +35,732 @@ Angle Coeffs # harmonic Atoms # full -49 25 2 0.008543040314262548 0 0 2.4018 0 0 0 -50 25 2 0.0160448240953976 1.4708 2.5475 2.4018 0 0 0 -51 26 2 -0.0079256875305239 0 5.0949 2.4018 0 0 0 -57 29 2 -0.005227878579680007 2.9416 0 2.4018 0 0 0 -58 29 2 0.01534182829253148 4.4124 2.5475 2.4018 0 0 0 -59 30 2 0.005249625623138609 2.9416 5.0949 2.4018 0 0 0 -676 242 3 -0.8476 2.819460981381933 5.027845836373835 5.552858700712285 1 0 0 -677 242 4 0.4238 3.6237064095951212 5.498057979630644 5.1894159030362905 1 0 0 -678 242 4 0.4238 3.0474931330566792 4.071918834795528 5.737806475295655 1 0 0 -709 253 3 -0.8476 3.326005069719568 2.1405935467748485 5.508189818283542 1 1 0 -195 81 4 0.4238 0.9649465875607126 4.340812162842168 5.657183047543541 0 0 0 -193 81 3 -0.8476 0.07822017262197362 3.9629228426194305 5.3908801998879925 0 0 0 -194 81 4 0.4238 0.11965319368873736 2.964163951647319 5.41854519664211 0 0 0 -103 51 3 -0.8476 6.804813198264613 5.084871250040471 11.277692419576146 1 0 0 -710 253 4 0.4238 2.3404190574558714 1.9714070000250485 5.508878140894409 1 1 0 -713 254 4 0.4238 9.064078450490644 2.446520257897097 5.3348626027546535 0 1 0 -65 33 2 0.01159205120014908 5.8832 0 2.4018 0 0 0 -66 33 2 0.01814012345205012 7.354000000000001 2.5475 2.4018 0 0 0 -67 34 2 0.001406594129736151 5.8832 5.0949 2.4018 0 0 0 -73 37 2 0.007725405338865237 8.8248 0 2.4018 0 0 0 -74 37 2 0.01259870480846824 10.2956 2.5475 2.4018 0 0 0 -75 38 2 -0.0004634638718638646 8.8248 5.0949 2.4018 0 0 0 -712 254 3 -0.8476 8.802633903527065 3.406390680517518 5.233373245990451 0 1 0 -714 254 4 0.4238 9.596656647074049 3.988446812598421 5.408709008648956 0 1 0 -604 218 3 -0.8476 10.053718350737668 0.9458152116350096 5.395407376762871 0 0 0 -189 79 4 0.4238 7.4156883111781475 3.478062124305858 6.469061899326572 -1 1 0 -170 73 4 0.4238 11.80947244959249 4.900763207760851 5.38132073658318 -1 0 0 -315 121 4 0.4238 12.776759773328315 8.761973185109612 12.512691519633954 0 0 0 -605 218 4 0.4238 11.02536148980741 0.7580225920428326 5.251723453806732 0 0 0 -116 55 4 0.4238 6.860405297106715 1.6714006503015966 5.673388843698673 -1 0 0 -388 146 3 -0.8476 13.766836983830515 3.9827224990972567 5.330985943540624 0 -1 0 -389 146 4 0.4238 13.425795558197045 3.8960741688633775 6.267033057995917 0 -1 0 -586 212 3 -0.8476 12.99172583601213 0.9627880677417303 5.186804494815568 0 1 0 -81 41 2 -0.006484897416350773 11.7664 0 2.4018 0 0 0 -82 41 2 0.008703081094077752 13.237200000000001 2.5475 2.4018 0 0 0 -83 42 2 0.00416546498595383 11.7664 5.0949 2.4018 0 0 0 -89 45 2 -0.01428117869162144 14.708000000000002 0 2.4018 0 0 0 -90 45 2 0.008098914705004666 16.178800000000003 2.5475 2.4018 0 0 0 -91 46 2 -0.02631301835063423 14.708000000000002 5.0949 2.4018 0 0 0 -601 217 3 -0.8476 14.580700057086469 2.470074704951404 9.549553516230905 0 0 0 -602 217 4 0.4238 13.852177407353523 2.485606699806581 10.234399813568656 0 0 0 -107 52 4 0.4238 1.7753325684361263 5.260464281758941 12.927518370297552 0 0 0 -603 217 4 0.4238 15.320102605212748 3.0795550665438127 9.835591885333054 0 0 0 -378 142 4 0.4238 15.457095569986127 9.173371129323348 12.171458596416667 0 -1 0 -422 157 4 0.4238 4.786861348572543 7.318978962263422 5.502857747714512 0 0 0 -52 26 2 -0.01097199601095499 1.4708 7.6424 2.4018 0 0 0 -53 27 2 0.01511923962052951 0 10.1898 2.4018 0 0 0 -60 30 2 -0.006773385603520778 4.4124 7.6424 2.4018 0 0 0 -61 31 2 -0.0006618884891667937 2.9416 10.1898 2.4018 0 0 0 -316 122 3 -0.8476 13.376991964874126 9.733980167782747 5.2443510947274685 -1 0 0 -423 157 4 0.4238 6.118596559257136 6.376695231617992 5.575034452052516 0 0 0 -421 157 3 -0.8476 5.134517216890271 6.414178710640228 5.748768298079106 0 0 0 -643 231 3 -0.8476 3.1763474635956395 8.886111555148053 5.282080436718036 1 0 0 -644 231 4 0.4238 2.513118087318634 8.218141042299745 4.944523274214661 1 0 0 -581 210 4 0.4238 1.9210593488372454 5.953179684029002 6.41990460669887 1 2 0 -426 158 4 0.4238 15.617845693245721 0.24896899149304588 12.27982548992809 0 0 0 -582 210 4 0.4238 0.738973409880735 7.079488872493541 6.392936823978947 1 2 0 -299 116 4 0.4238 1.8742478531098932 0.3995180953106482 9.934219884593341 0 0 0 -691 247 3 -0.8476 7.689714173805594 6.217320019017989 5.258073041482447 0 0 0 -693 247 4 0.4238 8.37284176321211 6.235548870214623 5.9881454257142686 0 0 0 -369 139 4 0.4238 8.495516986476424 8.433565798354097 5.028752451013381 0 0 0 -300 116 4 0.4238 2.911599743969392 1.5040316802567835 10.542971525540692 0 0 0 -367 139 3 -0.8476 8.981733107973055 8.98237922473984 5.708751536331027 0 0 0 -368 139 4 0.4238 9.966826030721563 8.844561146157186 5.605781099266854 0 0 0 -68 34 2 -0.005353421945912079 7.354000000000001 7.6424 2.4018 0 0 0 -69 35 2 -0.02242224817485722 5.8832 10.1898 2.4018 0 0 0 -76 38 2 -0.008749553110635829 10.2956 7.6424 2.4018 0 0 0 -77 39 2 -0.001587975150694571 8.8248 10.1898 2.4018 0 0 0 -169 73 3 -0.8476 10.86775468338433 5.19328586965271 5.547456960295855 -1 0 0 -171 73 4 0.4238 10.800651355284717 6.183975873079292 5.42898775849054 -1 0 0 -425 158 4 0.4238 16.365686839954538 1.6918548567498142 12.120323120019671 0 0 0 -543 197 4 0.4238 15.74455376269356 5.985972014656273 4.244902593730374 1 -1 0 -522 190 4 0.4238 12.358773694396177 8.241027948029787 5.4342692843409335 0 0 0 -541 197 3 -0.8476 15.948040102134595 5.877893730968188 5.217997046194076 1 -1 0 -520 190 3 -0.8476 11.521538237363735 7.820855042448146 5.784258984209179 0 0 0 -521 190 4 0.4238 11.640196773280092 7.596913910660865 6.751612100022279 0 0 0 -213 87 4 0.4238 16.94869795729418 7.658694530040734 4.96211922323137 -1 1 0 -84 42 2 -0.02253342595559467 13.237200000000001 7.6424 2.4018 0 0 0 -85 43 2 -0.02386325442458492 11.7664 10.1898 2.4018 0 0 0 -92 46 2 -0.03395260336333754 16.178800000000003 7.6424 2.4018 0 0 0 -93 47 2 -0.02530118571584997 14.708000000000002 10.1898 2.4018 0 0 0 -211 87 3 -0.8476 17.523577595505472 8.373665168921514 5.360027780919543 -1 1 0 -212 87 4 0.4238 17.0831513845729 9.262879118182907 5.236238106470797 -1 1 0 -205 85 3 -0.8476 5.522367248324516 5.082933874779558 8.132800488002275 0 0 0 -207 85 4 0.4238 4.856839636565012 5.040433764778345 8.877963749174969 0 0 0 -206 85 4 0.4238 5.248881626300537 5.7908645558964675 7.4816162727356925 0 0 0 -188 79 4 0.4238 6.497322905499542 3.778149013994996 7.785564626115502 -1 1 0 -104 51 4 0.4238 6.975223059984354 6.057718294907826 11.434323932547846 1 0 0 -240 96 4 0.4238 15.907149183138676 1.5390029324335393 8.501706376153551 0 0 0 -186 78 4 0.4238 10.809679491055352 4.82920260257931 12.234285165918621 -1 0 0 -627 225 4 0.4238 1.142311523721859 0.5701072346557061 5.407977967350236 1 0 0 -679 243 3 -0.8476 14.388344112145468 5.895841187409739 12.553492598002434 0 0 0 -298 116 3 -0.8476 2.249658462135075 0.7910692719529153 10.774314024535329 0 0 0 -498 182 4 0.4238 3.1782299333534842 4.421584435342713 10.843305251025729 0 0 0 -242 97 4 0.4238 0.11372454909840307 4.5608406751586585 8.512959914844476 1 0 0 -497 182 4 0.4238 3.635093197649102 3.6372270746257795 9.485847319495857 0 0 0 -496 182 3 -0.8476 3.891719288381077 4.3420728032109785 10.147162657393025 0 0 0 -243 97 4 0.4238 1.166929713515916 3.3148448925475837 8.443094046894181 1 0 0 -653 234 4 0.4238 7.986724447375092 9.58663088134249 7.078331051080797 0 -1 0 -291 113 4 0.4238 1.3902648936489443 6.574700931558314 8.627083040419217 2 0 0 -476 175 4 0.4238 10.873396710796088 3.7503648821895377 7.099886667034369 0 0 0 -626 225 4 0.4238 17.341387780659073 1.3131579087511918 5.302792549204005 0 0 0 -187 79 3 -0.8476 6.972728954372332 3.0679623101137263 7.266310623507446 -1 1 0 -198 82 4 0.4238 11.676864533923228 2.4008557059764484 11.887821076968272 0 1 0 -477 175 4 0.4238 11.028257394545655 2.35049554258184 6.2734372961507034 0 0 0 -385 145 3 -0.8476 9.464341047888412 3.3817188372167357 10.216775935923458 0 0 0 -432 160 4 0.4238 7.4158023596883 5.242602008656209 8.911704625300178 1 0 0 -386 145 4 0.4238 9.834023311752183 3.1577521519269993 11.118538449130567 0 0 0 -387 145 4 0.4238 8.839522007452976 2.6580907515237095 9.923575914839613 0 0 0 -431 160 4 0.4238 8.97937772550123 4.855861822733754 9.180574759645397 1 0 0 -430 160 3 -0.8476 8.360641109810988 5.4265820345806866 8.640716144277553 1 0 0 -475 175 3 -0.8476 11.185122253842481 2.80161992224134 7.152006656534362 0 0 0 -577 209 3 -0.8476 11.892138326574036 4.606875557740573 8.77639055263619 0 0 0 -578 209 4 0.4238 11.15205283743665 4.662613397329064 9.446591004081876 0 0 0 -579 209 4 0.4238 11.806616036319609 3.757706369789849 8.255238997490805 0 0 0 -282 110 4 0.4238 11.993978725584078 0.6955935520855357 10.362669416358116 1 -1 0 -281 110 4 0.4238 13.246870870022725 0.7932688823507881 11.405429138463369 1 -1 0 -280 110 3 -0.8476 12.399897412926068 1.230819260076083 11.103456814170583 1 -1 0 -576 208 4 0.4238 7.424477420107739 1.9205433206111677 8.347065650914391 0 0 0 -115 55 3 -0.8476 6.566829197641645 0.7852168728409362 5.314930190030221 -1 0 0 -117 55 4 0.4238 7.3699037409564365 0.24315040972892277 5.0674680046309595 -1 0 0 -654 234 4 0.4238 6.5231563540652955 9.334766916189148 7.757419217563333 0 -1 0 -196 82 3 -0.8476 11.325205678636125 3.0960265761644146 12.514778502806406 0 1 0 -353 134 4 0.4238 10.34648669613546 9.717097284025227 12.21531953491664 1 -1 0 -575 208 4 0.4238 6.8621106467674515 0.6153612624236356 9.151348490167914 0 0 0 -390 146 4 0.4238 14.71592873372509 4.297162424310161 5.349801109951233 0 -1 0 -468 172 4 0.4238 14.334820367346975 9.458375422451784 9.389857451086156 0 1 0 -680 243 4 0.4238 14.420209860242771 5.620779336744502 11.592592717412877 0 0 0 -401 150 4 0.4238 13.58439176144119 5.20555361726743 9.602450324228725 0 0 0 -241 97 3 -0.8476 0.3452523216688656 3.6651747745441994 8.892669971959721 1 0 0 -400 150 3 -0.8476 14.455722458405065 5.628055139668128 9.852004866869082 0 0 0 -562 204 3 -0.8476 16.641350343283886 4.083296189715342 10.989056663280612 0 0 0 -563 204 4 0.4238 16.037770379422128 4.850987807509285 10.773784577109874 0 0 0 -564 204 4 0.4238 17.178401412678653 3.844498107566038 10.180011679572727 0 0 0 -687 245 4 0.4238 16.714761709756484 4.337732009968187 12.639387839102408 0 0 0 -467 172 4 0.4238 13.346114040811248 9.313588789790407 10.681417293752048 0 1 0 -666 238 4 0.4238 4.34126756117676 8.905137414158627 6.516509692747207 0 0 0 -664 238 3 -0.8476 4.751093055532058 9.063792850376354 7.414773021734108 0 0 0 -637 229 3 -0.8476 0.7471877141074242 8.354301697005937 11.535489275372338 1 -1 0 -290 113 4 0.4238 1.5797294433316216 5.599705770675408 9.923275349951421 2 0 0 -652 234 3 -0.8476 7.361488829472968 9.878076947823384 7.802307315600979 0 -1 0 -402 150 4 0.4238 14.817635634485477 6.133309514160487 9.068590593856563 0 0 0 -257 102 4 0.4238 2.654784049830047 9.360773717063745 10.840199367879586 1 0 0 -256 102 3 -0.8476 2.7861525988520546 9.125527207512318 9.87717977353219 1 0 0 -424 158 3 -0.8476 16.282645750155215 0.8737366464771422 12.689346105039219 0 0 0 -665 238 4 0.4238 4.161382545837657 8.676258785766425 8.123335852134215 0 0 0 -122 57 4 0.4238 7.825760402756952 0.4118083408578644 10.770069138315867 0 0 0 -258 102 4 0.4238 2.6507626673715956 8.142581237775797 9.752715909565804 1 0 0 -466 172 3 -0.8476 13.51508294943025 9.818693918214702 9.83505984792318 0 1 0 -377 142 4 0.4238 17.080578433321772 9.22752863551317 12.004131277448275 0 -1 0 -105 51 4 0.4238 5.853746057457844 4.953910172266563 10.997832121722793 1 0 0 -580 210 3 -0.8476 1.3210642970676016 6.5207610408534675 6.98369360583625 1 2 0 -638 229 4 0.4238 0.9970176405359414 7.548196505367084 10.999036348164699 1 -1 0 -717 255 4 0.4238 12.39024162854418 0.28840285676654837 6.591412796748799 1 1 0 -352 134 3 -0.8476 11.226526547688243 9.242192984029268 12.216220312698256 1 -1 0 -137 62 4 0.4238 2.027815877839267 1.8732362417553365 7.987025431651223 0 0 0 -692 247 4 0.4238 7.786529711776536 5.3723882747118985 4.732032313657794 0 0 0 -645 231 4 0.4238 2.8214978665553723 9.809957726487395 5.138560233155634 1 0 0 -185 78 4 0.4238 10.316334741569422 6.044854419256892 11.261952987588222 -1 0 0 -292 114 3 -0.8476 5.67656046565693 9.596732521658042 10.995975339349497 0 0 0 -294 114 4 0.4238 4.789939140622079 9.742378050555555 11.434941355604284 0 0 0 -574 208 3 -0.8476 7.516492206466037 1.3710743960569696 9.177498905408314 0 0 0 -711 253 4 0.4238 3.810396593432228 1.2880838486682353 5.311739399800884 1 1 0 -437 162 4 0.4238 6.860466827809697 8.422553075168016 11.337314477776795 1 0 0 -436 162 3 -0.8476 7.571135241081482 7.730803749388945 11.465517092648946 1 0 0 -588 212 4 0.4238 13.498663213828278 0.38996264096399363 4.542687820493753 0 1 0 -438 162 4 0.4238 8.31154777226707 7.888534002434359 10.812132835679304 1 0 0 -701 250 4 0.4238 9.286513797831446 6.646575924029509 9.147658317438076 2 -1 0 -700 250 3 -0.8476 9.643385938511667 7.47449461758298 9.580320183736939 2 -1 0 -513 187 4 0.4238 1.8185112493161812 10.053298043923604 8.893843011592004 1 0 0 -106 52 3 -0.8476 2.266275159877156 4.688670030017356 12.270229177579722 0 0 0 -702 250 4 0.4238 10.60077224354893 7.600272590312019 9.32033378097907 2 -1 0 -138 62 4 0.4238 3.3080664559545965 2.543423811679406 7.226477171885048 0 0 0 -542 197 4 0.4238 16.61438869395917 5.142214492766869 5.339474575210934 1 -1 0 -376 142 3 -0.8476 16.267806197381876 9.752608027087469 12.256508250931114 0 -1 0 -639 229 4 0.4238 1.2657862555275905 8.359520313997795 12.390492314175315 1 -1 0 -524 191 4 0.4238 13.000197848284115 7.591623195457351 8.231720539306574 0 -1 0 -360 136 4 0.4238 16.927450088881905 9.623013099606048 8.250041448548666 0 0 0 -359 136 4 0.4238 16.11845308444977 9.867127694636144 6.852701508709072 0 0 0 -358 136 3 -0.8476 16.050165493006663 9.508888830997453 7.78383224839627 0 0 0 -289 113 3 -0.8476 1.4110503224699262 6.539558634958015 9.626249498776556 2 0 0 -384 144 4 0.4238 2.493028840280995 9.719794300761412 12.910496964228098 0 -1 0 -406 152 3 -0.8476 15.247929159060655 7.012234071819868 7.773022011622398 0 0 0 -408 152 4 0.4238 15.48816222034174 6.532006856700564 6.929416156188867 0 0 0 -523 191 3 -0.8476 12.082020144652011 7.21880883213217 8.365736806678662 0 -1 0 -407 152 4 0.4238 15.63244454689617 7.93511971351192 7.752267289359093 0 0 0 -525 191 4 0.4238 12.142278624301815 6.233249103608379 8.523992954763008 0 -1 0 -625 225 3 -0.8476 0.6808462683385743 1.4551937786169056 5.347366251301949 1 0 0 -136 62 3 -0.8476 2.697762074389062 2.615104290660337 8.015394827891544 0 0 0 -587 212 4 0.4238 13.566186954572455 1.7288682835758 5.475103447756109 0 1 0 -184 78 3 -0.8476 10.806213490399747 5.820732453607262 12.104443472749216 -1 0 0 -404 151 4 0.4238 0.19226097555573238 0.6070051864264498 8.178840137751594 1 0 0 -313 121 3 -0.8476 13.713176980186857 8.464536347918953 12.326518306939699 0 0 0 -238 96 3 -0.8476 16.147179753895433 0.6588013419307613 8.092271913343968 0 0 0 -461 170 4 0.4238 9.724872597026858 0.5544258850846108 9.053145916541903 0 0 0 -354 134 4 0.4238 11.073991971501862 8.257853428140294 12.30459990822289 1 -1 0 -314 121 4 0.4238 13.814688248066297 7.503222137375749 12.582601723500172 0 0 0 -403 151 3 -0.8476 1.1872556285218714 0.5093445341888718 8.200033176326532 1 0 0 -698 249 4 0.4238 15.55803239857769 0.7459365278981882 6.259847956511043 0 1 0 -114 54 4 0.4238 7.782158286850564 4.869601692703211 12.807668425470919 0 -1 0 -697 249 3 -0.8476 15.855429109033778 0.4369326727389228 5.356480411028421 0 1 0 -606 218 4 0.4238 9.544775439662294 0.08501982626141869 5.398561718648435 0 0 0 -317 122 4 0.4238 13.333479801593976 9.740943665116738 4.24532200523119 -1 0 0 -108 52 4 0.4238 2.6709587275475806 3.9072302649054578 12.745192231166719 0 0 0 -382 144 3 -0.8476 3.147429286024961 10.109636142426924 12.262589634326233 0 -1 0 -219 89 4 0.4238 6.364020207274239 2.520405553770681 12.99540340928131 0 1 0 -670 240 3 -0.8476 6.773533755134105 3.717038175159099 16.491590206755482 1 1 0 -396 148 4 0.4238 5.803462923264418 5.197637234493128 18.99743460565577 1 0 0 -395 148 4 0.4238 6.231119807997449 5.430041501948986 17.438676906564567 1 0 0 -394 148 3 -0.8476 5.703165163684741 5.798066954915367 18.20406962093302 1 0 0 -204 84 4 0.4238 0.9285041127500067 6.081115753960207 17.765142563298816 0 0 0 -608 219 4 0.4238 3.4847098211944805 4.983851303239975 16.51022523448973 2 0 0 -203 84 4 0.4238 2.239308631405881 6.936298376846396 18.23106240529696 0 0 0 -202 84 3 -0.8476 1.7977361263740537 6.4724758132065725 17.4630234950725 0 0 0 -486 178 4 0.4238 1.5196084362896762 6.12225022226849 15.824399106036145 2 -1 0 -347 132 4 0.4238 3.6682462328407848 1.7981456998993772 14.104840128555262 0 0 0 -45 23 1 0.006123381361742108 14.708000000000002 10.1898 23.449863020791625 0 0 0 -471 173 4 0.4238 1.169657196352889 2.3243122122885453 14.225856073802426 1 0 0 -348 132 4 0.4238 3.2986057185518605 3.2227066069571335 14.81238521553265 0 0 0 -275 108 4 0.4238 3.030667138719297 2.590837305059514 17.506935704777117 0 1 0 -346 132 3 -0.8476 3.0631397880047393 2.5935970488364877 14.071588140230032 0 0 0 -572 207 4 0.4238 5.938146311728662 1.1988717244542944 18.449373741134067 2 0 0 -338 129 4 0.4238 3.072928503496896 1.7841590474751556 19.542649762121915 1 1 0 -485 178 4 0.4238 0.47678333061827677 5.47396748641097 14.747888473867437 2 -1 0 -571 207 3 -0.8476 5.4801718917026605 1.015513120679157 17.579521025148217 2 0 0 -591 213 4 0.4238 1.6285162972905645 3.4120124953752153 19.93620754678186 1 0 0 -589 213 3 -0.8476 0.8251068536873744 3.8954462084678685 20.28381032825206 1 0 0 -607 219 3 -0.8476 3.867930772442749 4.066191566694831 16.405134372982015 2 0 0 -609 219 4 0.4238 4.806032103818568 4.055085076366629 16.75132234398619 2 0 0 -180 76 4 0.4238 6.828372582015677 7.87413160734309 14.827932072927481 1 0 0 -274 108 3 -0.8476 2.2754290519199434 2.0804855419940176 17.918224542873194 0 1 0 -686 245 4 0.4238 17.05951378440882 3.718092322788279 14.110381025997988 0 0 0 -671 240 4 0.4238 7.723844896306422 3.5324942522771177 16.240882591061286 1 1 0 -672 240 4 0.4238 6.164914683475686 3.1703614971042993 15.916500506334968 1 1 0 -112 54 3 -0.8476 8.040671566798173 4.854493140691428 13.773559856960954 0 -1 0 -681 243 4 0.4238 14.923807986964198 5.253612199100808 13.101965411111607 0 0 0 -113 54 4 0.4238 7.6698060149863725 5.662965420048592 14.230545447349645 0 -1 0 -344 131 4 0.4238 10.95474300812148 4.0896914619293145 14.970342975126565 1 0 0 -343 131 3 -0.8476 10.063394350235356 3.7363576006086254 15.254338082590541 1 0 0 -345 131 4 0.4238 9.34090547780924 4.213383582128138 14.753881815078818 1 0 0 -255 101 4 0.4238 10.85824303556981 3.0901798958905475 17.415063203472258 1 1 0 -254 101 4 0.4238 10.431165704841273 2.7912121126124174 18.962593602768095 1 1 0 -309 119 4 0.4238 9.657908807892223 1.9712599592283588 15.351618323136861 0 0 0 -253 101 3 -0.8476 11.154265512428617 3.1439882841524334 18.368727773437268 1 1 0 -479 176 4 0.4238 5.403795086006659 1.4149877692142259 20.021771864299765 0 -1 0 -109 53 3 -0.8476 8.600205030653099 2.2462808893047232 19.821549314151852 -1 -1 0 -480 176 4 0.4238 6.258921142430334 0.1412548703721989 20.581229029437516 0 -1 0 -375 141 4 0.4238 9.117868061991976 1.036566241068436 18.751587159762384 1 0 0 -44 22 1 -0.0001812904321965569 16.178800000000003 7.6424 23.449863020791625 0 0 0 -110 53 4 0.4238 7.727663154061957 1.8390933537663159 20.091493343399456 -1 -1 0 -307 119 3 -0.8476 9.343792417931972 1.0220586309221074 15.332862776937171 0 0 0 -685 245 3 -0.8476 16.514983914712488 4.396701916152739 13.617453660612183 0 0 0 -635 228 4 0.4238 14.934439265290866 2.288341571568405 19.356194526021124 -1 1 0 -636 228 4 0.4238 16.2158222895273 2.6797206531874846 18.422648696940644 -1 1 0 -271 107 3 -0.8476 14.384906263459381 5.231528110011023 18.211019803516685 0 0 0 -722 257 4 0.4238 0.7841546606140447 3.2030543524924195 17.73657679021505 1 0 0 -481 177 3 -0.8476 12.581138481752648 4.859708235311564 14.646852856409735 0 -1 0 -721 257 3 -0.8476 17.60844845622247 3.454378290202139 17.230572913673747 0 0 0 -483 177 4 0.4238 13.160238723845719 4.100628436368969 14.944244840432273 0 -1 0 -723 257 4 0.4238 17.606644439674373 2.9907645897973025 16.344535049328133 0 0 0 -482 177 4 0.4238 13.012070955214067 5.324546157865892 13.873402918227042 0 -1 0 -210 86 4 0.4238 15.870038382436055 6.148820952871613 19.006015180550836 0 0 0 -208 86 3 -0.8476 16.865547237935143 6.098380167171903 19.086141002575904 0 0 0 -469 173 3 -0.8476 0.24099730438873146 2.3625139757391653 14.594820907791535 1 0 0 -209 86 4 0.4238 17.139292025421696 5.150302069211487 19.248054676505525 0 0 0 -688 246 3 -0.8476 14.623886499778722 3.6932990280304163 15.732807373833925 0 0 0 -690 246 4 0.4238 14.619196195132695 3.9139495349394897 16.70815146361856 0 0 0 -634 228 3 -0.8476 15.93174987773314 2.3544851495071337 19.324605678443945 -1 1 0 -689 246 4 0.4238 15.265375999751216 4.295738562336769 15.257869634602969 0 0 0 -662 237 4 0.4238 4.978031757165134 0.7547617838359337 14.20344931791269 0 0 0 -149 66 4 0.4238 6.142925343814942 8.825398894478063 19.325397902096977 1 -1 0 -590 213 4 0.4238 0.07861235173383108 3.2446527141465413 20.422437871943448 1 0 0 -433 161 3 -0.8476 13.453174159881309 1.2429493424526434 18.58612891404859 1 0 0 -435 161 4 0.4238 13.569356144672101 0.9791538990920698 17.628571988252272 1 0 0 -102 50 4 0.4238 6.712168198770753 6.861720337029987 19.24687390403485 2 0 0 -140 63 4 0.4238 14.018366924616625 9.69491277775119 14.008138262339143 -2 -1 0 -417 155 4 0.4238 5.208444868460392 7.220217558553598 16.73639408130369 0 0 0 -415 155 3 -0.8476 5.290910423508213 8.090179521588407 16.250219145720393 0 0 0 -416 155 4 0.4238 4.571517941560458 8.713170942042227 16.557394543089575 0 0 0 -459 169 4 0.4238 1.274864904832181 9.57147587035769 16.73714616564885 1 0 0 -217 89 3 -0.8476 6.03252642387316 1.682543967490432 13.429110083925117 0 1 0 -478 176 3 -0.8476 6.321181520041977 1.0326296477116548 20.13225702561793 0 -1 0 -361 137 3 -0.8476 1.6007303313238133 8.59744641622387 14.087757338010231 1 -1 0 -197 82 4 0.4238 11.189299229444917 2.6912260959037098 13.419027842857094 0 1 0 -650 233 4 0.4238 14.003306552648727 1.5742686356038393 16.043690746479285 1 0 0 -488 179 4 0.4238 14.200182875506746 9.953534892777244 19.839371915250766 1 -1 0 -484 178 3 -0.8476 1.310019783094791 6.016938649674422 14.852293828373476 2 -1 0 -661 237 3 -0.8476 4.352879610820145 0.25944931473696636 14.80665155844631 0 0 0 -363 137 4 0.4238 1.959463608305586 9.151048377028488 14.839313627996184 1 -1 0 -100 50 3 -0.8476 7.520229491829531 7.3048366120870165 19.635059688498004 2 0 0 -707 252 4 0.4238 11.76043130595752 9.939320694789002 19.71667383739911 0 1 0 -178 76 3 -0.8476 7.517489493276682 7.333706134334132 14.345168774847096 1 0 0 -684 244 4 0.4238 17.28192914942711 9.812564778400814 18.086534426021203 0 1 0 -36 18 1 -0.0179910439504863 13.237200000000001 7.6424 23.449863020791625 0 0 0 -276 108 4 0.4238 2.207595987778979 1.1805886699543764 17.487427077013713 0 1 0 -214 88 3 -0.8476 8.637264772060341 8.061628662502454 16.90108297131685 -1 0 0 -216 88 4 0.4238 9.630438446102557 8.174027520932198 16.932331381504746 -1 0 0 -539 196 4 0.4238 9.695497532266977 6.886264199273172 14.189789226002413 2 0 0 -538 196 3 -0.8476 10.563020232995258 6.775061520800534 14.674598753985302 2 0 0 -252 100 4 0.4238 7.685168241584919 9.610566187163585 16.889892309335206 0 0 0 -228 92 4 0.4238 11.050503228858997 8.010373029173316 15.663121686944693 0 -1 0 -226 92 3 -0.8476 11.28429273467671 8.543911989710573 16.475943851978776 0 -1 0 -227 92 4 0.4238 11.344287050217062 9.512148354407193 16.233205016457113 0 -1 0 -540 196 4 0.4238 11.161666855372657 6.168261200879016 14.151701557933738 2 0 0 -596 215 4 0.4238 12.771065336519738 7.748494590220643 16.220536748708703 1 -1 0 -215 88 4 0.4238 8.374011229887373 7.6671090745462545 16.020711214547347 -1 0 0 -234 94 4 0.4238 16.576430424719607 0.5062309843763978 19.13844592766813 0 0 0 -706 252 3 -0.8476 12.36193947812822 9.160747667168573 19.537751621413815 0 1 0 -708 252 4 0.4238 11.865171027143662 8.469425792189265 19.01306505088366 0 1 0 -373 141 3 -0.8476 9.412620718118959 0.35565490575707015 18.08114998455027 1 0 0 -272 107 4 0.4238 13.96923862413299 5.521984167683582 19.072911164078484 0 0 0 -273 107 4 0.4238 14.169684339674113 5.896953089438392 17.496254328798827 0 0 0 -362 137 4 0.4238 1.6305502404987111 7.6307855704072995 14.342077627004548 1 -1 0 -597 215 4 0.4238 13.155595108591708 6.281716998754621 15.614461099800554 1 -1 0 -519 189 4 0.4238 0.25052520571656256 7.410000747569126 19.453385808828934 1 0 0 -682 244 3 -0.8476 17.37568243426495 9.11353756111006 17.377610598188703 0 1 0 -161 70 4 0.4238 0.4276393931068581 9.645404130294276 19.94966591203612 1 0 0 -683 244 4 0.4238 16.762775639163923 8.349640967386419 17.579621185009074 0 1 0 -339 129 4 0.4238 2.953255533740337 0.7273765470433621 20.781809824703732 1 1 0 -470 173 4 0.4238 17.313495807482283 1.701791190164049 14.11457782420363 0 0 0 -595 215 3 -0.8476 13.434254199843643 7.000670331013912 16.25121582144323 1 -1 0 -649 233 3 -0.8476 13.730521799815536 0.614769911259436 16.114057992895944 1 0 0 -179 76 4 0.4238 7.376399341193584 7.418181342250472 13.358780560554386 1 0 0 -308 119 4 0.4238 9.328524040796328 0.6575663281326254 16.263946795393448 0 0 0 -663 237 4 0.4238 4.505521910089192 0.5457888494359412 15.752543276886664 0 0 0 -337 129 3 -0.8476 3.514575860727707 1.4477360756662245 20.37437556806391 1 1 0 -327 125 4 0.4238 4.963020305736973 4.844213183983858 21.800104413199907 0 1 0 -325 125 3 -0.8476 5.413526513655491 4.683300538459343 20.92195188291159 0 1 0 -326 125 4 0.4238 6.356823537007404 4.39129241653594 21.079824846511343 0 1 0 -535 195 3 -0.8476 2.983237344424761 5.852992742968334 19.86140129850823 1 0 0 -537 195 4 0.4238 3.8877052935337013 5.573139871228802 20.183303829725734 1 0 0 -2 1 1 0.01681964573718448 1.4708000000000014 2.5475000000000003 23.449863020791625 0 0 0 -1 1 1 0.009530892217576416 1.7763568394002505e-15 1.7763568394002505e-15 23.449863020791625 0 0 0 -11 6 1 -0.01524214201230506 2.941600000000001 5.094900000000001 23.449863020791625 0 0 0 -3 2 1 0.01449029221643637 1.7763568394002505e-15 5.094900000000001 23.449863020791625 0 0 0 -10 5 1 0.00691884776850595 4.4124 2.5474999999999994 23.449863020791625 0 0 0 -9 5 1 0.0195314219644623 2.9415999999999993 1.7763568394002505e-15 23.449863020791625 0 0 0 -536 195 4 0.4238 2.319795753718221 5.1326684425952385 20.063837216279858 1 0 0 -516 188 4 0.4238 8.108138722594667 5.927016819163718 20.411810376184487 1 -1 0 -111 53 4 0.4238 8.496355497036129 3.238090310367132 19.747187863764335 -1 -1 0 -515 188 4 0.4238 9.362944894589518 4.883962319684104 20.47605173012904 1 -1 0 -514 188 3 -0.8476 8.36740867133632 4.961263964951319 20.421886089225346 1 -1 0 -168 72 4 0.4238 11.376288543712512 4.443050222600666 19.712926478310834 0 0 0 -166 72 3 -0.8476 11.119316529543537 5.1744679228851975 20.344587376759364 0 0 0 -17 9 1 -0.0001196702448092049 5.8832 0 23.449863020791625 0 0 0 -19 10 1 -0.04577843504398507 5.8832 5.094900000000001 23.449863020791625 0 0 0 -18 9 1 0.005448749793554232 7.354000000000001 2.5474999999999994 23.449863020791625 0 0 0 -27 14 1 0.01621780275369726 8.8248 5.094900000000001 23.449863020791625 0 0 0 -26 13 1 0.009139377486030886 10.2956 2.5474999999999994 23.449863020791625 0 0 0 -25 13 1 0.005843126768876098 8.8248 0 23.449863020791625 0 0 0 -434 161 4 0.4238 12.577274249871005 1.7121343654934205 18.69868691361602 1 0 0 -41 21 1 -0.0175826914366148 14.708 0 23.449863020791625 0 0 0 -42 21 1 0.003543843405838151 16.178800000000003 2.5474999999999994 23.449863020791625 0 0 0 -43 22 1 -0.008930438763612256 14.708000000000002 5.0949 23.449863020791625 0 0 0 -33 17 1 -0.01319754578259268 11.7664 1.7763568394002505e-15 23.449863020791625 0 0 0 -35 18 1 0.005624883561307313 11.7664 5.094900000000001 23.449863020791625 0 0 0 -34 17 1 -0.001833361793814021 13.237200000000001 2.5474999999999994 23.449863020791625 0 0 0 -518 189 4 0.4238 1.7262219883909424 7.436086788297749 20.15214607725663 1 0 0 -101 50 4 0.4238 8.106166655216015 7.636318994291072 18.895600145997378 2 0 0 -517 189 3 -0.8476 0.8975282537764131 7.9667901703236526 19.974321127200675 1 0 0 -150 66 4 0.4238 4.649148498694868 8.243938426512141 19.63710700967118 1 -1 0 -37 19 1 0.008059123604893179 11.7664 10.1898 23.449863020791625 0 0 0 -13 7 1 0.003562500361631949 2.941600000000001 10.1898 23.449863020791625 0 0 0 -4 2 1 0.01118045101209775 1.4708000000000006 7.6424 23.449863020791625 0 0 0 -12 6 1 -0.008187862475270539 4.4124 7.6424 23.449863020791625 0 0 0 -148 66 3 -0.8476 5.168232450516505 9.047906137187535 19.346953256748833 1 -1 0 -5 3 1 0.01564426943939494 1.7763568394002505e-15 10.1898 23.449863020791625 0 0 0 -167 72 4 0.4238 11.942045323115195 5.649130151908711 20.657340273077285 0 0 0 -328 126 3 -0.8476 13.536656944721523 6.706920305720269 20.30923123396737 0 1 0 -329 126 4 0.4238 14.033035625445095 6.901107759295683 21.155340398492882 0 1 0 -330 126 4 0.4238 13.32248868402487 7.565726120598325 19.84383926291113 0 1 0 -28 14 1 0.005135353479473132 10.2956 7.6424 23.449863020791625 0 0 0 -29 15 1 -0.01709114553122559 8.8248 10.1898 23.449863020791625 0 0 0 -20 10 1 0.004420735120240576 7.354000000000001 7.6424 23.449863020791625 0 0 0 -21 11 1 -8.295950892680149e-05 5.8832 10.1898 23.449863020791625 0 0 0 -457 169 3 -0.8476 2.137690785024048 9.831264578841258 16.303498875411698 1 0 0 -573 207 4 0.4238 5.848305837212314 0.1762190034544807 17.17943778184179 2 0 0 -651 233 4 0.4238 14.491471777300028 0.03037914374267814 15.83219648354528 1 0 0 -218 89 4 0.4238 6.5919786085182075 0.9091158018046296 13.131077697911964 0 1 0 -54 27 2 0.009538003210554242 1.4708 12.7373 2.4018 0 0 0 -55 28 2 -0.003172379929243049 0 15.2847 2.4018 0 0 0 -62 31 2 -0.00186117057999337 4.4124 12.7373 2.4018 0 0 0 -63 32 2 0.00758887481169554 2.9416 15.2847 2.4018 0 0 0 -192 80 4 0.4238 4.794387147708667 14.909075171120765 5.419182095600811 0 0 0 -119 56 4 0.4238 3.2500817867314398 11.832800805491306 6.2682928485004785 0 -1 0 -118 56 3 -0.8476 2.709695006424336 11.627182945371326 5.452384520275485 0 -1 0 -191 80 4 0.4238 3.8571863060224443 13.57325796518277 5.356927851433144 0 0 0 -190 80 3 -0.8476 3.8530200194608413 14.572485850889231 5.396004384825564 0 0 0 -98 49 4 0.4238 2.2766564815872377 15.778957767705766 5.556621305001019 1 0 0 -120 56 4 0.4238 1.8997669381619913 12.21338080817393 5.432566828266767 0 -1 0 -97 49 3 -0.8476 1.6582359104391984 16.291326734509507 6.152472357053496 1 0 0 -244 98 3 -0.8476 0.3924528377280096 13.052383693685869 5.275030660375085 0 -1 0 -99 49 4 0.4238 1.9764418005425044 16.22605313800913 7.098245454454695 1 0 0 -631 227 3 -0.8476 8.778943735028687 10.474788944453667 12.685594012363595 -1 0 0 -295 115 3 -0.8476 6.836426798704437 14.252095160705379 5.316785643293747 0 0 0 -296 115 4 0.4238 6.3380790395823565 13.385929350133972 5.27926186731909 0 0 0 -336 128 4 0.4238 9.504568664514785 15.01506830678913 4.725006859909346 0 0 0 -70 35 2 0.01569918460207732 7.354000000000001 12.7373 2.4018 0 0 0 -71 36 2 0.01622723354682065 5.8832 15.2847 2.4018 0 0 0 -78 39 2 0.01233699237017652 10.2956 12.7373 2.4018 0 0 0 -79 40 2 -0.0123167339477786 8.8248 15.2847 2.4018 0 0 0 -334 128 3 -0.8476 9.804960251945063 14.585282143844777 5.576505038341256 0 0 0 -335 128 4 0.4238 10.764689305944286 14.811244909035093 5.743428161519318 0 0 0 -656 235 4 0.4238 11.274876877297288 11.589128799416661 6.812142647899859 0 0 0 -655 235 3 -0.8476 11.388256990917405 11.907831882964768 5.871092838018554 0 0 0 -657 235 4 0.4238 10.511574676431575 12.241068556600506 5.524131235030396 0 0 0 -331 127 3 -0.8476 8.647876026470513 11.72968917644971 5.372752090789252 0 0 0 -225 91 4 0.4238 13.252704815948258 12.484966119923902 5.4991907056523175 -1 -1 0 -223 91 3 -0.8476 14.108667496093203 12.961787209464076 5.699123243872336 -1 -1 0 -86 43 2 0.004517062113848894 13.237200000000001 12.7373 2.4018 0 0 0 -87 44 2 0.001691435347730985 11.7664 15.2847 2.4018 0 0 0 -94 47 2 0.00685931941051703 16.178800000000003 12.7373 2.4018 0 0 0 -95 48 2 0.006949345406057055 14.708000000000002 15.2847 2.4018 0 0 0 -246 98 4 0.4238 0.38146479586720616 13.911666462643149 4.763645752254332 0 -1 0 -224 91 4 0.4238 14.421312095518909 12.71496419083952 6.616368538934622 -1 -1 0 -283 111 3 -0.8476 15.628193884175449 15.67958654625237 5.712183668752193 -1 0 0 -285 111 4 0.4238 15.20823137338435 14.77263604396369 5.744946721536371 -1 0 0 -284 111 4 0.4238 15.39730073469381 16.18406388803546 6.544167099225616 -1 0 0 -135 61 4 0.4238 17.181734297894028 11.50938194605289 5.376919239592664 -1 0 0 -128 59 4 0.4238 12.510696850559 13.400814682569763 12.12154569673403 0 0 0 -641 230 4 0.4238 16.460174864867515 11.555259291722754 11.513987660535511 1 0 0 -694 248 3 -0.8476 5.646664121771563 12.003829343647613 5.265517005823366 1 0 0 -508 186 3 -0.8476 11.874631242554559 19.183954362495257 12.757848230170808 -1 0 0 -365 138 4 0.4238 6.888120955508712 13.350278100146872 11.983484682294058 0 -1 0 -56 28 2 -0.007346483191423765 1.4708 17.8322 2.4018 0 0 0 -64 32 2 -0.007040366496871621 4.4124 17.8322 2.4018 0 0 0 -264 104 4 0.4238 2.890774254525348 19.395952063865504 5.416360014788498 0 -1 0 -262 104 3 -0.8476 1.9229167571391381 19.551713032251147 5.613835629405332 0 -1 0 -303 117 4 0.4238 12.119648008726836 10.348886671661969 8.982817094596912 0 0 0 -263 104 4 0.4238 1.3632164588516946 19.027705040806982 4.971845369641502 0 -1 0 -696 248 4 0.4238 4.931090248366684 11.920720405779006 5.959093966041219 1 0 0 -555 201 4 0.4238 0.1476370801517249 17.587643965474964 5.9820586175388515 1 -1 0 -460 170 3 -0.8476 10.511653292375941 20.36092252510843 9.28183703745981 0 -1 0 -357 135 4 0.4238 5.30802705175001 20.077669929184395 5.47750029282528 0 -1 0 -355 135 3 -0.8476 4.502197418039438 19.485574693167184 5.469578450808493 0 -1 0 -642 230 4 0.4238 17.59514938340467 12.494288109655482 10.809223899354208 1 0 0 -440 163 4 0.4238 6.746420411262218 15.956533676323577 5.22022015080474 0 0 0 -441 163 4 0.4238 5.7446670540994935 16.848265237800078 6.151849013066668 0 0 0 -248 99 4 0.4238 0.19491065621647194 15.263151600771593 12.384493561505723 1 0 0 -439 163 3 -0.8476 6.316582565899266 16.852550879871938 5.331546912613838 0 0 0 -72 36 2 0.007179830066346712 7.354000000000001 17.8322 2.4018 0 0 0 -80 40 2 0.009767193963479517 10.2956 17.8322 2.4018 0 0 0 -593 214 4 0.4238 7.884845767551953 18.242346210560054 5.215564680586794 1 0 0 -592 214 3 -0.8476 8.441708788539396 19.06278952840712 5.34509407825288 1 0 0 -594 214 4 0.4238 9.407518236319975 18.806924915027857 5.3868767845437215 1 0 0 -229 93 3 -0.8476 11.002931909959898 17.85349899482245 5.534832624443298 -1 -1 0 -356 135 4 0.4238 4.727932098205787 18.62143419085674 5.019794724809724 0 -1 0 -443 164 4 0.4238 12.40229864797583 14.881890635527546 6.532324378182912 -1 0 0 -230 93 4 0.4238 11.272239561806135 18.40387542301247 6.325124179849419 -1 -1 0 -442 164 3 -0.8476 12.249392559907344 15.43317503022671 5.712134600968626 -1 0 0 -444 164 4 0.4238 13.129546035940322 15.725685437724305 5.338276770112374 -1 0 0 -231 93 4 0.4238 11.438767335047864 16.955174113268875 5.59016816824532 -1 -1 0 -88 44 2 -0.004661733698708054 13.237200000000001 17.8322 2.4018 0 0 0 -96 48 2 0.004146602187371051 16.178800000000003 17.8322 2.4018 0 0 0 -553 201 3 -0.8476 17.01816778562073 17.995397600438885 5.50550827227041 0 -1 0 -554 201 4 0.4238 16.440634429393626 17.270603716767287 5.129835074976055 0 -1 0 -699 249 4 0.4238 15.700109015732405 19.83239470687886 5.2730815881929605 0 0 0 -247 99 3 -0.8476 17.336782813381703 15.9758100387841 12.86878129068549 0 0 0 -527 192 4 0.4238 8.400400049346944 19.554495577047934 12.685963916073062 0 -1 0 -245 98 4 0.4238 0.14624632377865007 13.228544728434645 6.228106595314394 0 -1 0 -633 227 4 0.4238 7.8446313240677465 10.215293497567252 12.929977075896192 -1 0 0 -123 57 4 0.4238 7.0746556208220435 19.34524620318107 10.872591375491558 0 -1 0 -724 258 3 -0.8476 4.234176441183506 12.039368920513985 7.672701195843418 1 -1 0 -725 258 4 0.4238 4.137223358179028 11.154093396315286 8.127551251299957 1 -1 0 -342 130 4 0.4238 3.3490444756314663 14.507070913866091 7.917816047124389 1 0 0 -340 130 3 -0.8476 2.475251769304553 14.763988319874148 8.330709130564067 1 0 0 -341 130 4 0.4238 2.5667527473696508 14.772232456574866 9.326480518807314 1 0 0 -364 138 3 -0.8476 6.231328463002679 12.764543730928395 11.508572517819397 0 -1 0 -726 258 4 0.4238 4.70687708932946 12.676759931947513 8.28121621344766 1 -1 0 -503 184 4 0.4238 0.626740782878561 12.112155305683151 8.36175181603283 2 0 0 -502 184 3 -0.8476 0.3530019095059348 13.026562250348038 8.063539643828118 2 0 0 -504 184 4 0.4238 1.1590491426400296 13.616383360322493 8.014514200238665 2 0 0 -413 154 4 0.4238 10.310246047781114 12.645425170155443 9.649734635743975 -1 -1 0 -278 109 4 0.4238 2.0689926172355833 13.226423725069202 11.044416560097394 1 0 0 -270 106 4 0.4238 14.518258075018746 16.25012768269104 11.329980010628349 -1 0 0 -719 256 4 0.4238 14.442688875729713 18.00809488214158 8.65135922354247 0 0 0 -132 60 4 0.4238 13.719412563278548 19.25471490200023 12.012858419540821 0 -1 0 -297 115 4 0.4238 7.758248037390944 14.09126118228873 5.669459107658047 0 0 0 -392 147 4 0.4238 8.440775970159434 10.837303720059037 8.832462502385212 1 -1 0 -260 103 4 0.4238 6.064521948562677 13.07373599605862 9.675228220765085 1 0 0 -548 199 4 0.4238 8.329731669573114 16.02435016298476 8.300652493750043 0 0 0 -302 117 4 0.4238 10.534927101610386 10.641668809892366 8.71905928310815 0 0 0 -259 103 3 -0.8476 6.039295026524322 13.683249827267247 8.882849726337565 1 0 0 -261 103 4 0.4238 6.968645563455479 13.97585610861691 8.65769716313075 1 0 0 -640 230 3 -0.8476 16.65021625418278 12.46084907650203 11.134783599664194 1 0 0 -532 194 3 -0.8476 8.625524965508806 14.111716138349044 7.926539176924266 1 -1 0 -235 95 3 -0.8476 2.8058865877200936 17.909202481046883 10.86408017002096 1 -1 0 -533 194 4 0.4238 9.285608328477988 13.74349101780916 8.581291434167639 1 -1 0 -534 194 4 0.4238 9.031378094953077 14.119395432885998 7.012632675162272 1 -1 0 -621 223 4 0.4238 11.759447009759235 16.637770265234245 8.125266626319792 0 -1 0 -121 57 3 -0.8476 7.405164265328445 20.132366073683155 11.393370019265204 0 -1 0 -269 106 4 0.4238 15.69906664349124 15.938606379638701 12.414079729103287 -1 0 0 -265 105 3 -0.8476 13.858511390467266 12.2257643539824 11.862964948226105 1 -1 0 -547 199 3 -0.8476 8.479300024438404 16.994101102650657 8.493567490661286 0 0 0 -619 223 3 -0.8476 11.181389829059919 17.28631938477271 8.620479805635687 0 -1 0 -279 109 4 0.4238 2.3342044958643817 11.616099100570484 10.98832580613683 1 0 0 -293 114 4 0.4238 5.974133299119694 10.444262483041067 10.556494238721228 0 0 0 -695 248 4 0.4238 5.440253808833983 11.395549814498784 4.499102405585278 1 0 0 -494 181 4 0.4238 14.091170402355985 15.83372339966198 8.056796739388613 0 -1 0 -131 60 4 0.4238 14.375504558444222 19.40171818823153 10.52471778468597 0 -1 0 -715 255 3 -0.8476 12.148806693669629 19.94644025668999 7.2400816171341615 1 0 0 -239 96 4 0.4238 15.531142815012778 20.3309642839673 8.438322792523895 0 -1 0 -414 154 4 0.4238 10.783851523474887 13.801560969805426 10.70124633178135 -1 -1 0 -648 232 4 0.4238 13.545815145696485 13.70677775084171 8.047430920645967 1 -1 0 -646 232 3 -0.8476 12.89354184562956 14.45291909331316 8.180909241857698 1 -1 0 -565 205 3 -0.8476 16.571290714132587 15.380788191495872 9.978390686128293 0 0 0 -566 205 4 0.4238 16.486697788555325 14.396887548242892 10.135820192964106 0 0 0 -544 198 3 -0.8476 14.802744123952923 12.494905050684105 8.220714343430616 0 0 0 -546 198 4 0.4238 15.69958392914293 12.648272017127166 8.635636336988226 0 0 0 -545 198 4 0.4238 14.327341303672132 11.766564694345089 8.71418549827662 0 0 0 -495 181 4 0.4238 15.64406667138792 16.008563289169672 8.530685968345766 0 -1 0 -647 232 4 0.4238 12.174548141627941 14.158466532425988 8.81047248263604 1 -1 0 -493 181 3 -0.8476 14.888021746634598 16.43755314652351 8.036353729476255 0 -1 0 -301 117 3 -0.8476 11.444178994842403 10.634235762851835 8.302874111374269 0 0 0 -127 59 3 -0.8476 11.835398099674071 14.130588554568469 12.228336617000755 0 0 0 -266 105 4 0.4238 13.437837209675466 11.718053793881642 11.111124693406984 1 -1 0 -391 147 3 -0.8476 9.099036309266321 11.055510230198061 9.552934514493218 1 -1 0 -465 171 4 0.4238 4.507962365618935 16.739930651989027 12.02419305834093 1 1 0 -333 127 4 0.4238 7.671719130956259 11.719916025379499 5.589601145029327 0 0 0 -366 138 4 0.4238 5.3810066147385625 12.723574451940152 12.033239886655569 0 -1 0 -267 105 4 0.4238 14.695595476843678 12.667206008724747 11.539822065683758 1 -1 0 -157 69 3 -0.8476 5.628213484046431 19.7062241141079 8.476653698924062 0 -1 0 -412 154 3 -0.8476 10.588274339586592 13.60163970345705 9.74115068987977 -1 -1 0 -393 147 4 0.4238 8.752170977546312 10.727795337016143 10.43173357510416 1 -1 0 -405 151 4 0.4238 1.4893493439895436 20.379210451086568 7.3946095610145495 1 -1 0 -448 166 3 -0.8476 2.31094841939137 15.22894706649686 11.40418724815192 1 -1 0 -449 166 4 0.4238 2.4578750502157516 15.152016401940413 12.390338787322065 1 -1 0 -584 211 4 0.4238 7.457640650200761 17.192133224007062 11.208629944424919 0 0 0 -585 211 4 0.4238 7.4183339086411015 17.350678325691767 9.583838609015473 0 0 0 -318 122 4 0.4238 12.677059363876626 10.345851943535926 5.612738242773594 -1 0 0 -450 166 4 0.4238 2.5278285080124174 16.1586189746941 11.106405599802631 1 -1 0 -159 69 4 0.4238 5.396739043963939 19.542646637149865 7.517663044565708 0 -1 0 -277 109 3 -0.8476 1.9668284394083102 12.400955373279421 10.489290044953318 1 0 0 -174 74 4 0.4238 2.093131136233991 20.2908531347256 12.509936900888619 1 -1 0 -158 69 4 0.4238 5.72722641111533 18.830742461490534 8.949654740651088 0 -1 0 -236 95 4 0.4238 2.955886959156451 18.56642796559528 10.125462919315872 1 -1 0 -332 127 4 0.4238 8.992796984842672 10.791435697737592 5.34607589753084 0 0 0 -567 205 4 0.4238 17.492436254495992 15.680156746258747 10.227126720885458 0 0 0 -268 106 3 -0.8476 14.72205779127257 15.84637768385046 12.22186102297119 -1 0 0 -144 64 4 0.4238 11.609867542673534 17.63780259318367 11.964952217223086 0 -1 0 -143 64 4 0.4238 10.437547809860437 16.53467569974479 11.690352189869234 0 -1 0 -620 223 4 0.4238 11.248363625488201 17.110068003656618 9.60254814088919 0 -1 0 -142 64 3 -0.8476 11.326107809904766 16.875494366073085 11.383255826277036 0 -1 0 -129 59 4 0.4238 12.300763358612933 15.015557263662124 12.2446824789516 0 0 0 -549 199 4 0.4238 9.422230282072096 17.23756950681282 8.266389738781958 0 0 0 -583 211 3 -0.8476 6.97427468797035 17.61248426688647 10.440734635242483 0 0 0 -718 256 3 -0.8476 13.966610727938773 18.787186536259128 9.059246432430188 0 0 0 -237 95 4 0.4238 2.482978017919997 18.391152324186773 11.678608951138568 1 -1 0 -462 170 4 0.4238 10.307703252681602 19.40879670268801 9.05410643052076 0 -1 0 -130 60 3 -0.8476 14.46327699006248 19.66514390094484 11.485397145457227 0 -1 0 -720 256 4 0.4238 13.217661837076776 19.070863155758513 8.460408162150607 0 0 0 -383 144 4 0.4238 3.5533021915261043 10.935137256889309 12.654783731389125 0 -1 0 -133 61 3 -0.8476 16.51149780470187 10.788229938237286 5.201627541800947 -1 0 0 -511 187 3 -0.8476 1.1543831961823052 10.310487624376274 8.191850041914243 1 0 0 -134 61 4 0.4238 15.632698323193418 11.200996122194294 4.9621749152925725 -1 0 0 -716 255 4 0.4238 11.626630842918797 20.339515205022618 7.996935994482277 1 0 0 -512 187 4 0.4238 1.567722559344666 10.205106901475968 7.287390743726031 1 0 0 -509 186 4 0.4238 10.912595818989244 19.417924622524666 12.89837775340388 -1 0 0 -568 206 3 -0.8476 6.485313610696203 14.44523352047762 16.559346762808755 1 0 0 -569 206 4 0.4238 5.877025478161448 14.853591461355627 17.239958916387955 1 0 0 -304 118 3 -0.8476 3.972168127351238 15.654660056945955 17.403540948690193 1 -1 0 -305 118 4 0.4238 3.3854131498127042 14.920622411377614 17.06162240739048 1 -1 0 -418 156 3 -0.8476 2.2734537776824832 13.394090298029402 17.756318894272294 0 0 0 -306 118 4 0.4238 3.723466580375299 16.51489113835542 16.958399519713794 1 -1 0 -501 183 4 0.4238 2.8455782661452247 12.338053980852902 14.176040664713545 0 -1 0 -445 165 3 -0.8476 5.729110891648391 12.122083027826067 15.433974986322738 1 -1 0 -463 171 3 -0.8476 4.549155758711698 16.77122254564855 13.022854621887307 1 1 0 -172 74 3 -0.8476 2.0677673094230764 19.527911145364634 13.155909715455525 1 -1 0 -489 179 4 0.4238 14.886763033339717 10.902943702023924 18.70189284494204 1 -1 0 -419 156 4 0.4238 1.6504734693675003 13.234408025086623 18.52208606851008 0 0 0 -446 165 4 0.4238 5.710179429818999 13.041573185918448 15.82663266450181 1 -1 0 -420 156 4 0.4238 3.1335652597928223 12.910968687196343 17.92004363905744 0 0 0 -499 183 3 -0.8476 3.6979504775468945 12.369149009344994 13.654029663057878 0 -1 0 -500 183 4 0.4238 4.473726698288414 12.401810668166792 14.284194212701715 0 -1 0 -250 100 3 -0.8476 7.609604863953975 10.606171102951322 16.945230673113805 0 0 0 -147 65 4 0.4238 13.61668681394621 19.964324916590904 19.533511237350798 0 -1 0 -146 65 4 0.4238 12.536466740647986 19.339889174664197 20.586997674791956 0 -1 0 -570 206 4 0.4238 7.376196607403398 14.262759769403841 16.97532363052286 1 0 0 -323 124 4 0.4238 8.730985930270878 15.01364577963519 18.921207974437056 1 1 0 -324 124 4 0.4238 9.459353552713571 15.212836705232725 17.473301605982858 1 1 0 -322 124 3 -0.8476 8.813624638926065 14.65274321341759 17.992272333045058 1 1 0 -200 83 4 0.4238 10.388442485410472 11.91097015701038 16.806022211892135 -1 0 0 -623 224 4 0.4238 6.927586929691289 14.247240193752283 14.41222893771625 1 -1 0 -551 200 4 0.4238 12.247394341229853 11.259529069604119 14.84681275368594 1 0 0 -201 83 4 0.4238 9.71192070215314 12.977793729481439 17.840834618671714 -1 0 0 -199 83 3 -0.8476 9.899149161698215 12.010006135076521 17.672503104553247 -1 0 0 -312 120 4 0.4238 11.79495765458046 13.369509996222956 18.772893074029064 -1 0 0 -624 224 4 0.4238 7.897178590463072 15.319195662378577 13.652340180508801 1 -1 0 -350 133 4 0.4238 16.208874637827858 18.83362085868009 21.47129005078417 0 -1 0 -126 58 4 0.4238 8.88511907083734 13.272142299537386 13.66818822412786 0 -1 0 -622 224 3 -0.8476 7.593373444769949 14.366747565469286 13.67571894110038 1 -1 0 -550 200 3 -0.8476 11.432996415804167 11.567553927000933 15.33862353821482 1 0 0 -552 200 4 0.4238 10.76952107398665 11.935576775479335 14.687194082211969 1 0 0 -124 58 3 -0.8476 9.764955887504145 12.797152211212811 13.684703994662227 0 -1 0 -145 65 3 -0.8476 13.361959064058402 19.150230676335642 20.05540166992056 0 -1 0 -40 20 1 -0.006425533623795996 13.237200000000001 17.832199999999997 23.449863020791625 0 0 0 -599 216 4 0.4238 15.202481084467259 12.24900078170297 16.690922642575146 0 1 0 -251 100 4 0.4238 8.439342401574516 10.980938867010675 17.358856275145612 0 0 0 -704 251 4 0.4238 16.305154322814072 16.042350718561647 17.631988502422384 1 0 0 -703 251 3 -0.8476 16.0883225484333 16.255856181651623 16.67941162794245 1 0 0 -705 251 4 0.4238 15.715587557055152 15.442833175152185 16.232124973929633 1 0 0 -48 24 1 -0.02029044178834072 16.178800000000003 17.8322 23.449863020791625 0 0 0 -559 203 3 -0.8476 15.105531419639098 13.835234878317607 15.170664799706675 0 -1 0 -561 203 4 0.4238 14.406014847882542 14.34932009538237 14.674283203645347 0 -1 0 -675 241 4 0.4238 17.437788579674944 14.421546806543976 19.79224658208944 1 -1 0 -222 90 4 0.4238 15.365101969084085 15.332074787573918 19.959893780942252 0 0 0 -598 216 3 -0.8476 14.485446191543312 11.647768322089009 17.04360100536762 0 1 0 -177 75 4 0.4238 3.61134855335209 11.579252278014556 19.453192026472223 0 -1 0 -310 120 3 -0.8476 12.381985872710548 13.80369947515285 18.089607987476125 -1 0 0 -458 169 4 0.4238 2.6933087112285694 10.351514807091242 16.952058213771583 1 0 0 -139 63 3 -0.8476 13.691362264873232 10.627931433301129 14.158294798087477 -2 -1 0 -614 221 4 0.4238 11.61650220566129 15.485182333983216 17.966722851607205 1 -1 0 -600 216 4 0.4238 13.914747640475733 11.329877307455188 16.286467756847514 0 1 0 -617 222 4 0.4238 13.259523186751528 14.51825781874507 19.356416644998088 0 -1 0 -311 120 4 0.4238 12.776789012062968 13.102786397427105 17.495594179094766 -1 0 0 -530 193 4 0.4238 1.6281735604033576 12.886011322673935 16.268039063851113 1 0 0 -141 63 4 0.4238 13.630765327041322 11.105034290734396 13.28153613591018 -2 -1 0 -531 193 4 0.4238 0.4467031724535419 12.527812716084183 15.199183538889944 1 0 0 -399 149 4 0.4238 6.486830695241165 16.029581701860693 15.666779418386291 0 -1 0 -380 143 4 0.4238 3.5853869202872657 18.660092474563687 18.603647711199425 1 -1 0 -464 171 4 0.4238 4.023461569086171 16.009792558697868 13.40215734502378 1 1 0 -428 159 4 0.4238 9.469055750500404 10.667524387442267 20.937661270126558 1 -1 0 -397 149 3 -0.8476 6.413895340325838 16.8360319627653 15.07998984725994 0 -1 0 -319 123 3 -0.8476 0.7829907556311054 16.744941337967973 15.272421110502437 1 0 0 -398 149 4 0.4238 5.749127839593244 16.66081301160753 14.353776938898731 0 -1 0 -528 192 4 0.4238 8.975850745071186 20.350056923475165 13.990790392092903 0 -1 0 -321 123 4 0.4238 0.12521342288041218 16.277401530292295 15.862964127879662 1 0 0 -490 180 3 -0.8476 3.125563432540245 18.468684529246257 16.74556745319216 1 -1 0 -491 180 4 0.4238 3.575636793388386 18.624126139932855 15.8662072375943 1 -1 0 -492 180 4 0.4238 2.578632077563288 19.27047397837691 16.986406012030017 1 -1 0 -659 236 4 0.4238 1.0298389225267837 20.168025384298502 20.026919057347232 2 -1 0 -249 99 4 0.4238 0.16814848071124128 16.21206933125259 13.713202558066024 1 0 0 -164 71 4 0.4238 0.5299522359953556 20.257624996360576 17.55648066935482 0 -1 0 -162 70 4 0.4238 16.66913392996693 10.45829253707763 19.795901801640834 0 0 0 -371 140 4 0.4238 11.056255566760345 16.598270748160388 15.718911806822456 0 -1 0 -370 140 3 -0.8476 11.298560558575987 16.404137638756527 14.768331949474652 0 -1 0 -610 220 3 -0.8476 9.182998099495135 16.844324083314575 13.063635808058317 1 -1 0 -154 68 3 -0.8476 9.372552675513472 16.050092330482723 20.09128772182719 0 0 0 -155 68 4 0.4238 9.045313534743997 16.990624622451623 20.000103598074276 0 0 0 -156 68 4 0.4238 10.11796075622463 15.89226417482912 19.443632058888397 0 0 0 -612 220 4 0.4238 9.912940585757283 16.62881769597969 13.71228285972464 1 -1 0 -183 77 4 0.4238 7.463961847985207 18.60237515839614 19.98843047486115 0 -1 0 -629 226 4 0.4238 6.710399312260268 18.123336806911855 16.079630988721004 1 -1 0 -182 77 4 0.4238 7.757164552671424 18.810844945497134 18.395570465863837 0 -1 0 -181 77 3 -0.8476 8.125126014517141 18.452044538789227 19.253401321364763 0 -1 0 -611 220 4 0.4238 8.931884466842028 17.808185361298875 13.152595651819967 1 -1 0 -628 226 3 -0.8476 6.9796091824851425 18.952004521134636 16.570383047183572 1 -1 0 -630 226 4 0.4238 7.708609412032784 19.4156379445819 16.06679113644326 1 -1 0 -487 179 3 -0.8476 15.066619024936566 10.249951535799466 19.437593400150895 1 -1 0 -526 192 3 -0.8476 9.129233109396537 19.581112471942753 13.37014199224269 0 -1 0 -151 67 3 -0.8476 17.426283060222275 19.58522448708249 14.435121464885997 -2 -2 0 -160 70 3 -0.8476 0.01506610403255687 10.548473719534147 19.830294631268465 1 0 0 -351 133 4 0.4238 15.056477500508233 18.63959592950024 20.330692470756837 0 -1 0 -372 140 4 0.4238 12.170052868259033 16.843340153646995 14.550139731531836 0 -1 0 -473 174 4 0.4238 14.26517035940876 17.98252701799394 14.507717382131688 0 -1 0 -669 239 4 0.4238 15.647005666799474 17.715015917343795 16.152341030706786 1 0 0 -220 90 3 -0.8476 16.219792055920426 15.707023482600887 19.60084001936226 0 0 0 -221 90 4 0.4238 16.33803818547856 16.64326825776226 19.931693947174367 0 0 0 -349 133 3 -0.8476 16.000726312606744 18.426710693303725 20.581851466927844 0 -1 0 -176 75 4 0.4238 4.728802867281302 10.760075907012997 18.588971835799967 0 -1 0 -472 174 3 -0.8476 13.537149582394218 17.542196784550853 13.982262808143558 0 -1 0 -286 112 3 -0.8476 12.565689798467716 18.517223262424135 17.37055509192227 0 -1 0 -287 112 4 0.4238 12.767092649586525 18.693595832778726 18.334054128623215 0 -1 0 -288 112 4 0.4238 13.312023375950227 18.86734630158713 16.80451492455031 0 -1 0 -667 239 3 -0.8476 15.34738402069065 18.575704886300255 15.74070654907211 1 0 0 -557 202 4 0.4238 2.0877847893502692 15.917637143334856 14.598779519777349 1 0 0 -668 239 4 0.4238 16.102271316982648 18.97804359363653 15.222758820554837 1 0 0 -233 94 4 0.4238 16.939408664150182 19.300736366917782 19.285818625681394 0 -1 0 -232 94 3 -0.8476 17.251185745369266 20.17960735549295 18.92473073318461 0 -1 0 -556 202 3 -0.8476 2.5142033450925534 15.10859384094593 14.194283647198105 1 0 0 -613 221 3 -0.8476 11.029798398400157 16.24252383347896 17.67998671968566 1 -1 0 -615 221 4 0.4238 11.597398207517758 17.002005745636787 17.362143868985218 1 -1 0 -447 165 4 0.4238 6.2756188615712825 11.521571558695248 16.017683721626977 1 -1 0 -453 167 4 0.4238 3.215029455130721 15.987095453067399 19.079850682663047 0 0 0 -452 167 4 0.4238 2.0544632500236664 15.323519686230991 20.017604338312154 0 0 0 -451 167 3 -0.8476 2.772338132809199 16.01844856447551 19.975979335062384 0 0 0 -427 159 3 -0.8476 10.261611448686569 11.049130758551382 20.462021892602714 1 -1 0 -429 159 4 0.4238 10.007428161019474 11.279799732432494 19.52277538343466 1 -1 0 -14 7 1 0.003164654221259076 4.4124 12.7373 23.449863020791625 0 0 0 -7 4 1 0.009893054359739757 1.7763568394002505e-15 15.2847 23.449863020791625 0 0 0 -6 3 1 0.007054820838538483 1.4708000000000014 12.7373 23.449863020791625 0 0 0 -15 8 1 0.01742682861283385 2.941600000000001 15.2847 23.449863020791625 0 0 0 -410 153 4 0.4238 10.111531319873574 14.412553872150411 20.82849386163515 1 -1 0 -411 153 4 0.4238 10.469141456583753 12.84237118855151 21.09917747701026 1 -1 0 -23 12 1 0.002267061274119069 5.8832 15.2847 23.449863020791625 0 0 0 -22 11 1 -0.00588542885415537 7.354000000000001 12.7373 23.449863020791625 0 0 0 -31 16 1 0.004565600593305302 8.8248 15.2847 23.449863020791625 0 0 0 -30 15 1 -0.005925222637524864 10.2956 12.737299999999998 23.449863020791625 0 0 0 -409 153 3 -0.8476 10.837769824697997 13.725395752659518 20.80869263231772 1 -1 0 -674 241 4 0.4238 0.39525518297454587 12.95332622295135 20.169962624276398 2 -1 0 -673 241 3 -0.8476 0.6270046999503937 13.886923561797822 19.896670228457296 2 -1 0 -616 222 3 -0.8476 13.68828360729474 14.607480608256637 20.25542035696146 0 -1 0 -618 222 4 0.4238 12.980122773618541 14.639356060980928 20.960754364272496 0 -1 0 -47 24 1 0.007459299037120008 14.708000000000002 15.284699999999999 23.449863020791625 0 0 0 -39 20 1 0.003376862325317847 11.7664 15.2847 23.449863020791625 0 0 0 -46 23 1 0.009768162996603134 16.178800000000003 12.737299999999998 23.449863020791625 0 0 0 -38 19 1 0.011451708519644 13.237200000000001 12.7373 23.449863020791625 0 0 0 -529 193 3 -0.8476 1.4045836747088354 12.797677923854442 15.297364918402971 1 0 0 -379 143 3 -0.8476 3.6479330411961883 18.493128836123883 19.58762503197076 1 -1 0 -165 71 4 0.4238 0.6364380304987282 20.088673926904107 15.935757183747858 0 -1 0 -660 236 4 0.4238 2.12389322021301 19.263967819272075 20.834602549240042 2 -1 0 -658 236 3 -0.8476 1.5737386108979707 20.098541840243776 20.86318845039298 2 -1 0 -560 203 4 0.4238 15.394781076902573 13.050765407651904 14.622081620313322 0 -1 0 -381 143 4 0.4238 3.2550133288406142 17.598298120219788 19.799504375422842 1 -1 0 -125 58 4 0.4238 10.47743096516406 13.402844176984058 13.330419032611076 0 -1 0 -506 185 4 0.4238 17.00798692793307 10.56073453324316 15.263209711132241 -1 0 0 -8 4 1 0.007878856031568425 1.4708000000000023 17.8322 23.449863020791625 0 0 0 -16 8 1 -0.02162051739161995 4.412400000000001 17.8322 23.449863020791625 0 0 0 -454 168 3 -0.8476 6.1211530914480035 18.877217060758102 21.057303091018483 1 0 0 -455 168 4 0.4238 6.016004433060814 18.378364098649328 21.91758892263117 1 0 0 -456 168 4 0.4238 5.249585193480707 18.883650340743063 20.567064277406875 1 0 0 -24 12 1 -0.02105358127656316 7.354000000000001 17.8322 23.449863020791625 0 0 0 -32 16 1 -8.633878219141563e-05 10.2956 17.8322 23.449863020791625 0 0 0 -474 174 4 0.4238 13.940539993728047 16.977316374214087 13.262406896868265 0 -1 0 -320 123 4 0.4238 0.45185935575146113 17.666250404746776 15.068591299890938 1 0 0 -173 74 4 0.4238 2.7498380997441414 19.67489584208449 13.872273730507478 1 -1 0 -175 75 3 -0.8476 4.212203814165672 11.613788132755259 18.65457863001542 0 -1 0 -152 67 4 0.4238 0.6848929361146843 19.37421734773228 14.07318618999465 -1 -2 0 -505 185 3 -0.8476 16.758143951478264 11.211629355559246 14.546329703315896 -1 0 0 -558 202 4 0.4238 2.2322174055594726 14.29431286166049 14.701660067407344 1 0 0 -510 186 4 0.4238 12.208040730030191 18.659648620639253 13.541393467576771 -1 0 0 -374 141 4 0.4238 9.497589320200765 19.8441690425366 18.526563503706242 1 -1 0 -153 67 4 0.4238 16.840552768523775 19.914595574397616 13.694556413474471 -2 -2 0 -163 71 3 -0.8476 1.137603810251879 20.333101852965335 16.765870695643105 0 -1 0 -507 185 4 0.4238 16.68943419233681 10.7331700931247 13.670909273297896 -1 0 0 -632 227 4 0.4238 9.059492914790276 11.263838240899624 13.232125352935022 -1 0 0 +49 25 2 0.01313937832121366 0 0 2.4018 0 0 0 +50 25 2 0.01865462761144026 1.4708 2.5475 2.4018 0 0 0 +51 26 2 0.01215067828938248 0 5.0949 2.4018 0 0 0 +57 29 2 -0.003610807073483032 2.9416 0 2.4018 0 0 0 +58 29 2 0.005703013773218414 4.4124 2.5475 2.4018 0 0 0 +59 30 2 0.01492950075159763 2.9416 5.0949 2.4018 0 0 0 +170 73 4 0.4238 1.1970063131417725 4.448138656468396 5.466951657599895 0 0 0 +65 33 2 -0.01336008416568608 5.8832 0 2.4018 0 0 0 +66 33 2 0.008131464922511046 7.354000000000001 2.5475 2.4018 0 0 0 +67 34 2 0.006428627158081519 5.8832 5.0949 2.4018 0 0 0 +73 37 2 0.01530290922280649 8.8248 0 2.4018 0 0 0 +74 37 2 0.0178705863531212 10.2956 2.5475 2.4018 0 0 0 +75 38 2 0.01605820740803012 8.8248 5.0949 2.4018 0 0 0 +339 129 4 0.4238 6.215143407565153 1.5981782348074796 4.622256839105766 0 1 0 +655 235 3 -0.8476 8.476564900511942 1.2821844087742245 5.337051952010723 0 0 0 +219 89 4 0.4238 10.502021333726653 3.7021423103868947 5.7312543103421625 0 0 0 +81 41 2 0.003821352996929769 11.7664 0 2.4018 0 0 0 +82 41 2 0.0122499340344385 13.237200000000001 2.5475 2.4018 0 0 0 +83 42 2 0.02008338572547091 11.7664 5.0949 2.4018 0 0 0 +89 45 2 -0.00220016637598902 14.708000000000002 0 2.4018 0 0 0 +90 45 2 0.01916344106292139 16.178800000000003 2.5475 2.4018 0 0 0 +91 46 2 0.01585713186018216 14.708000000000002 5.0949 2.4018 0 0 0 +422 157 4 0.4238 12.182185463466961 1.5623973821830206 4.952119670183798 -1 0 0 +311 120 4 0.4238 16.230200660164634 0.5697212073154095 5.261903478511206 -1 1 0 +121 57 3 -0.8476 14.928965974853021 3.8320491507582126 5.646357258624189 -1 0 0 +122 57 4 0.4238 15.663742089675145 4.504768415478503 5.559442077530576 -1 0 0 +52 26 2 0.009929698685546195 1.4708 7.6424 2.4018 0 0 0 +53 27 2 0.01070160392393697 0 10.1898 2.4018 0 0 0 +60 30 2 0.002065168034918851 4.4124 7.6424 2.4018 0 0 0 +61 31 2 0.008604633418259809 2.9416 10.1898 2.4018 0 0 0 +279 109 4 0.4238 4.3692626624440685 8.41895331852646 5.3396246864177614 0 0 0 +371 140 4 0.4238 2.4486062593013034 6.793479221771884 5.5865046284837065 0 0 0 +68 34 2 0.004714971778387275 7.354000000000001 7.6424 2.4018 0 0 0 +69 35 2 0.003924637444139914 5.8832 10.1898 2.4018 0 0 0 +76 38 2 0.007917285397572442 10.2956 7.6424 2.4018 0 0 0 +77 39 2 -0.01808660951169254 8.8248 10.1898 2.4018 0 0 0 +485 178 4 0.4238 10.14363196358318 10.102798405663004 4.167302462597097 0 -1 0 +408 152 4 0.4238 9.38291263437119 5.564927602775459 5.045183595795903 0 0 0 +84 42 2 0.01241966874518944 13.237200000000001 7.6424 2.4018 0 0 0 +85 43 2 -0.01817868841189527 11.7664 10.1898 2.4018 0 0 0 +92 46 2 0.009203470152072506 16.178800000000003 7.6424 2.4018 0 0 0 +93 47 2 0.01207830870567194 14.708000000000002 10.1898 2.4018 0 0 0 +693 247 4 0.4238 11.759233893108473 9.14080805374956 4.994613485874183 0 0 0 +691 247 3 -0.8476 12.619729421525784 8.811154786831024 5.383042455327591 0 0 0 +54 27 2 0.005629728388362503 1.4708 12.7373 2.4018 0 0 0 +55 28 2 0.002513408296186064 0 15.2847 2.4018 0 0 0 +62 31 2 0.003092652587940009 4.4124 12.7373 2.4018 0 0 0 +63 32 2 0.008508558468704444 2.9416 15.2847 2.4018 0 0 0 +537 195 4 0.4238 1.534381720252049 11.860861719269268 6.542947084634663 1 0 0 +536 195 4 0.4238 2.676602707730869 11.479113232811624 5.440118771886036 1 0 0 +70 35 2 0.02093416092812059 7.354000000000001 12.7373 2.4018 0 0 0 +71 36 2 0.0162835107880356 5.8832 15.2847 2.4018 0 0 0 +78 39 2 0.005658666939466993 10.2956 12.7373 2.4018 0 0 0 +79 40 2 0.01444653211523109 8.8248 15.2847 2.4018 0 0 0 +212 87 4 0.4238 9.17689647437603 12.056181317800215 5.899700054352701 -1 0 0 +197 82 4 0.4238 10.811203724884162 14.938620779548806 5.143521101460397 -1 0 0 +213 87 4 0.4238 9.916127809741116 13.253540453299259 5.071149368154535 -1 0 0 +211 87 3 -0.8476 9.032071730946864 12.857093231537508 5.318694103871617 -1 0 0 +531 193 4 0.4238 12.030992283922586 12.605823554960878 5.100034965099747 0 0 0 +86 43 2 0.005023636657948909 13.237200000000001 12.7373 2.4018 0 0 0 +87 44 2 -0.008143953810172733 11.7664 15.2847 2.4018 0 0 0 +94 47 2 0.01565233889388304 16.178800000000003 12.7373 2.4018 0 0 0 +95 48 2 -0.0009568931481186349 14.708000000000002 15.2847 2.4018 0 0 0 +173 74 4 0.4238 14.607048329829912 14.709369240727511 5.225217921443813 -1 0 0 +529 193 3 -0.8476 11.686238647240836 13.533907397787061 5.240770699213196 0 0 0 +56 28 2 0.02451397099577675 1.4708 17.8322 2.4018 0 0 0 +64 32 2 0.0004346307116607769 4.4124 17.8322 2.4018 0 0 0 +549 199 4 0.4238 2.8035257638796756 19.94451746271372 5.290160967083597 0 -1 0 +547 199 3 -0.8476 3.220242278418862 19.03563378790663 5.306889171843751 0 -1 0 +425 158 4 0.4238 2.2192904250669567 17.674274362104903 5.45770242867776 0 0 0 +72 36 2 -0.01170623458315166 7.354000000000001 17.8322 2.4018 0 0 0 +80 40 2 -0.003752064366203554 10.2956 17.8322 2.4018 0 0 0 +584 211 4 0.4238 11.447564153441556 19.671954191394008 5.093755855325763 0 0 0 +512 187 4 0.4238 8.000288495265798 18.140951857955233 4.574866834804232 0 -1 0 +351 133 4 0.4238 7.438947477451015 14.722835533994202 5.283284390297782 0 -1 0 +350 133 4 0.4238 8.678274881612676 15.784894198802297 5.335518060454404 0 -1 0 +88 44 2 -0.01375822979594546 13.237200000000001 17.8322 2.4018 0 0 0 +96 48 2 -0.002740917165010555 16.178800000000003 17.8322 2.4018 0 0 0 +458 169 4 0.4238 3.421534555503742 1.4200532895040254 5.205718648604084 -1 1 0 +683 244 4 0.4238 3.567476599791179 4.781786128581657 5.5628705767985975 0 1 0 +337 129 3 -0.8476 5.3595063418125735 1.756185300491631 5.115126186134353 0 1 0 +338 129 4 0.4238 5.103160503829063 2.7196512122815215 5.037493926885174 0 1 0 +682 244 3 -0.8476 4.375390642381924 4.307521060869852 5.213087037727385 0 1 0 +348 132 4 0.4238 3.382593086797166 2.6582649725340324 8.899394163639482 -1 0 0 +457 169 3 -0.8476 2.5460133336841064 1.2725516181617833 5.665834465490807 -1 1 0 +459 169 4 0.4238 2.589096641757538 1.6467500485588584 6.592182668049703 -1 1 0 +561 203 4 0.4238 5.34134772960545 2.295447087726068 9.507163619354456 1 1 0 +477 175 4 0.4238 1.1383794820837874 2.252829548411057 5.551788680212561 0 0 0 +346 132 3 -0.8476 2.621854939654064 2.2807187162263123 8.371434688851567 -1 0 0 +347 132 4 0.4238 1.7577917835720536 2.6237577368523186 8.739836673923394 -1 0 0 +383 144 4 0.4238 2.013751021656296 5.7853836770492775 8.820622894619671 0 0 0 +559 203 3 -0.8476 4.88356003957368 3.182230159728057 9.570778035270529 1 1 0 +475 175 3 -0.8476 0.4441306060454029 2.969095805500066 5.4811598260455865 0 0 0 +684 244 4 0.4238 5.088994528516322 4.975670185205686 5.002495896526019 0 1 0 +384 144 4 0.4238 0.5852422497137534 5.010166403151444 8.97882465943909 0 0 0 +446 165 4 0.4238 16.969963796078353 2.624650344678554 9.438794114735915 0 1 0 +445 165 3 -0.8476 17.46800479622538 3.4190272308822935 9.786532112927045 0 1 0 +133 61 3 -0.8476 4.876806410111092 0.32439160649893634 11.376006535574295 0 0 0 +169 73 3 -0.8476 1.674583456761345 5.262162719784211 5.7975370973848515 0 0 0 +382 144 3 -0.8476 1.069182487281893 5.739688687583618 8.495501784676557 0 0 0 +171 73 4 0.4238 1.3106640973137187 5.521867623412742 6.69202978450027 0 0 0 +187 79 3 -0.8476 16.62720577119881 0.930326042887631 8.54479026588559 0 0 0 +497 182 4 0.4238 7.839378997418928 3.3814437841168177 6.16452533621845 0 0 0 +657 235 4 0.4238 9.272031090332927 1.83712209050886 5.580522819358505 0 0 0 +496 182 3 -0.8476 8.158502438157697 4.1808456808602115 5.655489718055916 0 0 0 +560 203 4 0.4238 5.558544167193662 3.9135595468724897 9.473032422600387 1 1 0 +134 61 4 0.4238 5.572966567570519 0.36773706388079447 10.659428961782988 0 0 0 +320 123 4 0.4238 6.060161805639105 0.42325179488669523 8.102448068005529 -1 0 0 +100 50 3 -0.8476 6.756557578146551 5.071855368999333 9.86032571931797 0 -1 0 +319 123 3 -0.8476 6.2976701265986375 0.9111688382417715 8.94240786444143 -1 0 0 +218 89 4 0.4238 11.919622768934 3.042196618470905 6.201897890908077 0 0 0 +217 89 3 -0.8476 11.091533855644208 2.897504314620502 5.660292882238534 0 0 0 +498 182 4 0.4238 7.39235181929264 4.804271861585367 5.499427861231793 0 0 0 +673 241 3 -0.8476 8.72132440503013 2.982111010693392 8.479197221282682 0 0 0 +675 241 4 0.4238 9.472560847985294 3.63799712476457 8.553089388517241 0 0 0 +315 121 4 0.4238 9.783618797865904 1.3565381734610216 8.142854277918985 -1 0 0 +313 121 3 -0.8476 10.641087985568811 0.8450915924487797 8.199185616935535 -1 0 0 +656 235 4 0.4238 8.705311185196425 0.3130981855681743 5.429503199432064 0 0 0 +321 123 4 0.4238 7.291857043575641 0.9958524437618977 9.008915498770374 -1 0 0 +314 121 4 0.4238 11.392357550719073 1.4165705546620657 7.869018352891692 -1 0 0 +101 50 4 0.4238 7.602696291781229 5.018646345700789 10.390630557572885 0 -1 0 +428 159 4 0.4238 13.536294651585951 5.130827955800905 5.52874090365456 0 0 0 +476 175 4 0.4238 17.183591503992144 2.557510755197463 5.532274212078341 -1 0 0 +423 157 4 0.4238 12.915229636213642 0.7721644033966159 6.178824792641202 -1 0 0 +421 157 3 -0.8476 12.792647828079465 0.8059591347522885 5.186940887095969 -1 0 0 +501 183 4 0.4238 13.941179643749352 5.35062707289763 10.498878569878066 -1 0 0 +312 120 4 0.4238 14.692034430136435 0.8895962070881698 4.816534411636045 -1 1 0 +591 213 4 0.4238 13.351071847481165 2.941187861887174 8.418048382553936 -1 1 0 +310 120 3 -0.8476 15.567234528236744 1.2957664610552069 5.07931259036294 -1 1 0 +589 213 3 -0.8476 13.12753273250181 2.720571025556741 7.46864676879339 -1 1 0 +590 213 4 0.4238 13.75501355893383 3.203248562648256 6.857668437181667 -1 1 0 +123 57 4 0.4238 15.254810307885181 2.9401558436833777 5.332733604019717 -1 0 0 +462 170 4 0.4238 13.399880789358258 0.5612397722346458 8.301937028492524 0 1 0 +460 170 3 -0.8476 13.830254350542669 20.21339558773755 7.767789683970099 0 0 0 +500 183 4 0.4238 15.139101303003244 5.143764226309559 9.408548650472385 -1 0 0 +499 183 3 -0.8476 14.313107519347962 4.738870829320874 9.800718744114604 -1 0 0 +461 170 4 0.4238 13.806841757790728 19.35964290602946 8.287945657181965 0 0 0 +642 230 4 0.4238 13.924828446037314 3.192103166011166 10.042815337098027 0 0 0 +188 79 4 0.4238 15.651878359345202 0.7202970936706271 8.476773709300652 0 0 0 +189 79 4 0.4238 17.119731934741303 0.46913940826563705 7.806733913984351 0 0 0 +372 140 4 0.4238 2.1559098027054806 8.390680329253254 5.759435884286429 0 0 0 +277 109 3 -0.8476 5.251725056849934 8.853277180020518 5.159004549432832 0 0 0 +370 140 3 -0.8476 2.8628007492845517 7.683568349352478 5.7767294855350775 0 0 0 +156 68 4 0.4238 2.8150852986677677 8.399635697634759 8.775609296767776 -1 0 0 +155 68 4 0.4238 3.5682284865582092 7.799323343928108 7.456885546869966 -1 0 0 +154 68 3 -0.8476 3.6941121125704357 8.105231498558357 8.400588181078405 -1 0 0 +344 131 4 0.4238 5.851495590776306 7.610268020195233 8.303410633066342 -1 1 0 +276 108 4 0.4238 0.6295214161994077 7.955800732747191 9.476625658579314 0 0 0 +278 109 4 0.4238 5.108434652534757 9.815403980808044 4.927098708630241 0 0 0 +316 122 3 -0.8476 0.6785550047344096 9.233352412166546 5.294545132789045 0 0 0 +317 122 4 0.4238 17.343772536332082 9.247243955744489 5.117929828541656 -1 0 0 +274 108 3 -0.8476 1.151091478343952 8.802133590012104 9.584730954699129 0 0 0 +254 101 4 0.4238 1.4047672246121385 10.402717047765396 8.849432253625244 -2 -1 0 +404 151 4 0.4238 4.348339388021353 9.732964506609658 8.16305825421071 0 0 0 +253 101 3 -0.8476 1.5634005715993873 11.349547396690783 8.56951677399392 -2 -1 0 +296 115 4 0.4238 6.049974642770434 7.005961379640421 4.760383889102717 1 0 0 +407 152 4 0.4238 10.893684166125988 6.183904655316318 5.0778448895518 0 0 0 +406 152 3 -0.8476 9.92212042239337 6.395593944326714 5.18392681258845 0 0 0 +695 248 4 0.4238 7.072663419111676 8.755492401905604 5.307222408462379 0 0 0 +295 115 3 -0.8476 6.42489326521015 6.192180884716901 5.204455031976987 1 0 0 +153 67 4 0.4238 8.779210794637798 8.625421447058493 9.803957094562449 0 0 0 +151 67 3 -0.8476 8.660365397175308 8.533072250541817 8.815347887838605 0 0 0 +102 50 4 0.4238 6.676968470482932 5.980291172533071 9.449942413306985 0 -1 0 +343 131 3 -0.8476 6.6877815390881965 7.227331943962429 7.910999439459834 -1 1 0 +345 131 4 0.4238 7.4737844847511195 7.770043673650436 8.20708275884543 -1 1 0 +297 115 4 0.4238 6.548167486855295 6.371956103800878 6.180408248088382 1 0 0 +696 248 4 0.4238 8.407631718052315 7.937841760258333 5.771911245838207 0 0 0 +266 105 4 0.4238 10.125527147142027 5.899881907831837 7.700846235464896 0 -1 0 +694 248 3 -0.8476 8.021629398317938 8.84590763177934 5.6093675780004055 0 0 0 +152 67 4 0.4238 8.930290303293235 9.384773358194789 8.366185469432219 0 0 0 +486 178 4 0.4238 9.673896467385871 9.736202026628838 5.687691405424343 0 -1 0 +479 176 4 0.4238 6.671283907606323 10.929283909165283 7.536694131524121 0 -1 0 +108 52 4 0.4238 15.689686278000234 9.852886126152223 5.073893956070031 -1 -1 0 +318 122 4 0.4238 1.04516399602464 10.160036886043383 5.211735941197096 0 0 0 +429 159 4 0.4238 13.04775836664228 6.686508044310339 5.44031754428302 0 0 0 +265 105 3 -0.8476 10.636090713378708 5.1967298416607415 8.195726948026525 0 -1 0 +267 105 4 0.4238 11.616401875422898 5.375514677179539 8.111892329040971 0 -1 0 +104 51 4 0.4238 17.29639938634143 6.658767486997808 5.41697244336261 -1 -1 0 +106 52 3 -0.8476 15.312852705388183 8.952159621375953 5.289971412067087 -1 -1 0 +107 52 4 0.4238 14.314625041523152 8.988401490112066 5.242720370467341 -1 -1 0 +427 159 3 -0.8476 12.76581221568869 5.734250348907851 5.323218772008595 0 0 0 +563 204 4 0.4238 13.048980959535292 7.888697741575689 8.480878050559213 1 0 0 +562 204 3 -0.8476 12.227040593668018 8.000330933842479 7.922350810547911 1 0 0 +564 204 4 0.4238 11.732672557134151 8.818271900064063 8.216584527290978 1 0 0 +692 247 4 0.4238 12.439249191460995 8.35687647064915 6.255429527858298 0 0 0 +105 51 4 0.4238 15.7644057782206 7.2206968932244315 5.479087533550543 -1 -1 0 +103 51 3 -0.8476 16.34172803824704 6.410609804322348 5.581353946690772 -1 -1 0 +233 94 4 0.4238 15.831459483890962 6.3443425412232815 7.506676348102655 -1 -1 0 +234 94 4 0.4238 17.207197138288947 6.58665183662654 8.352406396337843 -1 -1 0 +232 94 3 -0.8476 16.237496094503037 6.821730002360146 8.285930002143425 -1 -1 0 +568 206 3 -0.8476 14.436802869756018 8.066379237357582 9.656320010860052 0 1 0 +570 206 4 0.4238 15.171464425763704 7.7573845547850455 9.052336493827966 0 1 0 +206 85 4 0.4238 13.135819254007934 10.504053706053634 5.840839099898824 -1 0 0 +569 206 4 0.4238 14.82053541511776 8.63463863870175 10.384216696867258 0 1 0 +449 166 4 0.4238 4.0285958260301316 15.343584351945665 5.674729337450389 1 0 0 +535 195 3 -0.8476 1.7311902045688985 11.779756585356743 5.565865309159913 1 0 0 +111 53 4 0.4238 0.5647210915819924 13.356388391731127 5.427024712740609 0 -1 0 +713 254 4 0.4238 5.114864454323739 12.17254541331872 5.344615097885859 0 0 0 +450 166 4 0.4238 3.321354127455215 13.96810057745761 5.1508197883186915 1 0 0 +712 254 3 -0.8476 4.420471355693568 11.461671518193928 5.456320210128772 0 0 0 +405 151 4 0.4238 4.529002172190804 11.144785520432174 8.963526376822028 0 0 0 +448 166 3 -0.8476 3.1614736111076764 14.853064880509136 5.58817173281572 1 0 0 +403 151 3 -0.8476 4.618417094929696 10.69190038264696 8.076452136710195 0 0 0 +714 254 4 0.4238 4.306261868188604 11.257121809283122 6.428491588117838 0 0 0 +650 233 4 0.4238 0.8261337305710591 15.272855563227955 11.422916396063492 0 0 0 +651 233 4 0.4238 1.66943487046593 14.509581557091455 10.251214842599271 0 0 0 +175 75 3 -0.8476 17.172315219972358 13.599797919951236 8.480240037975031 -1 0 0 +255 101 4 0.4238 2.111601727879556 11.815127535788964 9.264292189404564 -2 -1 0 +669 239 4 0.4238 1.32441182429345 14.440534331535007 8.119698252001108 0 -1 0 +176 75 4 0.4238 16.919992058996513 13.7590598745656 7.525792869934411 -1 0 0 +177 75 4 0.4238 0.14212439820882036 12.816487336818591 8.535057539477759 0 0 0 +426 158 4 0.4238 2.0148349179214744 16.05958673041296 5.325003286853482 0 0 0 +667 239 3 -0.8476 2.1848064397683484 14.772802155555862 8.50611755159529 0 -1 0 +668 239 4 0.4238 2.826360435363054 14.975159669662883 7.766211372331817 0 -1 0 +484 178 3 -0.8476 10.357631689874177 10.215682706838484 5.137593326285856 0 -1 0 +515 188 4 0.4238 7.237271230821362 13.016850696588378 6.291233855537184 0 -1 0 +514 188 3 -0.8476 6.302362345803112 13.314909166429452 6.098601687369539 0 -1 0 +516 188 4 0.4238 5.9159319591680255 13.747530614580732 6.913164684522444 0 -1 0 +478 176 3 -0.8476 7.649517829269427 10.723084115514967 7.513436353460663 0 -1 0 +480 176 4 0.4238 7.821442293527245 9.997393515338612 6.84724073071097 0 -1 0 +375 141 4 0.4238 8.262201775857786 12.681244389980177 7.985174959835936 -1 -1 0 +373 141 3 -0.8476 8.351343481979528 13.360278166139022 8.713854172750194 -1 -1 0 +127 59 3 -0.8476 9.725571949589012 15.799965406891792 8.639971492004653 -1 -1 0 +129 59 4 0.4238 9.383943626176912 14.910368743084565 8.943138729244842 -1 -1 0 +128 59 4 0.4238 9.78187897329827 15.812796452465063 7.641639904254624 -1 -1 0 +670 240 3 -0.8476 10.876081158438845 10.214147348206216 8.664462055509786 0 0 0 +716 255 4 0.4238 6.5227205557849794 14.51639237254202 9.157695237319166 0 1 0 +715 255 3 -0.8476 5.656410068931462 14.74288667317751 8.712490382023443 0 1 0 +717 255 4 0.4238 5.396715203220265 15.679952244365603 8.945875797043128 0 1 0 +374 141 4 0.4238 8.147095087998556 12.932874656872187 9.594542632899609 -1 -1 0 +690 246 4 0.4238 16.316627758868375 12.417272105899405 5.609830556023115 1 -1 0 +688 246 3 -0.8476 15.88450022727728 11.563228829395056 5.3202165565601955 1 -1 0 +110 53 4 0.4238 17.403222143019665 14.771437036588974 5.50894993304906 -1 -1 0 +530 193 4 0.4238 12.455252864940926 14.171237812645117 5.290056431143296 0 0 0 +672 240 4 0.4238 10.93446456953076 11.130757013043066 8.268964586777383 0 0 0 +606 218 4 0.4238 13.696925311062042 12.016193744415892 9.42033448199557 0 -1 0 +604 218 3 -0.8476 13.199097784370716 12.175725911474224 8.567856309628706 0 -1 0 +689 246 4 0.4238 14.951805886784305 11.52332053618768 5.678670862924324 1 -1 0 +109 53 3 -0.8476 17.44518184821449 13.833335825788478 5.852765063356562 -1 -1 0 +205 85 3 -0.8476 13.408638554629501 11.443690849497175 6.047363985992727 -1 0 0 +207 85 4 0.4238 13.219352634578524 11.642002996511048 7.009051887823537 -1 0 0 +605 218 4 0.4238 12.764432567986548 13.075775194143777 8.599132109124211 0 -1 0 +113 54 4 0.4238 11.526752853301545 15.360710840693375 9.023317467071111 -2 -1 0 +503 184 4 0.4238 14.318784694441247 15.15739959317121 8.815434883619313 0 -1 0 +112 54 3 -0.8476 12.463653527967322 15.164318472108 9.31253609220812 -2 -1 0 +719 256 4 0.4238 16.762922728615607 13.882542054852971 10.562472020809135 0 -1 0 +114 54 4 0.4238 12.555583410102484 15.34717931689137 10.291367658555105 -2 -1 0 +618 222 4 0.4238 6.148311559852576 16.02626161022556 5.608753804443583 0 -1 0 +548 199 4 0.4238 4.155001768830376 19.091027507803666 4.955952128009002 0 -1 0 +711 253 4 0.4238 0.956245615044033 20.16155734765175 5.837829871650892 0 0 0 +125 58 4 0.4238 3.7327483205332106 19.623338975867025 7.74099072648916 0 -2 0 +124 58 3 -0.8476 3.0946065332880934 19.44476887418889 8.489916040495311 0 -2 0 +126 58 4 0.4238 2.6716481257293134 20.30346156454942 8.779319328513571 0 -2 0 +617 222 4 0.4238 5.234073045261178 17.301463815054312 6.0611421474634195 0 -1 0 +534 194 4 0.4238 5.69636760733354 0.22016688690531758 5.87928032633577 0 1 0 +467 172 4 0.4238 4.410552940319404 18.162358205230102 8.85743528851177 0 -1 0 +616 222 3 -0.8476 5.231395482139811 16.317768569195522 5.881315846511935 0 -1 0 +575 208 4 0.4238 2.177620897192864 16.64982393435223 8.761554745053633 0 1 0 +576 208 4 0.4238 2.094574505181361 18.21985639375971 9.202835736910075 0 1 0 +574 208 3 -0.8476 1.5873217943892133 17.359983182573774 9.145250259424412 0 1 0 +424 158 3 -0.8476 1.564206785445587 16.948839460798485 5.246489063063134 0 0 0 +578 209 4 0.4238 0.2760161314354884 17.459253764508798 7.916581117516428 1 -1 0 +709 253 3 -0.8476 17.62184604917465 20.114099005680494 6.010710031072736 -1 0 0 +242 97 4 0.4238 17.40984948086816 16.699345430262625 10.164071784489389 -1 -1 0 +513 187 4 0.4238 9.115189452617253 18.724168298812177 5.6157709754579 0 -1 0 +468 172 4 0.4238 6.034258727738924 17.988689189495606 8.85060717294741 0 -1 0 +466 172 3 -0.8476 5.166589027853813 17.544989350665965 9.074843606247345 0 -1 0 +381 143 4 0.4238 4.1591214489581345 15.524908809046764 10.990269722350863 0 -1 0 +532 194 3 -0.8476 5.834562824802455 19.887060730724258 6.566790661757808 0 0 0 +511 187 3 -0.8476 8.188668075061216 18.845091881965207 5.259485027693011 0 -1 0 +196 82 3 -0.8476 10.527262376382927 15.867880764509227 5.379864060368958 -1 0 0 +623 224 4 0.4238 8.528221169678154 19.31113215754156 7.824261629619986 0 -1 0 +198 82 4 0.4238 11.062901638987622 16.525094673686695 4.849617314139471 -1 0 0 +533 194 4 0.4238 6.631147177486181 19.33543163284572 6.319477694784791 0 0 0 +349 133 3 -0.8476 7.69607689524864 15.683400937910493 5.177437140121121 0 -1 0 +622 224 3 -0.8476 7.888478893752487 18.75285961396988 8.352524879091089 0 -1 0 +643 231 3 -0.8476 10.764609330931004 18.70078929569158 9.368107024446358 0 -1 0 +645 231 4 0.4238 11.38443546601623 18.224272161997142 8.74461050411629 0 -1 0 +644 231 4 0.4238 10.714600259975864 19.666844993781993 9.114653652940364 0 -1 0 +624 224 4 0.4238 8.318616297804342 17.87963305837006 8.581561676244952 0 -1 0 +583 211 3 -0.8476 10.923680387277354 18.90106219271726 5.456073631082404 0 0 0 +174 74 4 0.4238 13.812701589520023 16.099993367558167 5.544291418876141 -1 0 0 +504 184 4 0.4238 15.88399643967493 14.722614317395516 8.648992333485126 0 -1 0 +172 74 3 -0.8476 13.713001428124947 15.11276340618361 5.420040747545721 -1 0 0 +502 184 3 -0.8476 15.256633354866155 15.496055548019697 8.739580218641269 0 -1 0 +585 211 4 0.4238 11.40414286428808 18.511473583820692 6.241809732636211 0 0 0 +387 145 4 0.4238 12.265671546558718 16.380737435742297 7.1686513413536215 0 -1 0 +369 139 4 0.4238 14.681121882135567 18.628753446505907 6.59440054246881 -1 -1 0 +611 220 4 0.4238 17.481802587326232 16.639709214951562 4.903714531175374 0 -1 0 +612 220 4 0.4238 15.918553047167078 17.11175795529572 4.910655987581638 0 -1 0 +579 209 4 0.4238 16.78201906894718 17.325920408163103 6.758352457087368 0 -1 0 +385 145 3 -0.8476 12.331377756083219 17.368242490786933 7.311891787604915 0 -1 0 +386 145 4 0.4238 12.970558936772463 17.555028613004016 8.057921957800264 0 -1 0 +710 253 4 0.4238 17.433607789783785 19.383368605771306 6.6669116430518915 -1 0 0 +368 139 4 0.4238 14.227107778925602 18.993012948194856 5.068683005163068 -1 -1 0 +259 103 3 -0.8476 14.329652787283667 18.053325372164224 9.13418399297064 -1 -1 0 +610 220 3 -0.8476 16.550451245609086 16.37625019023457 5.15506039199796 0 -1 0 +367 139 3 -0.8476 14.838696244695667 18.432110772478424 5.626669643597806 -1 -1 0 +577 209 3 -0.8476 17.1798101180517 17.93211878211929 7.447037188901601 0 -1 0 +447 165 4 0.4238 0.1812793845060234 3.2133495020905416 10.695468049934293 1 1 0 +357 135 4 0.4238 1.847556029739268 4.750019700352974 15.001767737024641 0 0 0 +97 49 3 -0.8476 4.740821103384455 20.304436935423432 14.92515435856283 -1 -2 0 +99 49 4 0.4238 4.178373693671055 0.6308790673370844 14.495182679676672 -1 -1 0 +168 72 4 0.4238 4.092559755070765 1.9726288450981528 11.723644946206903 0 -1 0 +435 161 4 0.4238 1.8652049665647261 2.529104882577933 11.972384220967834 0 0 0 +558 202 4 0.4238 0.4787023196380537 0.9784172030698345 11.983674757347728 0 1 0 +166 72 3 -0.8476 3.722204957330288 2.6872039330909865 12.317129443300917 0 -1 0 +394 148 3 -0.8476 3.600129810223536 5.711189886722592 9.91127897374719 0 0 0 +433 161 3 -0.8476 0.9775133011806281 2.984419097499584 12.0408888299802 0 0 0 +434 161 4 0.4238 0.9453105758914859 3.527438181538437 12.879992426286092 0 0 0 +167 72 4 0.4238 4.256504961433037 3.5248456706327174 12.20361853529446 0 -1 0 +396 148 4 0.4238 4.369323942225964 5.074189350069953 9.962000089090727 0 0 0 +355 135 3 -0.8476 1.1940316851586277 4.732773898353678 14.245054728005904 0 0 0 +647 232 4 0.4238 1.8279553613860204 1.0549182196346443 15.03870664516926 1 1 0 +654 234 4 0.4238 2.7123045598750704 3.03126732097064 15.384352990991019 0 0 0 +652 234 3 -0.8476 3.043853077556617 2.221473163587609 14.900296754255706 0 0 0 +653 234 4 0.4238 3.443501871147192 2.496242346441958 14.02577780630131 0 0 0 +674 241 4 0.4238 7.892284873018967 3.379123004272847 8.87299414189215 0 0 0 +246 98 4 0.4238 6.174705839105568 0.8103733560375688 15.585953552731109 0 0 0 +245 98 4 0.4238 7.7059877558665955 0.7048163707072558 16.143323425074527 0 0 0 +244 98 3 -0.8476 6.8553461484756175 1.2287134080244495 16.187385937552218 0 0 0 +697 249 3 -0.8476 10.83831761471495 1.52057398500823 14.182581980610884 0 1 0 +698 249 4 0.4238 10.210242664416823 0.8231989403443087 14.5278259235526 0 1 0 +629 226 4 0.4238 9.662909714901263 4.794365531285398 11.375689970627544 1 -1 0 +593 214 4 0.4238 10.40807559412412 3.1534573657689107 13.657275086695144 0 1 0 +592 214 3 -0.8476 9.922606001827361 3.9489839075095747 13.29470320203831 0 1 0 +210 86 4 0.4238 7.277002837073857 4.1094452089125735 15.493029225132387 0 1 0 +209 86 4 0.4238 7.286164061287226 2.6881361742965186 14.689024342262156 0 1 0 +594 214 4 0.4238 8.938734710948083 3.8273333316116873 13.425851125247322 0 1 0 +663 237 4 0.4238 5.827808807325225 4.62753019272002 13.404417702965164 0 0 0 +208 86 3 -0.8476 7.383014424746107 3.679135358090266 14.596591722696116 0 1 0 +419 156 4 0.4238 0.3607084943625497 6.098316380765166 11.804799703813217 0 1 0 +641 230 4 0.4238 14.353180736024825 1.7906609315646662 10.763301969550975 0 0 0 +640 230 3 -0.8476 13.840489913902166 2.1963234981178763 10.006607544167009 0 0 0 +137 62 4 0.4238 12.072289781940233 0.35299104460048664 11.012586562998269 -1 -1 0 +699 249 4 0.4238 11.2862135608659 1.1848898153830811 13.353902530381527 0 1 0 +136 62 3 -0.8476 12.23072292639147 0.397665446037911 11.998945478595864 -1 -1 0 +140 63 4 0.4238 14.867607209668295 1.938752709182049 13.08463832223618 -1 0 0 +139 63 3 -0.8476 14.78021627607108 1.1486224670575256 12.477960031682642 -1 0 0 +138 62 4 0.4238 13.213575802526444 0.4463785851081826 12.176792489424273 -1 -1 0 +286 112 3 -0.8476 15.394577876326938 3.1059264031945113 14.329682330157693 0 0 0 +141 63 4 0.4238 15.393986285992415 0.42194716963361606 12.786553485765614 -1 0 0 +356 135 4 0.4238 0.3581533842113541 5.210392233397551 14.5155921820269 0 0 0 +395 148 4 0.4238 3.856603538115896 6.499626022756107 9.352180381061403 0 0 0 +224 91 4 0.4238 3.665540131628934 8.766822079901068 13.52560383146032 -1 -1 0 +275 108 4 0.4238 0.7921354634518165 9.317805682629903 10.362699912662606 0 0 0 +223 91 3 -0.8476 3.1475931393099716 8.798963862485444 12.67079496023714 -1 -1 0 +389 146 4 0.4238 4.678784160455236 8.294957402231551 15.253203116408447 -1 -1 0 +216 88 4 0.4238 3.9959639352096077 10.178590384900206 11.243371748278841 0 0 0 +257 102 4 0.4238 2.9767178037344864 6.102184067402138 11.44667157530849 -1 -1 0 +225 91 4 0.4238 2.793289630849297 7.887606052634235 12.461279975706473 -1 -1 0 +258 102 4 0.4238 2.1426164777900727 5.507280901940478 12.718282585374252 -1 -1 0 +256 102 3 -0.8476 2.288629921057995 6.311084043070111 12.141582956180768 -1 -1 0 +269 106 4 0.4238 6.145338047857415 6.587211058381091 14.096023407757173 0 -1 0 +284 111 4 0.4238 1.6547649730419856 9.615458094132954 12.360533668396412 1 -1 0 +388 146 3 -0.8476 4.1336175160828486 9.01706227616198 15.679065669504851 -1 -1 0 +390 146 4 0.4238 3.278752062602154 8.62968447460259 16.02423850482696 -1 -1 0 +686 245 4 0.4238 0.050473204555478116 8.33233481867503 15.35489007150469 0 0 0 +630 226 4 0.4238 9.804119270073283 5.686472363021448 10.015236700422788 1 -1 0 +628 226 3 -0.8476 9.256514915435922 5.53293526442516 10.837768251306391 1 -1 0 +662 237 4 0.4238 6.055655244038911 5.5127515886593095 12.051237698943496 0 0 0 +661 237 3 -0.8476 5.39645715645333 4.966977086843131 12.568527627928479 0 0 0 +158 69 4 0.4238 8.239784129603814 6.518295232953348 11.762767465452137 0 1 0 +157 69 3 -0.8476 7.525721427365336 7.099872414593089 12.152493487393517 0 1 0 +331 127 3 -0.8476 9.940292101697922 6.820709072068782 14.168909743748504 0 0 0 +333 127 4 0.4238 10.9222641824768 6.811258108109765 14.357704544221606 0 0 0 +332 127 4 0.4238 9.588248841650607 5.884912383557486 14.187665406873634 0 0 0 +159 69 4 0.4238 7.941296904021835 7.9208242176348564 12.544078932702808 0 1 0 +443 164 4 0.4238 9.257282573896715 8.236146821821395 13.82644901446346 -1 0 0 +702 250 4 0.4238 8.944556842035203 4.460477944048146 17.220028746753886 -1 1 0 +418 156 3 -0.8476 17.04244166005861 5.998736304556262 11.57305385987536 -1 1 0 +420 156 4 0.4238 16.929542275845908 5.239054047369782 10.932633742526257 -1 1 0 +306 118 4 0.4238 15.054721929761767 6.1988663198682445 12.195550287825709 0 0 0 +725 258 4 0.4238 11.763315259015506 4.675923827711252 13.938998247166115 0 0 0 +285 111 4 0.4238 0.47886486086631647 10.687324505395337 12.727942385254115 1 -1 0 +305 118 4 0.4238 14.247100207506463 7.1072870676606525 11.105070468321909 0 0 0 +304 118 3 -0.8476 14.149275445987765 6.481969740029936 11.879287885340991 0 0 0 +726 258 4 0.4238 12.960718425168919 5.660168858219739 13.425076283647144 0 0 0 +724 258 3 -0.8476 12.468338574375162 5.323652974482742 14.227772092043644 0 0 0 +638 229 4 0.4238 12.05956539715828 10.864161281925869 13.802323315521988 -1 -1 0 +399 149 4 0.4238 16.750473304787647 9.530503152154038 11.418317259828266 0 1 0 +397 149 3 -0.8476 15.763166233431196 9.425157842686454 11.537182449361275 0 1 0 +283 111 3 -0.8476 0.820922338317977 10.057794191068144 12.03031158296465 1 -1 0 +163 71 3 -0.8476 15.162496118240178 9.870657051117623 14.110440538494784 -1 0 0 +164 71 4 0.4238 15.645588456789435 10.715622587912256 13.880969343781755 -1 0 0 +685 245 3 -0.8476 16.737395452628256 8.13331549974446 15.539361115979883 -1 0 0 +687 245 4 0.4238 16.587379737429536 8.099923479195049 16.527481394265017 -1 0 0 +649 233 3 -0.8476 1.3588313009098396 14.456362531344404 11.200264748731371 0 0 0 +215 88 4 0.4238 3.5126588937641405 11.73786546709177 11.202089685116377 0 0 0 +587 212 4 0.4238 2.2171274427421794 11.308020818373768 14.408963587129238 0 0 0 +586 212 3 -0.8476 3.200811418785457 11.452264392873431 14.516484383241018 0 0 0 +588 212 4 0.4238 3.6188421074861963 10.627827313402745 14.898004157725504 0 0 0 +539 196 4 0.4238 17.370847511142472 12.473840831402779 14.354545058816383 -1 -1 0 +214 88 3 -0.8476 3.7263785710719746 10.934315254340394 10.646543487573023 0 0 0 +380 143 4 0.4238 4.83223071836321 14.206968779399421 11.680622544421002 0 -1 0 +191 80 4 0.4238 2.634895605896023 13.532265477504726 11.89540521982074 0 -1 0 +192 80 4 0.4238 3.5341925623469734 12.960851287636022 13.1328946454657 0 -1 0 +190 80 3 -0.8476 3.4485200177145052 13.003668076064319 12.137491132459456 0 -1 0 +538 196 3 -0.8476 0.1998118507190113 11.598384594819466 14.42343364564352 0 -1 0 +671 240 4 0.4238 10.419939259027254 10.262962738121466 9.553030055557315 0 0 0 +262 104 3 -0.8476 7.382624766578302 12.090860349556454 11.21002162235012 0 0 0 +263 104 4 0.4238 6.397935592185901 12.157149760289094 11.371247837235982 0 0 0 +264 104 4 0.4238 7.875171242026451 12.409626820057237 12.019829693455922 0 0 0 +614 221 4 0.4238 8.56240323068188 10.7496696662053 10.831178941272759 1 -1 0 +442 164 3 -0.8476 8.700375825935984 9.011931818299498 13.52977847188488 -1 0 0 +613 221 3 -0.8476 9.416954282026312 10.299467264220647 11.090140080600808 1 -1 0 +615 221 4 0.4238 9.289091051191704 9.813815389086011 11.954890873003347 1 -1 0 +238 96 3 -0.8476 8.063535417845607 13.825205891587308 13.355505940484326 0 -1 0 +240 96 4 0.4238 7.110550789673944 13.69051190534572 13.626946955335905 0 -1 0 +444 164 4 0.4238 8.650889599910359 9.687403844292913 14.265502263239682 -1 0 0 +398 149 4 0.4238 15.539622010653874 9.45549971647298 12.511406165959794 0 1 0 +438 162 4 0.4238 16.34550689895525 14.042303121150413 13.215768931198447 0 0 0 +436 162 3 -0.8476 16.370275386771294 13.763035604635466 14.175664210056159 0 0 0 +437 162 4 0.4238 16.296354933000924 14.571220389567156 14.759938421613354 0 0 0 +718 256 3 -0.8476 16.185204308293734 14.193675912341332 11.317085379662494 0 -1 0 +720 256 4 0.4238 15.94977871330843 15.156098767140222 11.181729380736286 0 -1 0 +119 56 4 0.4238 12.0427416973315 12.029763013766948 11.110158074645799 -1 -1 0 +118 56 3 -0.8476 11.432374799819748 12.039882357165899 11.902213132638838 -1 -1 0 +120 56 4 0.4238 10.727244194532929 11.339965743413659 11.788592316430185 -1 -1 0 +301 117 3 -0.8476 14.485076610417329 11.996229174502563 10.837416919864094 0 1 0 +302 117 4 0.4238 15.163601977583083 12.707930544200536 11.019321482233156 0 1 0 +303 117 4 0.4238 14.884023759502458 11.099078067355505 11.02705377313857 0 1 0 +165 71 4 0.4238 15.800206222252266 9.226148688473826 14.53226881689346 -1 0 0 +379 143 3 -0.8476 4.964606912131187 15.175261574473684 11.468749797049503 0 -1 0 +98 49 4 0.4238 4.921449415179219 19.574795232809254 14.265611581334724 -1 -2 0 +135 61 4 0.4238 4.776915758368173 19.759021395862487 11.68693405197857 0 -1 0 +441 163 4 0.4238 1.9351451019676944 17.810262754350813 13.855350901711349 1 -1 0 +439 163 3 -0.8476 2.3968917687887275 18.36237607994476 13.161114984632775 1 -1 0 +440 163 4 0.4238 1.7483468435780378 19.014200867634028 12.768029827752589 1 -1 0 +241 97 3 -0.8476 16.87510404175997 16.99501892831403 10.955668267021162 -1 -1 0 +142 64 3 -0.8476 4.978218715970766 18.003139583189803 12.73273931719706 0 -1 0 +144 64 4 0.4238 5.071803553446059 17.0267051264412 12.927210467166335 0 -1 0 +143 64 4 0.4238 4.015521476811523 18.265451459404645 12.799137950654782 0 -1 0 +180 76 4 0.4238 15.512872196801505 16.252950464244147 14.820082384125504 -1 0 0 +472 174 3 -0.8476 1.2742457978033506 16.56205800584485 14.895996687575648 1 0 0 +473 174 4 0.4238 1.7096564617644439 15.705257719780878 15.17224729633624 1 0 0 +506 185 4 0.4238 6.823327693130979 18.663437128415826 12.684689753490513 1 -1 0 +505 185 3 -0.8476 7.777055812692833 18.761555507512135 12.968905430156887 1 -1 0 +507 185 4 0.4238 8.37216510962521 18.321063652267217 12.296732893458284 1 -1 0 +365 138 4 0.4238 8.015724365992902 15.339188239200784 11.973621131278675 0 -1 0 +366 138 4 0.4238 6.661835125589007 15.522086977430543 11.079104620814839 0 -1 0 +364 138 3 -0.8476 7.645088578296798 15.700175956054876 11.117863800626324 0 -1 0 +660 236 4 0.4238 8.979207486352824 16.70505321395575 11.054160054895618 0 -1 0 +658 236 3 -0.8476 9.570262170022627 17.431653565334543 11.404457081728449 0 -1 0 +659 236 4 0.4238 10.08742436484279 17.8339100043106 10.648987499442617 0 -1 0 +704 251 4 0.4238 8.473215883829688 19.510640813911238 14.263676778007913 0 -1 0 +703 251 3 -0.8476 8.776192673660734 19.901447031621075 15.132859426903634 0 -1 0 +359 136 4 0.4238 11.051537950639599 17.350243474212757 16.068712189222182 0 0 0 +470 173 4 0.4238 10.76441001086064 18.073330110832174 12.467224302186365 0 -1 0 +239 96 4 0.4238 8.508542866435485 14.448033390567616 13.998979240873444 0 -1 0 +360 136 4 0.4238 11.598748952515562 18.256517242858383 14.825387360343209 0 0 0 +358 136 3 -0.8476 11.275556526609193 18.278394528773564 15.771469774850447 0 0 0 +261 103 4 0.4238 14.652123948741334 17.14841245921013 8.856431310351903 -1 -1 0 +260 103 4 0.4238 14.830063048937909 18.35037138224516 9.947421934004115 -1 -1 0 +556 202 3 -0.8476 0.6451634932785091 0.08612058957410944 12.403314711368045 0 1 0 +557 202 4 0.4238 0.7705800276817398 0.19949478758276096 13.388919878352045 0 1 0 +243 97 4 0.4238 16.648631090570646 17.96448680244335 10.861632499169296 -1 -1 0 +452 167 4 0.4238 16.320072793421065 20.26278000968495 10.014885064756477 -1 -1 0 +453 167 4 0.4238 17.10698081722232 19.78697457015618 11.364334136186669 -1 -1 0 +451 167 3 -0.8476 16.28128072015691 19.662897475548206 10.814034290253536 -1 -1 0 +249 99 4 0.4238 12.811870600520288 14.966040923006444 12.612254155376286 0 -1 0 +378 142 4 0.4238 13.864097722276158 13.369472687627342 13.658656095537358 0 -1 0 +469 173 3 -0.8476 11.581595523986602 18.239940681502915 13.01899796347378 0 -1 0 +471 173 4 0.4238 11.958183091686623 19.138581414646616 12.793986536425175 0 -1 0 +247 99 3 -0.8476 12.876116783439823 15.746834294738138 11.990772724238388 0 -1 0 +248 99 4 0.4238 12.217138825237507 16.446894626362194 12.265849833084124 0 -1 0 +361 137 3 -0.8476 15.13727009687457 16.90165414469196 13.223153761736725 -1 -1 0 +362 137 4 0.4238 14.470451489983892 16.44380220380938 12.635168635911581 -1 -1 0 +363 137 4 0.4238 15.932868898604944 17.169056583231026 12.679536691827476 -1 -1 0 +492 180 4 0.4238 0.43743422645945185 4.5906269933473665 18.587621435257972 1 -1 0 +490 180 3 -0.8476 0.7538552615552045 3.741012408657575 18.165674020330567 1 -1 0 +292 114 3 -0.8476 6.779237475248931 2.5855973221897752 18.742314354584874 -1 1 0 +293 114 4 0.4238 5.782974477885699 2.665690105600376 18.774671827300182 -1 1 0 +543 197 4 0.4238 2.261683519266417 18.956286129295005 17.516517444173967 0 -1 0 +294 114 4 0.4238 7.041384117522155 1.9923415303923404 17.981177212709813 -1 1 0 +648 232 4 0.4238 1.2840185943369538 20.027487564337527 15.663576384325069 1 0 0 +646 232 3 -0.8476 1.035833673325263 0.4501108958548825 15.120877926941924 1 1 0 +289 113 3 -0.8476 3.5694615540602066 3.9557007985544073 18.892473225882544 -1 0 0 +290 113 4 0.4238 3.9007473345866632 4.846501971064104 18.58146458496819 -1 0 0 +634 228 3 -0.8476 2.0548959172216112 1.4885500264873104 19.846198245709125 1 0 0 +635 228 4 0.4238 2.9628766537025832 1.9045281700166616 19.795858546975285 1 0 0 +299 116 4 0.4238 2.171952214244551 4.633689704374672 16.985315368019506 0 0 0 +291 113 4 0.4238 2.6481656653101635 3.799781565594691 18.536236986216945 -1 0 0 +393 147 4 0.4238 4.348351463424381 19.061632161699574 17.883086170554588 0 -1 0 +636 228 4 0.4238 1.3782409041190875 2.118028733596981 19.46423579740044 1 0 0 +149 66 4 0.4238 10.058819394907307 3.0688181389053097 19.210862966210907 0 1 0 +325 125 3 -0.8476 10.74828334198565 4.322936964736242 17.57185541428758 0 0 0 +326 125 4 0.4238 11.425688586961753 3.656912809840247 17.259547991077014 0 0 0 +327 125 4 0.4238 11.140117164858376 5.241979252441542 17.529066927007428 0 0 0 +488 179 4 0.4238 10.350157062795372 0.2420626451877226 21.92631989941215 1 0 0 +148 66 3 -0.8476 9.537226432172295 2.5429363057164167 19.88271855735622 0 1 0 +150 66 4 0.4238 8.560229252221008 2.711870615751354 19.75256698710486 0 1 0 +707 252 4 0.4238 11.740110463186003 1.776348015109221 15.53086302864974 0 0 0 +706 252 3 -0.8476 12.198096570724744 1.8904670385576847 16.412467842603686 0 0 0 +708 252 4 0.4238 12.571862151067574 1.0119896957090955 16.710088672419115 0 0 0 +481 177 3 -0.8476 9.315276994339321 18.510963695713393 19.342025103756953 0 -1 0 +483 177 4 0.4238 9.422623982664092 19.209702688095064 20.04930314789335 0 -1 0 +482 177 4 0.4238 9.988811289898274 17.785763007329415 19.484984290912223 0 -1 0 +288 112 4 0.4238 15.471449713112566 2.8488298385283906 15.293007007266988 0 0 0 +287 112 4 0.4238 15.516107836695687 4.09424959615854 14.237750379319154 0 0 0 +491 180 4 0.4238 17.64496292035689 3.3085743846428177 17.67782963384906 0 -1 0 +309 119 4 0.4238 13.582283027599846 2.6353512461283666 17.34240140650764 -1 0 0 +307 119 3 -0.8476 14.343622662449947 2.966429642204021 17.899854712193406 -1 0 0 +495 181 4 0.4238 17.43274891004834 1.5087555488754918 16.215207616573853 0 0 0 +308 119 4 0.4238 15.20818961662623 2.678545913791243 17.487968923154984 -1 0 0 +229 93 3 -0.8476 14.344885450355205 0.7111805793204466 20.537565280186016 -1 0 0 +465 171 4 0.4238 14.311096036256034 4.047018967431671 19.16592080772689 0 1 0 +494 181 4 0.4238 16.24079039258795 0.9996458541668086 17.208520508456573 0 0 0 +493 181 3 -0.8476 16.619064945220725 1.7887900548853854 16.724619451647936 0 0 0 +185 78 4 0.4238 12.823282507193017 6.351770580905416 20.083457041313054 -1 0 0 +463 171 3 -0.8476 14.179508428091005 4.717580926865845 19.896014275607744 0 1 0 +270 106 4 0.4238 6.032468062116908 7.155526539301534 15.622753627061442 0 -1 0 +268 106 3 -0.8476 5.657810510464103 7.219793323360017 14.697818677953899 0 -1 0 +298 116 3 -0.8476 2.818422477899985 4.939880429917721 16.286511307998115 0 0 0 +680 243 4 0.4238 4.206367111153776 7.357182675152206 18.457428435583857 0 0 0 +334 128 3 -0.8476 1.4174345103786654 8.190935790107671 19.4900782394972 0 0 0 +335 128 4 0.4238 1.0010926992929934 9.046505146618708 19.797750119178264 0 0 0 +679 243 3 -0.8476 4.384215592438126 6.497743117254143 17.97812275252637 0 0 0 +456 168 4 0.4238 1.4547159295169854 7.96221128068873 17.469762961216215 0 1 0 +681 243 4 0.4238 5.262112071440925 6.556612702721318 17.502904009616717 0 0 0 +573 207 4 0.4238 7.2650142005940035 7.6086751010873 17.74198610111241 -1 0 0 +336 128 4 0.4238 2.397074513938586 8.206080435611778 19.6902728582061 0 0 0 +454 168 3 -0.8476 1.7321156971839582 8.543693209618814 16.704956222386965 0 1 0 +271 107 3 -0.8476 4.087574069629593 9.129323818676124 19.48021356815156 -1 -1 0 +300 116 4 0.4238 3.5500184500427867 5.467928404881992 16.717714103309124 0 0 0 +280 110 3 -0.8476 6.414874336555821 9.928443784453252 16.808359567446605 0 0 0 +272 107 4 0.4238 3.653665561817695 10.029220473914936 19.523966349859798 -1 -1 0 +116 55 4 0.4238 0.0723261427341601 6.970688135061237 19.45119017600495 0 -1 0 +581 210 4 0.4238 11.115101941015714 9.669097525259048 16.97608379349732 0 0 0 +700 250 3 -0.8476 7.951324048838638 4.507019114114237 17.113591427548194 -1 1 0 +701 250 4 0.4238 7.518815989634965 3.8495736320843488 17.73060492219878 -1 1 0 +580 210 3 -0.8476 10.489708859215067 8.908706454507964 16.800898362124844 0 0 0 +571 207 3 -0.8476 6.876526326487497 6.854145263283054 17.213055418586528 -1 0 0 +186 78 4 0.4238 12.276769507558853 6.982996982936812 18.680066735842384 -1 0 0 +184 78 3 -0.8476 12.229018908956789 7.045751225223292 19.67695394058582 -1 0 0 +723 257 4 0.4238 11.554579899201622 7.466152123138789 16.791653001025573 -1 1 0 +721 257 3 -0.8476 12.07052187358629 6.609563755245322 16.79963694089583 -1 1 0 +609 219 4 0.4238 8.650803366971875 7.61928606613244 19.271292272849085 -1 0 0 +608 219 4 0.4238 9.166062533392942 8.732739969731657 18.19362940326139 -1 0 0 +607 219 3 -0.8476 8.394806459926999 8.438458175553992 18.758044165956715 -1 0 0 +572 207 4 0.4238 7.468410774949949 6.052032470496192 17.29239859654011 -1 0 0 +161 70 4 0.4238 9.737907903821842 5.686564739227311 20.517408312071204 0 -1 0 +582 210 4 0.4238 9.902510744294325 9.13252755652863 16.02301379324525 0 0 0 +282 110 4 0.4238 5.975197133623462 10.669659986067497 17.315593194480346 0 0 0 +639 229 4 0.4238 13.219121632761292 9.970188622986985 14.525420510553294 -1 -1 0 +637 229 3 -0.8476 12.400731795859281 10.524051175890197 14.678640191793187 -1 -1 0 +722 257 4 0.4238 12.539550953814611 6.49479219401724 15.923942648950579 -1 1 0 +510 186 4 0.4238 11.287628312760472 9.398714217255213 19.519112317260827 -1 -1 0 +222 90 4 0.4238 15.937034254451548 5.640752915151805 15.671658019394947 -1 0 0 +220 90 3 -0.8476 16.308887888331522 5.590975428109702 14.744700548019777 -1 0 0 +221 90 4 0.4238 16.571741636418928 6.506894589151454 14.44138371581618 -1 0 0 +194 81 4 0.4238 12.75368231744947 10.752721407362513 16.425169074232862 -1 0 0 +195 81 4 0.4238 12.71140708501866 10.750250283312678 18.05760167752052 -1 0 0 +193 81 3 -0.8476 13.253688156531002 10.503329403105685 17.254506434193278 -1 0 0 +432 160 4 0.4238 14.561267636598071 5.317977222991033 17.730025349380618 -1 0 0 +431 160 4 0.4238 15.03866372011643 6.789122067501419 17.206141993385756 -1 0 0 +430 160 3 -0.8476 15.26623621703309 5.815535381499027 17.224598071379116 -1 0 0 +544 198 3 -0.8476 0.6114163714340954 10.422427507789719 20.759093077200042 1 0 0 +115 55 3 -0.8476 17.335575147083638 6.085970670681771 19.19010513950838 -1 -1 0 +117 55 4 0.4238 16.62864657877149 6.222571151340762 18.496135953606725 -1 -1 0 +545 198 4 0.4238 17.385110185671635 10.717184621385705 21.141530864904997 0 0 0 +182 77 4 0.4238 4.775987467397462 12.501881710927542 14.958355156555413 -1 -1 0 +540 196 4 0.4238 0.37050159087522283 11.386645019643359 15.385739254435364 0 -1 0 +602 217 4 0.4238 2.877091840194542 13.464366499134016 15.558945208444463 0 0 0 +603 217 4 0.4238 2.969586552771944 14.499684055252724 16.818385363959177 0 0 0 +455 168 4 0.4238 1.369396484122558 9.465935894269819 16.83876422312793 0 1 0 +201 83 4 0.4238 2.671037056829991 12.406467556922887 19.346315858245593 0 -1 0 +199 83 3 -0.8476 3.2625773832214624 11.698316447863316 18.96082513336595 0 -1 0 +200 83 4 0.4238 4.100557971867599 12.11769488133759 18.611667090961166 0 -1 0 +599 216 4 0.4238 1.8893584169093294 14.35428360513243 20.05147404139672 -1 0 0 +598 216 3 -0.8476 1.5649431232930577 13.416630818672424 20.176224312691144 -1 0 0 +600 216 4 0.4238 0.5683002528537319 13.416872997825863 20.258099525254817 -1 0 0 +281 110 4 0.4238 5.804304259236728 9.613996628517596 16.081495363106505 0 0 0 +324 124 4 0.4238 0.043659843874497825 11.700549431435512 17.548783471249404 0 0 0 +322 124 3 -0.8476 0.6986180999032698 10.969146709178826 17.358832885092397 0 0 0 +323 124 4 0.4238 1.5437602904086145 11.138573552128177 17.86581552014627 0 0 0 +520 190 3 -0.8476 16.497913500683367 13.608830531340717 20.099224242174998 -2 -1 0 +183 77 4 0.4238 6.061108779415605 13.35100663171201 15.500644142396819 -1 -1 0 +181 77 3 -0.8476 5.432852358019868 13.221576145595803 14.733479278991409 -1 -1 0 +528 192 4 0.4238 7.947908460965703 10.415144237551592 16.017452267881904 -1 0 0 +527 192 4 0.4238 8.693810029330587 11.679749716859721 15.302586746464218 -1 0 0 +526 192 3 -0.8476 8.723815386797254 10.691157629577742 15.450190140921961 -1 0 0 +413 154 4 0.4238 8.47629321139097 9.924837900824734 19.765923633588624 0 -1 0 +551 200 4 0.4238 6.295140628612961 13.0811562212512 18.595381699645387 0 -1 0 +352 134 3 -0.8476 7.421716948050476 13.052200283352796 19.864348347568836 0 -1 0 +353 134 4 0.4238 8.102450866164704 12.320106124247694 19.838998054827613 0 -1 0 +227 92 4 0.4238 9.529976846550452 13.300151576381868 16.226718397521843 -1 -1 0 +228 92 4 0.4238 8.58524448668043 13.865491623869215 17.432744650799876 -1 -1 0 +226 92 3 -0.8476 8.58726918461898 13.46732542687426 16.515432680586017 -1 -1 0 +354 134 4 0.4238 7.8556697820960695 13.919448291047914 19.620279543432734 0 -1 0 +550 200 3 -0.8476 5.420440329517178 13.080782052941927 18.110716314441905 0 -1 0 +524 191 4 0.4238 11.884868441493689 14.448712932136393 15.081249372531165 0 0 0 +523 191 3 -0.8476 11.50361661998975 15.067119970952685 15.76843547762266 0 0 0 +525 191 4 0.4238 10.635428893494353 15.437655673235382 15.438349657119135 0 0 0 +519 189 4 0.4238 16.12596399656808 9.713127165378456 18.774089973722194 -1 -1 0 +517 189 3 -0.8476 15.575253587195496 9.20267771394846 18.11366575383574 -1 -1 0 +518 189 4 0.4238 14.797935848983123 9.761696645097231 17.825082898206848 -1 -1 0 +508 186 3 -0.8476 11.36032110607987 10.395500955326444 19.485415246824253 -1 -1 0 +509 186 4 0.4238 10.574909438442395 10.802916738502745 19.951406129255314 -1 -1 0 +625 225 3 -0.8476 13.431373674817415 12.360229415324964 20.046821494380612 0 -1 0 +626 225 4 0.4238 12.815658302976129 11.572267924143482 20.04324286856607 0 -1 0 +132 60 4 0.4238 13.973033764300695 13.370819921016986 17.597892066875374 -1 0 0 +252 100 4 0.4238 14.626947965687904 11.458256675553198 20.594723533070734 -1 -1 0 +250 100 3 -0.8476 15.446910706815945 10.985490885337827 20.91745283601959 -1 -1 0 +521 190 4 0.4238 16.708490712860183 13.560658918372258 19.12283207188856 -2 -1 0 +251 100 4 0.4238 15.28278621296645 10.621734288846643 21.834373973684016 -1 -1 0 +130 60 3 -0.8476 14.678369605079089 12.957802124288227 17.021768263766795 -1 0 0 +131 60 4 0.4238 14.458348330319499 11.995153975026893 16.86397133682681 -1 0 0 +203 84 4 0.4238 0.33763023117752755 14.034931383383197 16.80850588241971 0 0 0 +202 84 3 -0.8476 17.280677882219976 13.944722872415943 17.510595617565976 -1 0 0 +204 84 4 0.4238 16.38038455006987 14.080495208212355 17.097025000411602 -1 0 0 +627 225 4 0.4238 12.895998920515487 13.20189858279176 19.976338825971638 0 -1 0 +542 197 4 0.4238 0.7514357233548431 18.409811166527543 17.22131458532548 0 -1 0 +541 197 3 -0.8476 1.6321891678483407 18.639355403189736 16.807086616186705 0 -1 0 +391 147 3 -0.8476 4.491135944425146 18.24495480864346 17.323933884799132 0 -1 0 +392 147 4 0.4238 4.35867572061232 18.473941006167053 16.359556499968285 0 -1 0 +601 217 3 -0.8476 2.401796289847322 14.19076268037919 16.055376271388944 0 0 0 +179 76 4 0.4238 17.097847191102588 16.180629654501978 15.206412710169566 -1 0 0 +178 76 3 -0.8476 16.16763103793032 16.039085275960307 15.545032905740433 -1 0 0 +552 200 4 0.4238 4.921378705613509 13.920936803256845 18.323031860347246 0 -1 0 +235 95 3 -0.8476 3.8179023582749987 15.626245156567531 18.280442798179074 0 -1 0 +236 95 4 0.4238 3.9015889607236156 16.56041975973048 17.9335779875284 0 -1 0 +474 174 4 0.4238 1.3938281099787186 17.244378381710156 15.61720555921285 1 0 0 +417 155 4 0.4238 16.829213900498775 17.86385263709467 19.17468317954824 0 0 0 +664 238 3 -0.8476 16.31330980781755 16.489937600377882 20.11050236537085 0 -1 0 +665 238 4 0.4238 16.286507352436093 16.770533199811723 21.06995549510748 0 -1 0 +666 238 4 0.4238 16.36964604463261 15.492998348354005 20.056238228791614 0 -1 0 +237 95 4 0.4238 3.173112662693499 15.61096420027613 19.044650970042266 0 -1 0 +415 155 3 -0.8476 17.22802140468305 18.537375488433902 18.552332663713077 0 0 0 +705 251 4 0.4238 9.342662276321002 19.23551765587517 15.618297870694642 0 -1 0 +566 205 4 0.4238 13.181146270356484 19.36562603507473 20.289515940498255 -1 0 0 +565 205 3 -0.8476 12.315921540981028 18.962773541675908 19.99102173948854 -1 0 0 +567 205 4 0.4238 11.555026103750892 19.500332980563563 20.354434978126818 -1 0 0 +411 153 4 0.4238 12.630285403347742 19.2153458441829 16.63075507902968 0 -1 0 +410 153 4 0.4238 12.651895714100402 19.507371433526508 18.23726711474267 0 -1 0 +596 215 4 0.4238 6.6514078093810145 17.757519545906224 17.131726952309517 -1 0 0 +621 223 4 0.4238 9.32094779449351 16.89261159883148 13.964094343456331 0 -1 0 +597 215 4 0.4238 8.13320198651832 18.265654411012385 17.592933954665543 -1 0 0 +595 215 3 -0.8476 7.634367947932014 17.59815575684757 17.04011269845976 -1 0 0 +330 126 4 0.4238 9.706965875463291 15.583293645125334 19.213496685030627 -1 0 0 +328 126 3 -0.8476 8.837667391066828 15.233920832767678 18.863840186279532 -1 0 0 +329 126 4 0.4238 8.379052771415251 15.949000543126097 18.33626624707152 -1 0 0 +620 223 4 0.4238 8.86418018229449 16.466922123871992 15.472994396666568 0 -1 0 +619 223 3 -0.8476 9.191474593370469 16.125190194404134 14.592029230830551 0 -1 0 +677 242 4 0.4238 11.606354518062112 17.4135854015012 19.509290617242318 -2 -1 0 +376 142 3 -0.8476 12.910170234041873 13.669280959087763 13.670410604783452 0 -1 0 +342 130 4 0.4238 15.099355043551732 15.7895013741819 17.14729243749143 0 -1 0 +340 130 3 -0.8476 14.691352665896357 15.671573647682955 18.05262685485254 0 -1 0 +409 153 3 -0.8476 12.934070775997657 19.850129404667392 17.341223260208253 0 -1 0 +341 130 4 0.4238 15.300574406606136 16.0571625967734 18.745571691918716 0 -1 0 +678 242 4 0.4238 11.697820011038054 15.820826603277476 19.16089332874788 -2 -1 0 +676 242 3 -0.8476 11.085760395622547 16.563145453357837 19.433558232820836 -2 -1 0 +377 142 4 0.4238 12.389327721957683 13.150393614646125 12.992558137112923 0 -1 0 +633 227 4 0.4238 12.150975050009347 14.58692603804811 17.3320178342166 -1 -1 0 +631 227 3 -0.8476 12.563624593567864 14.439408482448403 18.23088427417809 -1 -1 0 +632 227 4 0.4238 13.407238305522702 14.971665072902693 18.301764553117142 -1 -1 0 +401 150 4 0.4238 14.428996277987272 20.00194102350041 17.727272883257537 -2 -1 0 +400 150 3 -0.8476 15.319708893239577 20.19041269993394 18.140928720505386 -2 -1 0 +402 150 4 0.4238 15.18982517096631 0.14146099953284744 19.075632215078734 -2 0 0 +2 1 1 0.004217334499211409 1.4708000000000006 2.5474999999999977 23.511674200062604 0 0 0 +1 1 1 -0.009646358641736526 0 0 23.511674200062604 0 0 0 +11 6 1 0.008218030684364237 2.9416 5.094899999999999 23.511674200062604 0 0 0 +3 2 1 0.001033549197079144 0 5.094899999999999 23.511674200062604 0 0 0 +10 5 1 0.00518887606701035 4.4124 2.5474999999999985 23.511674200062604 0 0 0 +487 179 3 -0.8476 10.236653495137274 0.145864427872912 20.93745027852826 1 0 0 +489 179 4 0.4238 9.828066097123468 0.9796565535099634 20.56617177499297 1 0 0 +19 10 1 0.005324823179772448 5.8832 5.094899999999999 23.511674200062604 0 0 0 +18 9 1 0.002880544028719106 7.354000000000001 2.5474999999999977 23.511674200062604 0 0 0 +27 14 1 -0.00457765761153277 8.8248 5.094899999999999 23.511674200062604 0 0 0 +26 13 1 -0.009572738618142772 10.2956 2.5474999999999985 23.511674200062604 0 0 0 +230 93 4 0.4238 13.928563556680734 1.5055446074937315 20.095227719319016 -1 0 0 +464 171 4 0.4238 15.045155051420673 4.862866706743665 20.375126707934175 0 1 0 +34 17 1 -0.01553742137562577 13.237200000000001 2.5474999999999985 23.511674200062604 0 0 0 +35 18 1 -0.002400379063516555 11.7664 5.0949 23.511674200062604 0 0 0 +41 21 1 -0.02896905738507962 14.708000000000004 0 23.511674200062604 0 0 0 +33 17 1 -0.0363745952158159 11.7664 0 23.511674200062604 0 0 0 +42 21 1 -0.02420540570462749 16.178800000000003 2.5474999999999994 23.511674200062604 0 0 0 +43 22 1 -0.007948234293211202 14.708000000000002 5.094899999999999 23.511674200062604 0 0 0 +273 107 4 0.4238 5.0753239133404575 9.229382676896916 19.59996240932027 -1 -1 0 +5 3 1 -0.005693638015952107 0 10.1898 23.511674200062604 0 0 0 +13 7 1 0.009501309380865988 2.9416 10.1898 23.511674200062604 0 0 0 +12 6 1 0.004203404930459461 4.4124 7.642399999999999 23.511674200062604 0 0 0 +4 2 1 0.01251408387036118 1.4707999999999997 7.642399999999999 23.511674200062604 0 0 0 +162 70 4 0.4238 10.49626201731352 6.799815098606447 19.594261077861322 0 -1 0 +160 70 3 -0.8476 9.605787134419803 6.445564649029472 19.879861827728533 0 -1 0 +20 10 1 -0.008607284016686766 7.354000000000001 7.6424 23.511674200062604 0 0 0 +21 11 1 -0.004896191756267181 5.8831999999999995 10.1898 23.511674200062604 0 0 0 +29 15 1 -0.02813825825945993 8.8248 10.1898 23.511674200062604 0 0 0 +28 14 1 -0.005579254270553642 10.2956 7.6424 23.511674200062604 0 0 0 +546 198 4 0.4238 1.1579498075131722 11.22511062551035 20.52034359271027 1 0 0 +44 22 1 -0.001308966881307358 16.178800000000003 7.6424 23.511674200062604 0 0 0 +45 23 1 -0.0566626999288059 14.708000000000002 10.189800000000002 23.511674200062604 0 0 0 +37 19 1 -0.005877766889753366 11.7664 10.1898 23.511674200062604 0 0 0 +36 18 1 0.0001157691193102936 13.237200000000001 7.6424 23.511674200062604 0 0 0 +14 7 1 0.005848521348572336 4.412399999999999 12.7373 23.511674200062604 0 0 0 +7 4 1 -0.01090660504939763 0 15.2847 23.511674200062604 0 0 0 +6 3 1 0.003727512893892018 1.4707999999999997 12.7373 23.511674200062604 0 0 0 +15 8 1 -0.02615871378048023 2.9415999999999984 15.2847 23.511674200062604 0 0 0 +414 154 4 0.4238 8.618799900704422 9.929833758208787 21.392667183756693 0 -1 0 +412 154 3 -0.8476 8.888565594412722 10.392171148935295 20.547994386549856 0 -1 0 +23 12 1 0.003038043205112527 5.8831999999999995 15.2847 23.511674200062604 0 0 0 +22 11 1 0.0119720834206347 7.354000000000001 12.737300000000001 23.511674200062604 0 0 0 +30 15 1 -0.0004640159590853481 10.2956 12.737300000000001 23.511674200062604 0 0 0 +31 16 1 0.007270268763850805 8.8248 15.284700000000003 23.511674200062604 0 0 0 +522 190 4 0.4238 16.06546508942164 12.755155831821405 20.38944688158725 -2 -1 0 +38 19 1 -0.005817166430377722 13.237200000000001 12.737300000000001 23.511674200062604 0 0 0 +46 23 1 -0.01105048584332794 16.178800000000003 12.737300000000001 23.511674200062604 0 0 0 +47 24 1 -0.00899474344889325 14.708000000000002 15.2847 23.511674200062604 0 0 0 +39 20 1 0.0003381839543199087 11.7664 15.2847 23.511674200062604 0 0 0 +553 201 3 -0.8476 2.352480003313166 16.235506117690385 20.496795756680786 0 0 0 +554 201 4 0.4238 2.075014408980979 17.17478517923389 20.2948805334894 0 0 0 +145 65 3 -0.8476 2.0491389692751447 19.147925155655606 19.86618701962954 -1 -1 0 +147 65 4 0.4238 2.1057321900381294 20.08004855757078 20.223884530204927 -1 -1 0 +146 65 4 0.4238 1.1682593704719069 19.018552992048466 19.410866059436394 -1 -1 0 +9 5 1 0.002797560954409141 2.9416 20.379799999999996 23.511674200062604 0 -1 0 +16 8 1 -0.00898908154146778 4.412399999999998 17.8322 23.511674200062604 0 0 0 +8 4 1 -0.01523070185408367 1.4707999999999997 17.8322 23.511674200062604 0 0 0 +416 155 4 0.4238 16.5271394385928 19.197417604787603 18.281944374175474 0 0 0 +555 201 4 0.4238 2.776284397029487 16.20040204569084 21.401869691047523 0 0 0 +17 9 1 0.002683529706333287 5.8832 20.379799999999996 23.511674200062604 0 -1 0 +25 13 1 -0.02370656583241818 8.8248 20.379799999999996 23.511674200062604 0 -1 0 +24 12 1 0.004229835349690803 7.354 17.8322 23.511674200062604 0 0 0 +32 16 1 -0.001928890613042939 10.2956 17.8322 23.511674200062604 0 0 0 +231 93 4 0.4238 14.85513137299608 1.0083962689014228 21.344604479273965 -1 0 0 +48 24 1 -0.02799231331453521 16.178800000000003 17.8322 23.511674200062604 0 0 0 +40 20 1 -0.005168906099793637 13.237200000000001 17.8322 23.511674200062604 0 0 0 Velocities @@ -770,1359 +770,1359 @@ Velocities 57 0 0 0 58 0 0 0 59 0 0 0 -676 0.0021411732266066546 -0.0031466597050466686 0.006950385069113567 -677 0.00471300605204294 -0.010676608272384733 0.0027534373566423364 -678 -0.008823855984279599 -0.007959499471369818 -0.004534651421080043 -709 0.005380424876014373 0.006307583340186229 -0.0018881938332245358 -195 0.0035011066672069953 -0.018982633794167522 0.013387657244058954 -193 -0.0016243730866856681 -0.0009043410307212374 0.00442651336838353 -194 -0.016844359613345537 -0.0020052459554273784 -0.01311294231282549 -103 0.0015806838149129447 0.002560824201124871 0.0047168491592377345 -710 0.007830390266471615 -0.009204470955483884 0.04052260106336803 -713 -0.011412032208487173 -0.0013968159548142917 -0.01011897403656863 +170 -0.015565801323246945 0.011553923587055334 0.00011655885423701334 65 0 0 0 66 0 0 0 67 0 0 0 73 0 0 0 74 0 0 0 75 0 0 0 -712 0.00439112600296801 0.00360710731488533 -0.0039525073869872964 -714 0.014803144807230072 -0.010674744767348688 -0.003430825293082879 -604 -0.00011827390695045583 -0.006806704613944644 0.0027321887706147296 -189 0.008154941183069432 0.00402238852258463 0.006084124951427027 -170 0.0013361044299764954 -0.00017168208250770554 -0.006118458408511565 -315 0.0037328380509703343 0.017096489497345373 0.013207513139570021 -605 0.003503171355645862 0.00393175960965181 0.01269038834140635 -116 -0.009757167707959114 0.010598646892323519 -0.010231402748289127 -388 0.001747370305520368 0.0018503925217209565 -0.0005923969541604404 -389 -0.02015066489450734 -0.008493989807482257 -0.009473043666461643 -586 0.0050721953206553675 -0.002995629227084019 -0.0022560086328735564 +339 0.009050739203913844 0.0013966839274111471 0.0018201686444279928 +655 0.008427072647088075 0.0006319785638995712 0.0038333297014463124 +219 0.004936273877479474 0.014881086295152265 -0.026501890988539768 81 0 0 0 82 0 0 0 83 0 0 0 89 0 0 0 90 0 0 0 91 0 0 0 -601 0.0013661096020166409 -0.003796167035264375 0.0063671190647323125 -602 -0.008528174022195655 0.008966924162453272 -0.0044782466696049895 -107 0.002028194218827179 -0.012365773885091972 0.011299553506975946 -603 -0.0030874748643350066 0.0020597842518737266 0.005359799428542693 -378 -0.009420735022443168 0.009599931914543234 -0.009184011191465311 -422 0.0010193233677437787 0.005769570923430941 -0.0006033266822692004 +422 -0.006013872800717573 -0.014299169073987292 0.011787290530609689 +311 -0.0035005696212290246 -0.0025619143601447055 -0.020644600964886833 +121 0.0033895387366071708 0.0029511322370656483 0.002475063911206653 +122 0.006429509891969969 -0.0022696133618547894 -0.011704037009368165 52 0 0 0 53 0 0 0 60 0 0 0 61 0 0 0 -316 0.002099526043199114 -0.0045408329717682855 -0.0028575294101176726 -423 -0.0017639729433514052 0.002384599378075939 0.006405279839456641 -421 -0.0026843238108787987 0.0046959324815539945 0.0006610392109797653 -643 -0.003182764168498806 -0.002245164669701677 -0.0020501158160216556 -644 -0.02278045268171879 0.008802300249148224 0.014781779450300365 -581 0.014810628036019674 0.0056131550207308666 0.001138473889555862 -426 -0.01183599814307284 -0.0030118119812299515 0.011634339637079983 -582 0.011911283072524504 0.002506814749779835 -0.001888380076239702 -299 0.00994979834473168 -0.0096597572982869 0.006175710613675385 -691 -0.0026712809298204015 0.005580991440600302 -0.005608206061799583 -693 -0.014851955236401738 0.019823950564919104 0.005329652535995544 -369 -0.014885149160620455 0.006101800275190467 0.006812320026047257 -300 0.0008158139232951453 0.00232745268131941 0.00015792455194356278 -367 -0.0049456849226559435 0.008314528563211335 -0.002138833331259298 -368 -0.005849586902335537 0.016404409742447917 -0.023365351477116908 +279 -0.004503246475321911 -0.0019896359221923837 -0.012622036989509512 +371 -0.008396587696531819 0.0055149451013554035 -0.01218971454894145 68 0 0 0 69 0 0 0 76 0 0 0 77 0 0 0 -169 0.005590524540675908 0.007794464783479033 0.003654628816346811 -171 0.012286139005426607 0.008057541351814898 0.0020922247023472014 -425 -0.016526775746840687 -0.0019895804930743877 -0.0012848640610859466 -543 -0.008403263122905095 -0.010110530886943685 0.0016250745100911436 -522 -0.00235343490059379 -0.005821725621201975 -0.014831986110216069 -541 -0.002052849658527383 0.001446847447984322 0.0015600130792332112 -520 0.0005441812914655316 0.0020611556729780707 0.0017969804508576564 -521 0.01905794717342043 -0.002386834191950047 -0.0014130319315243112 -213 -0.0036990379004162195 0.008707625631414345 -0.019663536410738924 +485 0.011178139277846433 -0.021617084858181413 -0.005247077888543972 +408 0.0016835580349242782 0.010384878087276615 -0.011894462536384614 84 0 0 0 85 0 0 0 92 0 0 0 93 0 0 0 -211 -0.005623424343732137 0.00041450752084430637 -0.00187652360271947 -212 0.006534163449200209 0.005670602877114846 -0.0069945707656233055 -205 0.008555811513959347 -0.002709371287039603 0.0014234983072410974 -207 0.01677499159222979 -0.003385261115317942 0.008761159144685641 -206 -0.0001887616937573145 -0.004069535594198049 0.0036374306485813203 -188 0.0030565470233890027 0.008303749761324268 0.0014899500510024226 -104 0.0036813924474077115 0.007994502590776614 -0.03313731805992863 -240 0.010056751094400922 -0.013332457722194798 0.036809456838136606 -186 -0.0012950439927692653 0.002894648277169305 0.006583342682271782 -627 -0.011158521584990703 -0.0009662710867750767 0.006042395691770004 -679 0.006444076291197415 -0.0014424205891745063 -0.0014998614075233054 -298 0.001415424120738642 0.003068364998106709 0.004182110752503899 -498 0.0015425122749562377 0.016719318190993645 -0.007505001561501574 -242 -0.02456132712089157 -0.00499984312835767 -0.017843586754103514 -497 0.007139149173339814 -0.0145879096307924 0.012441864775946854 -496 0.0010186556613462456 0.005655575482822908 -0.006762667135991682 -243 -0.007715796816331542 0.008719348744647202 -0.007300486873615359 -653 0.010449033256064723 0.004309437854212114 0.000935271957518078 -291 0.004183977929022222 0.0034791720281195566 0.008654935223702453 -476 0.016439414220948263 -0.0010854446635568742 -0.046096342306847136 -626 -0.004396560653690805 0.010758464422674686 -0.0049427779061986445 -187 -0.004442223772804815 0.0047589723343784175 -0.0006148440280884378 -198 -0.017122202248149542 0.004671830831065398 -0.021591592448874278 -477 0.0040737641278782745 -0.04058404020647128 0.019242920253909494 -385 0.007886786472273232 0.0013311289547582469 -0.006409370965421947 -432 -0.005112477606678751 0.009856086607739475 0.0027357065631810756 -386 0.02463926635147559 0.016683088148706424 -0.009438473091688007 -387 -0.00010606347230315728 -0.0020318345731269952 0.018980717561988752 -431 -0.007493012343989028 -0.00807857236319325 -0.009881982085251819 -430 -0.004524910755669161 0.0069218123924701105 0.0028532664656262 -475 0.0005240789999880052 -0.0036600642125827463 0.0005837376117434307 -577 -0.00039257654752591074 0.006216233007986547 0.002821290791104702 -578 0.020057630069978766 -0.004246264624556574 0.02613706699373874 -579 -0.007622100966699831 0.0073994147205036324 0.0020110299310591565 -282 0.0008362717929222001 0.0042467846601403755 0.0027792731068598457 -281 -0.0022527029426062414 0.003975642769665842 0.006531907364618286 -280 -0.0020932155844553303 0.003303421993385573 0.005106114099904367 -576 -0.021795680954640875 0.00033248379966947404 0.0035909079681866697 -115 0.0009651319566518861 0.001613687366934229 0.0031050301198059047 -117 0.007092275821736963 0.016601328333389103 -0.010174399596936017 -654 0.006666123396093453 0.0034820782549897476 -0.007548491071939311 -196 -0.007724650614744938 -0.004434335618261068 -0.006100969448446816 -353 0.0012893706598156962 -0.003696189678514886 0.006810683602718142 -575 -0.00015451142420669985 -0.007903206226872591 0.0053590040277165804 -390 0.0019318952353184432 -3.915485612460652e-05 0.02512946163532081 -468 -0.02149606396352213 -0.014627346139848459 -0.02322137074184742 -680 0.0021316175435442384 -0.006654962178855455 -0.0001873582646005704 -401 0.010401215314564395 -0.01960362072239097 -0.01515973547470601 -241 -0.005230192439982171 0.007020204461620798 -0.0013500646300778566 -400 -0.006812157761295941 0.009089711854151245 -0.0036543826545893435 -562 0.0019804650115473567 -0.00028603596969985575 0.005858052848098717 -563 -0.01218620597672023 -0.015524824921392979 -0.008793186490164185 -564 -0.008935569769710614 -0.019371477501039753 0.004169465211802351 -687 -0.02132702946477968 0.002624497943599152 -0.009338031127366477 -467 0.012537198784621843 0.002965885297784254 0.004720391558890157 -666 0.00798795194024716 -0.030319685798422914 -0.0020188158019839183 -664 0.004749322796011822 -0.0043766561886238765 -0.0049774737380464725 -637 0.00588099891901965 -0.001216339123192569 -0.0026242446564109594 -290 0.014516979272844701 0.0015897248385656547 0.005707976744589011 -652 0.006850034980395777 0.0026782797648557486 -0.0015069280546491383 -402 -0.0034976084774069804 0.004535202116435988 -0.005087829093657203 -257 0.0012607025312018137 -0.009368212646836838 0.006968118390459642 -256 -0.0018478117849684223 0.002025941765796813 0.003727441819147934 -424 -0.006901245522197137 -0.0013303335985025966 0.0011059441800063592 -665 -0.004108673022343136 0.02756341408187244 0.004998477269975495 -122 0.03325733328895117 -0.009837145275822285 0.010300807091427751 -258 0.02352477625978478 -0.000800587290288175 -0.002937467081773502 -466 0.0008211706166287764 0.0037786952682420934 0.0028864889717026224 -377 -0.006791525954268541 -0.012741664603392176 0.008960836876523243 -105 0.0075254897454936276 -0.004097719399251073 -0.012147216735037885 -580 0.0037274873834820628 -0.00451385869218868 -0.0005479283373083121 -638 0.02378979194655618 0.01258017180535563 -0.014888606022849447 -717 0.0008536852916907268 0.00758135276550789 0.00866904087809462 -352 0.0013677093267280443 -0.0035327394727749832 -0.0021756600763700967 -137 -0.004025571305218045 -0.0011771198658975714 -0.0028210853387310437 -692 0.0019285659783500123 -0.007498396388372936 0.016327933902900025 -645 -0.006334167147176737 0.0026932034532357765 0.03810632174272965 -185 -0.0258016499999917 0.002966337289661987 0.0192775032868555 -292 0.0032239529951158365 -0.002940539950527776 0.005128379648619589 -294 -0.002882030968976172 -0.009999674767135671 -0.004996218559394716 -574 -0.0017098010265335615 -0.006233341003337626 -0.003130881298453147 -711 0.011550634037340288 0.005661405841651928 0.016230520184342886 -437 0.016623543237673673 0.021126526281754876 0.01525697145973429 -436 0.0011580833433645576 0.001866769096270803 -0.0020668982892715054 -588 0.003788053246840207 0.004318290540820436 -0.009756708962759054 -438 0.002778859820834817 -0.0006615532270598109 -0.0008258015725774891 -701 -0.0077340127867783545 -0.0012750504303974512 -0.0015549160015513451 -700 0.0003771746026641942 -0.005971056101101204 0.00048713541643599623 -513 -0.007685562035241124 -0.003451884123490726 0.011140761717829488 -106 0.0012167401758591842 0.0005190446916700595 -0.0005689566549062379 -702 0.0012360073361495057 -0.014010782072965118 -0.00023435212022074399 -138 -0.00844580607399001 0.002622106272118458 -0.006828542248324802 -542 0.004462053398768184 0.00798739986184309 0.005271563844807477 -376 -0.002635850208642133 -0.0009250576279445919 -0.0022212103610827097 -639 -0.009436328867848297 -0.013749239756427646 0.006593851052360545 -524 -0.005123725178539699 0.015426884373031625 -0.01834347769166834 -360 -0.004178590839375953 0.012772866811974804 0.009637982488128747 -359 0.001703407707272143 0.009108089839648342 0.0055708198881699615 -358 -0.00036687245580791145 0.005831964931051857 0.004159047388106057 -289 -0.001595283063915116 -0.00038607006533445217 0.008644630517419101 -384 -0.0025783811970427543 -0.010842560568130202 0.0002485575154442456 -406 0.008334788236422419 0.0010503441284235345 -0.0023800280127281867 -408 -0.008249724433327414 0.0125860312627397 -0.013608031710222075 -523 0.002630732510263263 0.003918200827993626 0.002970183260485006 -407 0.0010126932985940003 0.004105264448148497 -0.0008185914388617361 -525 0.015007331123588413 -0.002998296737147837 -0.044921726699770494 -625 -0.003508771931501176 0.0027372555782873113 0.0013339734432499892 -136 -0.005107835457616012 -0.00017978248743965154 -0.003988644887833829 -587 0.0006181639400713768 0.001490404492305943 -0.005441807772501442 -184 0.006119642789751914 0.002129260802961511 0.000355130366432989 -404 0.0055448536095734375 0.0007743654867219097 0.016037969196716063 -313 -0.004078044888590166 0.0008247081419541478 -0.0005316362965100083 -238 0.0018177803681502889 0.001226893367767893 0.0007423981284663952 -461 0.0009318635511549625 -4.928350118386009e-05 0.0045466223791930825 -354 0.001972954579596857 -0.0043780296240654385 -0.01077371477183407 -314 -0.009623735019970261 0.00665798742211111 0.02408146022132393 -403 0.006589710410456089 0.007960810210289698 -0.0020320127654004315 -698 0.00031058122010607815 -0.010174080916795681 0.006501436501535736 -114 0.013755765119664892 -0.013815807900815349 -0.008433355002016293 -697 0.0007293039474806055 -0.0017923216167614411 0.003822203247328284 -606 0.008037094668825863 -0.011716121615248383 -0.01219235266766627 -317 -0.014708949199744841 0.009643525399184418 -0.0020141933611741514 -108 0.03603925575757461 0.012858477843299815 -0.009808108963212754 -382 -0.0028195334564676882 -0.0005791679751282715 0.00626241480650448 -219 -0.01247120825189971 0.0030987939456600623 -0.01140054054306225 -670 -0.0009417370514361473 -0.00047014470829927983 -0.002823228428905164 -396 -0.005706783431449613 -0.011306512585110057 -0.009211332176758109 -395 -0.023204652307578223 -0.011850758133780951 -0.014161496708519091 -394 0.0029623638021562065 -7.495431979780323e-05 -0.0017703271435133582 -204 -0.009868889536072716 0.02769142115737454 0.0017278949223337818 -608 -0.00450536239188671 0.002161396364473985 -0.014865545157464521 -203 0.0030390793343812923 0.007253293998996769 0.002638515417395934 -202 0.002472172566760438 0.0031112304950174172 0.005448652165971851 -486 0.0032226946473274958 0.027815340414288316 -0.0050285190432157985 -347 0.011618224126060037 0.010964925075023732 -0.006653010163344175 -45 0 0 2.5892839001447932e-05 -471 -0.007037423015746189 -0.003782108828722424 -0.011604084450051443 -348 -0.007877981592598695 0.00414031561501778 -0.0030371587615563864 -275 0.0027899592485585616 -0.011786738734745311 0.0008697111063236321 -346 0.0014770373743619686 0.003355855691268311 -0.005340974682633985 -572 -0.0025855405956535737 -0.007377959785635259 0.005585381444125606 -338 -0.0070240134955776665 0.004933198476666814 0.0002829725739334517 -485 -0.005851182975421713 0.013136051886263062 0.012654523591979782 -571 0.00834830199522675 -0.0009831706646230961 -0.0015188720646701576 -591 -0.014367954804647138 -0.0282607848831299 -0.0021645959273891365 -589 0.004702184319895896 0.0032133515813428256 -0.002238551119579548 -607 -0.0077765081012144705 -0.000563208567949008 -0.0033449827357436538 -609 0.00272424910864701 0.008195494864301909 -0.03137225773080429 -180 0.0008690738597768954 0.005018713025200337 -0.002945938694498902 -274 -0.005699313791818707 -0.004759962610832066 -0.005872756565232799 -686 0.008217894207660833 -0.0100983629438411 -0.021635270384703958 -671 -0.00024128230687570196 -0.021572647010253177 0.015357674519379468 -672 -0.0012462607034635857 -0.007069689753832631 0.00381563953963042 -112 0.005190774999806905 -0.005729811432305558 -0.0060176087276321245 -681 0.0007714432326670715 -0.004259570858526994 0.0008648677556282801 -113 0.0043631901827183815 7.2629853515748496e-06 -0.016906736065202134 -344 0.0006884579264700855 0.010742221645104114 0.011459152479148704 -343 0.0008499678995289771 -0.0009767427603578425 -0.0031023296178217664 -345 0.0020361124741315505 -0.0003990095428137886 -0.004264505629606172 -255 -0.007269101324618613 0.011421184414796655 0.003680445929695058 -254 0.006698925536045348 -0.0016114719270781995 0.005001912184894123 -309 0.0026873735966253492 -0.003516917240483255 -0.017190081722208775 -253 0.0010722910362563373 0.004038576864854738 0.0014868195441214305 -479 -0.013992183831219059 -0.02537860894898881 -0.00897013602536543 -109 0.002777209346426365 -0.001936144063141461 -0.0069405893687318095 -480 0.018491401867564334 -0.003446569057091999 -0.009085032649696024 -375 0.01146247831539809 -0.002217879718471049 0.0033766238753439658 -44 0 0 2.5892839001447936e-05 -110 0.0019920646548702734 -0.006687944878399153 -0.016768903427213912 -307 -0.0002242679944927341 -0.0028719408963667494 0.001806513745984584 -685 -0.0005070695650422137 -0.004796427068777599 -0.004675336978463182 -635 -0.006874160125070285 -0.0014608020876715408 -0.02409078032412396 -636 0.010895677030626532 -0.0037324590359100168 -0.00047381957852790586 -271 -0.0006627518310477532 -0.0006417588443855544 -0.000925908330851208 -722 -0.008255845250114668 0.00023297165630569398 0.0024535094545625113 -481 -0.005629526983345739 -0.0031242149927506956 0.0037214577831749165 -721 -0.001593152923256278 -0.0007609137655317765 -0.008921595727198363 -483 0.0018748021123651613 -0.0041152897635225805 -0.013180944449052353 -723 0.014252615954590953 0.004118554178258352 -0.011499683175531865 -482 -0.007456018443800531 0.022105815174257835 0.017712618439186752 -210 -0.0015471256324352317 -0.013597641088573208 -0.006216934372877166 -208 -0.0014177674098368779 0.0004455926366301616 0.00017918089607261745 -469 -0.0005997161956485187 0.004690227452983195 0.003880946509081852 -209 0.012946439616943303 0.0003010845740829233 -0.024955441077315038 -688 0.004244333938104657 0.00088687279816499 0.00042834367934795574 -690 -0.01615279858740688 0.013008480696852221 -0.002485959767769533 -634 -0.006715643473882907 0.005128315157175796 -0.0028461075943380623 -689 -0.02883305567581292 0.033940126886677344 -0.002767256806642573 -662 -0.01022324961652937 0.02459966582402962 0.007784567790126536 -149 0.003448328041689386 -0.006877133198457014 0.003969592342967052 -590 -0.02195059781319254 0.033237536847323716 -0.006017526921710795 -433 0.00272180042867418 0.005464940336619222 -0.007183585266666167 -435 -0.00997731338770566 0.018353157147169678 -0.012308600735794373 -102 -0.004933393112589753 -0.0014184896165212457 0.00282315695425379 -140 0.0037442461642616855 0.0008981125403190698 0.017717716926278767 -417 0.008997384653293916 -0.0007344093814239228 0.006883529345814865 -415 0.0010928032033067465 -0.005899521475255703 -0.0035861446547572782 -416 0.010512486392201103 -0.00010648666874990137 0.006727460050107925 -459 0.019803011405952094 -0.03588714256147905 0.008839860703799078 -217 0.0019975096609847784 0.007198832692135352 0.007528959939583509 -478 -0.003112488499603424 0.003929662738660447 0.0028623819844919673 -361 0.0006999918066639268 -0.004357350629198427 0.00022328947844429584 -197 0.0056318114382033204 -0.01769689459774823 -0.010011278507051987 -650 -0.013351051426644498 0.005724197454670781 -0.007295403538761586 -488 -0.0020278193298860344 -0.014631550395182694 0.006454598682826132 -484 0.0007862864811946282 0.005692991164955517 -0.0020259406411123064 -661 0.0014175655249771993 0.002025210035311634 0.0015878833296731276 -363 0.005742013891446284 -0.008837413122760119 0.0011588715258481145 -100 -0.0018359970011427253 -0.0034868726137758537 -0.0012239581668545684 -707 -0.009434545254390386 0.004083690301746898 1.2720907411063185e-05 -178 0.0002213341038015743 0.00042280505641683046 0.0012455284523796245 -684 -0.0016857583723109088 0.01457015268967376 -0.01248668591187947 -36 0 0 2.5892839001447932e-05 -276 -0.01288304297198337 -0.0024180918894788875 -0.009445007106884281 -214 0.0040375473866697525 0.004832098072512322 -0.0011350282263338225 -216 0.003281923037182911 0.012991080014267777 -0.00640293960536805 -539 0.005431350013191119 -0.02106556848906726 -0.00764575525773749 -538 0.004112938902306128 -0.002290109903302108 -0.0010714133951981704 -252 0.014720479077525389 -0.004278515844677452 0.00617407962447848 -228 -0.02651274201810521 0.006169895153203455 0.0026039557167579757 -226 -0.005986759492118269 -0.002624851477283382 0.002437497167111253 -227 0.037359535164647996 -0.005692341539956028 0.0007690705251742958 -540 0.029556683797969833 0.028216009622947624 -0.007637203209894227 -596 -0.000697425483047941 0.001418504974987797 0.0025860571290182237 -215 0.0019872688713270963 0.009030373521039053 -0.0024074898093308073 -234 -0.013734641718106119 -0.006668468740782935 -0.01326772362636071 -706 -0.0074752312033302334 0.005036319412231939 0.0023954321652624308 -708 -0.0008425953758246843 0.009181695196824482 -0.009248661735532846 -373 0.004422144964975159 -0.0017838198122578036 -0.00018027826543031534 -272 0.013275855183390188 0.014396950748917418 0.0007514222935930509 -273 0.005974305377988905 -0.0017929350389151585 -0.004011080458908929 -362 0.005928696718884773 -0.0061635334731560834 -0.0070875384379755196 -597 -0.011587275738507787 -0.0026775845755159858 0.005599952012635736 -519 -0.010602493961103342 0.01561109572005503 -0.004366769028339268 -682 0.001983241531391707 0.0001436343494854703 0.002165088698424475 -161 0.009978689554182 0.001974367386088278 -0.005346935314707327 -683 -0.011175053949123178 0.011604486671463417 0.005680469507150669 -339 0.011317559380578967 -0.013840330482369045 -0.013807747849132778 -470 -0.012260116006234724 0.0029555761306863846 0.02022738168370677 -595 -0.0012887047489432875 0.0007223671835801802 -0.0028794772050928733 -649 -0.001959620111970716 0.0027086652664905795 -0.004508497780011865 -179 -0.008134269078556558 -0.018166688138021095 0.0007578460469746819 -308 0.0220712849298707 0.00809270514744733 0.0063544521946541635 -663 -0.018587653237992264 0.008058025396004323 0.003021049320538634 -337 0.0009033685485476928 -0.0015102179823566727 -0.0064849412993145715 -327 0.00783068755116193 -0.006919671129723819 0.007255760426290675 -325 0.0014839226012046617 -0.004293646082977329 0.003541697150309064 -326 0.009138500341898103 0.016222223033475605 -0.004576555598052157 -535 0.005511650342351115 0.003976008787370079 -0.0035332740014495886 -537 0.00039714859735720515 -0.0034221246954245044 0.004417018509094299 -2 0 0 2.5892839001447915e-05 -1 0 0 2.5892839001447912e-05 -11 0 0 2.5892839001447912e-05 -3 0 0 2.589283900144791e-05 -10 0 0 2.589283900144792e-05 -9 0 0 2.5892839001447915e-05 -536 -0.008139619366591666 0.023305802200695613 0.020099395824835317 -516 -0.01472371433290118 -0.00947034405699238 -0.006759743057624231 -111 -0.0005643300911320225 -0.00203649367262994 -0.0031700572161786175 -515 0.0021658009569283476 0.013002309599111122 0.023091810824977285 -514 0.002194248370768298 -0.00477869990315876 -0.001376235961931239 -168 -0.007642051948728814 0.0025148703254984145 -0.0010089913229547366 -166 -0.0018884353605177553 0.00853020828258679 -0.005584376923825304 -17 0 0 2.5892839001447922e-05 -19 0 0 2.589283900144792e-05 -18 0 0 2.5892839001447925e-05 -27 0 0 2.5892839001447922e-05 -26 0 0 2.589283900144793e-05 -25 0 0 2.5892839001447925e-05 -434 -0.0131141501224289 -0.029735168306092356 0.018069386056516087 -41 0 0 2.5892839001447936e-05 -42 0 0 2.589283900144794e-05 -43 0 0 2.5892839001447932e-05 -33 0 0 2.5892839001447932e-05 -35 0 0 2.589283900144793e-05 -34 0 0 2.5892839001447936e-05 -518 -0.003364650601080657 -0.0025510701028415793 -0.019031077701915526 -101 0.0066056761815660925 -0.025335359921442018 -0.0042522676779589135 -517 -0.0042150036150125966 0.003039265084075177 0.001234238912865041 -150 -0.003263779481471764 -0.006968079925877713 -0.0285427305003533 -37 0 0 2.589283900144793e-05 -13 0 0 2.5892839001447912e-05 -4 0 0 2.5892839001447912e-05 -12 0 0 2.5892839001447915e-05 -148 0.004337680509183382 -0.0024120213706328784 -0.0023459000779718947 -5 0 0 2.589283900144791e-05 -167 0.0022761530768332797 0.0009747010232492098 -0.004993243345757521 -328 0.004462110300378782 0.003171460897117234 0.0013533076822872438 -329 -0.0028078357210696643 0.0006206344128711716 0.006200475106646407 -330 0.030738960581955917 0.003287330484129426 -0.010708188876434703 -28 0 0 2.5892839001447925e-05 -29 0 0 2.5892839001447922e-05 -20 0 0 2.5892839001447922e-05 -21 0 0 2.589283900144792e-05 -457 0.006550818533058792 -0.001884276384381016 0.003039243394733296 -573 0.013975969924696937 0.0024199182318704903 -0.0034702509100560364 -651 0.015420309153338693 0.010283570358113264 0.02634159883149936 -218 -0.003395956296838163 0.00547325260028855 0.0019942972776871965 +693 0.0016850498482422836 0.012795588923833173 0.008819177076982475 +691 0.0006659466365485686 -0.004801790379394271 -0.004167147629911888 54 0 0 0 55 0 0 0 62 0 0 0 63 0 0 0 -192 -0.004363758761444326 0.00951161221484961 0.017129944705041603 -119 -0.004701077453742114 -8.296328219091687e-05 -0.0009688745560292821 -118 -0.0009314150513423432 0.00027605062629613427 -0.0035150783233501826 -191 0.00680583753605197 0.003167173243801115 -0.015417719909486413 -190 -0.0014967223491699952 0.0025908878048932016 -0.002402175301537957 -98 -0.009260175858086675 -0.028226198550552986 0.007567183856183354 -120 -0.0034806697031884997 -0.003298183743718096 -0.004362434174689871 -97 0.005989233619364602 0.0023803823609934273 -0.0030417661760985806 -244 0.0017880362939288001 0.00422352421710819 0.0005606753077441453 -99 -0.006220115534110591 -0.002045805635333923 0.0006476194511692398 -631 -0.0033826096876896855 -0.002181941878393241 0.0025269093094629474 -295 0.0006648861314364348 -0.003931280096251278 -0.0026803518350101033 -296 0.0062929742791497266 -0.006194372009187594 -0.024124245716887833 -336 -2.5155253934298795e-05 -0.00267261595791318 -0.014156428435828225 +537 0.01468949321341597 0.0002955070862203851 -0.0005770601442394362 +536 -0.013636100182219493 -0.03966146462346522 -0.016320795623323316 70 0 0 0 71 0 0 0 78 0 0 0 79 0 0 0 -334 0.0001249108228848411 0.009592140759049824 -0.008055311762730182 -335 -0.008933120836296046 0.03861648264199437 0.005139262991883574 -656 -0.012795486572600556 0.01001730917412183 0.010504777975066928 -655 0.0002453631990046368 -0.008270009402721512 0.005790081828127683 -657 0.0059063953119072934 -0.011220436899447496 -0.011461093784466869 -331 -0.001861800330708783 -0.004080943128134591 -0.006024367439539751 -225 0.008847588531356471 -0.005432354583684017 -0.017291462941727266 -223 0.0018512701070779799 0.002105046598030068 -0.0050342839053457425 +212 0.01705537091061074 -0.004886408006080845 -0.003352178696340439 +197 -0.016828593668849028 -0.006738778640958227 0.014672615750273036 +213 -0.006844285828259031 0.0005504793122972704 -0.01690321699919477 +211 0.00047763896071806983 -0.0032200506515021304 0.0031358523377286716 +531 0.008315679787373681 -0.0029449319799378826 0.02301150358070123 86 0 0 0 87 0 0 0 94 0 0 0 95 0 0 0 -246 0.019304488124036106 0.012412888772496453 0.01389232978530525 -224 0.011417823406336933 -0.02584104798241233 -0.01586969560916166 -283 -0.000656343011071711 0.0008016291011868049 -0.003620593475455601 -285 0.0051281146563605 -0.002140065887603185 -0.011749359473630993 -284 0.002108917603863087 -0.010745428739586635 0.004067661946326833 -135 -0.0019613502216042204 0.0060261613203991815 -0.005145175930284868 -128 -0.01091600795889493 -0.005359155172554258 0.0011735199042172864 -641 -0.0047721234085586475 -0.00089548417111443 -0.02881249647727017 -694 0.004306853434289274 -0.0003461190629024837 0.002613610137021579 -508 0.0038336193257742066 0.004428638671902145 -0.002578190874375256 -365 -0.0008789666156448981 -0.01647416448186925 0.005405726875929458 +173 0.0018108173359719039 -0.02194729107444219 0.03303638780801747 +529 0.0018196663303762268 -0.0019337872361304407 -0.0004951331903322852 56 0 0 0 64 0 0 0 -264 -0.005069066816637629 0.008594012902267328 -0.004896454013501075 -262 -0.00411559201856892 0.0055846035307135136 0.0022939832937934027 -303 -0.012248995229285456 -0.02038598577770783 -0.0067506409467423655 -263 -0.007203606603798386 0.00015673233657838596 0.009479088778907655 -696 -0.002403944998986855 0.012547542006427242 -0.0025721085279788183 -555 0.010313716462669934 0.017093518256946594 -0.0007535353716470382 -460 0.004762464388993355 0.0035128765813662345 0.0002544426222686458 -357 0.0026975244838181372 0.0006296683369134417 -0.004187815650450881 -355 0.0009889367525614406 0.0028571604624972836 0.0044422297391537215 -642 0.011684188963247771 0.02173040302358248 0.027637684910990796 -440 0.004733172069375852 -0.0006744085975210469 0.015964767016019198 -441 0.019273424633345186 0.02031857101103021 0.01136636551406023 -248 0.005408140991082604 0.01948553192838653 -0.01769576815856515 -439 0.0021888008868001167 0.00022281918895093757 -0.0005699233777872146 +549 -0.001085187706420696 -0.00574725337910797 -0.016056269313645996 +547 0.004373179305666361 -0.003029062157355542 -0.0017211998966215611 +425 0.010010309618889898 -0.004056891961561442 -0.025365538726182652 72 0 0 0 80 0 0 0 -593 -0.010764868078727771 0.0004632189843140992 0.03371192356674729 -592 -0.0012510047155927621 -0.0013228538172386057 0.0030004231674896093 -594 -0.003138799668445178 -0.009265431891145101 -0.0035030936801646703 -229 -0.004015308077517968 0.002304541027168982 0.0018452763612786536 -356 -0.00439289027906843 -0.0003181501233854808 0.007804079534610549 -443 0.01501004287837676 0.01274826059103139 -0.0008103413168549527 -230 -0.0033363552955116165 0.0011395679198842948 0.002421577058286637 -442 0.004590428851528285 -0.00016647082324879346 -0.007536939151246863 -444 -0.0004709522261627252 0.0007916817345592208 -0.01857710544198639 -231 -0.005563876064052946 0.001516515443061688 0.0011917788782933065 +584 -0.02113256914273244 0.00879913545422227 0.005306119166035373 +512 -0.009668620362088287 0.0057211811089109554 0.003791885288692614 +351 0.013871895197824322 0.0037677016362735807 0.03166326938297827 +350 0.0004693304380701279 0.02107627618636817 -0.0018376988073814104 88 0 0 0 96 0 0 0 -553 0.002310850563285711 0.0038622245684212407 0.001063744581887175 -554 0.020520241141740107 -0.005768318995011451 -0.008503556427794993 -699 0.009769647936468813 -0.0026398354232907723 -0.0019420937862542735 -247 -0.0005440687793801106 0.00533274551270155 -0.003116117624827588 -527 0.0018514500777837737 -0.009230378273878258 -0.0060158525133069156 -245 0.005556414067735625 -0.0055651124084785675 0.0033327958619201684 -633 -0.006228493799001829 -0.0025536564906557587 -0.008694681481617547 -123 -0.0013254634442550768 0.0063472029134561585 -0.011594854053242773 -724 0.009989087181242503 -0.005372152351255475 -0.0018551724238006096 -725 0.028063127915331425 0.0036594616018658425 0.019379030908003192 -342 0.0006491711315738201 0.016203183514455405 0.0023688436726023014 -340 -0.00433735839176797 -0.000495918764211808 0.002257318744322688 -341 -0.0006929018962787288 0.015189606179435388 0.0018137275128837062 -364 -0.00882244249614916 0.0034576704590505883 -0.00811983159685899 -726 -0.01855210191687358 0.024009648567330344 -0.010178733951576051 -503 0.014134059605139943 -0.004326106316946778 -0.001926850902735659 -502 0.003759520085920061 -0.005572417624353865 0.0038047544622829043 -504 -0.003935710721857757 0.005577813760648028 0.013790854542965157 -413 -0.021593565939491674 0.003234704353097422 0.011974405473584714 -278 0.00883327301294058 -0.013449834793822607 0.020644593756055547 -270 0.00781868067364934 0.002754459504676058 -0.0010544004588571533 -719 0.006398783376387078 0.001946288912145545 0.022229144951245915 -132 0.007832425765429163 0.011404797448368427 0.015400661765000056 -297 0.0038792006849247243 -0.007593554626325106 -0.012809257149632622 -392 -0.011715180257929931 -1.176189615249834e-05 0.009633360116141418 -260 -0.009423773124827882 -0.023186194647239755 -0.02190022720812517 -548 0.009629883272752136 0.006774886139507993 -0.020907198728238808 -302 -0.007841165533640462 0.003026014956910295 -0.00703538244890269 -259 -0.003426942147231846 0.0014749707614869303 -0.003444717877250437 -261 0.0006945604695285328 -0.010576783124679686 -0.0020734669000596877 -640 -0.0008886178358934431 0.0060434330372213935 -0.010383480842809305 -532 8.241792411033156e-05 0.006040661450994054 -0.002463893772382022 -235 0.0007038770519582305 0.0067292095538841615 -0.0028443681465380494 -533 -0.0002129926328668816 0.00488451374048223 -0.0028066827071909287 -534 0.007064961280930333 0.025232242617842127 0.0008574875214082739 -621 0.011287366443141251 -0.003449176508228183 0.017928382611092662 -121 0.0007022815589027053 -0.000892538811671254 -0.0018627823896997114 -269 0.00469009840256279 0.0015241035513903975 0.001984306143110744 -265 -0.0054586758884403105 0.002131291238446908 0.001153323924828889 -547 -0.0011175811849537705 0.004103087625132249 0.00078716134613171 -619 0.0003632578854721528 0.005362253640767787 -0.006417849782413687 -279 0.011624081133984786 -0.011774327315428757 -0.014995684102348524 -293 -0.0017466342827571289 -0.002552253740249767 0.002528434692005852 -695 -0.004911630333401857 0.008651651256560356 -0.0020402912967414214 -494 0.005776310030291935 -0.000219217384465697 -0.0012280489592709103 -131 -0.018436321747528253 -0.021208301175051184 0.0006884707536230596 -715 0.006546258488425628 -0.005755050576697564 -0.0039883518170252905 -239 0.011588133086593538 -0.011846815428878082 -0.00881463043856705 -414 0.010325867114536506 -0.0006113612193524784 0.0017105622669241444 -648 -0.0026558023935934014 -0.009616362543538188 0.010264407433954103 -646 -0.0003042619186802288 -0.006311024166021424 0.0031010083811757994 -565 0.0007394748342163842 0.004516477559592657 0.00033539363242210933 -566 0.002090696563890277 0.0033273332142688904 -0.006266252541019348 -544 0.0007700118900610095 -0.001389627444945187 -0.004115546441642321 -546 -0.008050688006328074 0.023127963394541477 0.006164274038600667 -545 0.005924140141637715 0.001350652630120117 0.004941780161927939 -495 0.0069079619862543245 -0.007627704476709708 -0.0021154124154080375 -647 -0.00017732064807360345 0.002645796003071014 0.007429648590994952 -493 0.008654158253716833 -0.004029112678793171 -0.0016991226950217582 -301 -0.00533271211616937 0.007677255432536089 -0.0016339575663828834 -127 -0.0017719186381853886 0.003534213331123468 -0.0014256780429603613 -266 -0.0005212803553580399 -0.010749716358853169 0.007192928429952392 -391 -0.002578132714595172 0.0014365390200574261 0.0008211021077538514 -465 0.016880882832760326 -0.01067083624985097 -0.00022780999411606596 -333 -0.002918705357704968 -0.01118788463028499 -0.011006638219927969 -366 -0.0034141036467909827 -0.01084067671589307 -0.0004984580617246783 -267 0.006279258266850698 -0.018295845749178304 0.003999927664413487 -157 -0.0032474639721635297 -0.002071067218862699 0.005146248544668708 -412 0.0010230248589894202 -0.002669542251526284 0.004046648042845933 -393 0.003984235524416656 0.01206305025975438 0.007338917088694135 -405 -0.0055971864668224415 -0.001835879479675777 -0.0003608610575552909 -448 0.004430595048261473 -0.005005222921986947 -0.0018506673587511161 -449 0.01637776697980032 -0.014127790377349642 -0.00434461965343095 -584 0.013793791431671172 -0.009326091804055824 -0.01747981576570497 -585 -0.008359394537154218 0.009831653490172253 -0.015131425117590833 -318 0.014260723165817455 -0.002876736345312385 0.01741120858595613 -450 0.016867039987388758 -0.006826024777415599 0.0014250845205727915 -159 -0.0020686816783562546 0.023218708679260347 0.0005679898884230374 -277 -0.00031624432316685767 -0.003276417788006159 0.007206583965036211 -174 0.02232250253907675 -0.01231852993148094 -0.010546896918912205 -158 0.009085924338852294 -0.014728147944420766 -0.020912169525047947 -236 0.006765120985488478 0.005926831661173007 -0.002318291635240894 -332 0.0042747818750445725 -0.0017899782198140476 -0.007971038141225751 -567 0.002235629448123555 0.003016503143010697 -0.003392544405989525 -268 0.004011420131944795 0.008377084166031164 0.002316053989518986 -144 -0.012024612981489083 0.005361811091711969 -0.0014672866723572583 -143 -0.0073730174733633545 0.0040880726939264795 -0.0165900644982253 -620 -0.0065142327069454865 0.035190802650504636 -0.0006640427681044298 -142 0.0028419016591640558 -0.004087187698190576 0.0037294719979222247 -129 0.008463487923697903 -0.0015510850454567688 -0.015170037898573475 -549 -0.0025830067012953825 0.01852116530899133 0.010385008510639499 -583 0.004268963968694046 0.0010471359047598279 -0.005851219475190436 -718 0.0006430494717885148 0.007923101925764318 0.004010379569037137 -237 0.014352864654346011 0.01020811390215342 0.00047127720322738515 -462 0.005064298161311936 0.0015423027868889188 0.008335104423218753 -130 0.004406284567008871 -0.00860513254615911 -0.004879385522234749 -720 0.00393831447904276 -0.006119628459627095 -0.006764066218979042 -383 0.004218653914705313 -0.01202327645784736 0.022980672819351747 -133 -0.00102039624254495 0.002371407198966068 0.0067364713751238425 -511 0.003912741513012298 0.00101552438914296 0.0018958766721141054 -134 -0.0033610434450266286 -0.0026284616742153787 0.00674072004379062 -716 0.010566057481285352 -0.02176428147337611 0.007168160969202919 -512 0.01634597212601708 -0.0002926570645188546 0.007738629495829494 -509 0.0011140510641293316 0.0007182760943427564 -0.014628144005186052 -568 -0.0039044314646687196 -0.006830451357868171 -0.0022373549345757774 -569 -0.0013290493571988461 0.004839537419246563 -0.006910692862670655 -304 0.0054736539006658485 -0.004960430228645577 -0.001968166657216059 -305 -0.012109090513145905 0.00577200024652643 0.005396896203310628 -418 -2.437543145425559e-05 -0.005689015414779892 -0.002258568108083334 -306 0.011459516326170439 0.0007872800806459576 0.005803298963212287 -501 -0.009350152887850311 0.003677986993344379 -0.011989987989375296 -445 -0.0008290701903718754 0.005643282980849799 0.0002485307221862214 -463 0.0004729541684906896 -0.0009865037215842994 0.0002106726307666064 -172 0.004731719855505472 -0.0030321314569809483 -0.0003530081265682011 -489 -0.014429505694453698 0.009455042753152534 0.01903652416959836 -419 0.0025409339530107623 -0.002879625146716656 0.0003702102460500956 -446 -0.00021411000691779435 0.00955825379875846 -0.00885753338160607 -420 0.007536051380740864 0.010381989365120456 0.005336366205111886 -499 -0.0006342662881036965 -0.00023501992000385272 0.0020560303434147245 -500 -0.01195099663304182 0.028212202950552916 0.014770929928671189 -250 0.007361035395654199 -0.004690688159251201 0.003061239445099873 -147 -0.009310962727936977 0.020391157953635785 0.03074647165589922 -146 -3.6811505540478325e-05 -0.017980254752765046 0.017302450341036273 -570 -0.0017712854514889199 0.0019656582840076615 -0.002982248494982292 -323 0.02025520719624794 0.00437956264756661 -0.0018309996628302016 -324 -0.014124442777214079 0.011549999461420518 -0.018237952404482057 -322 0.0016068916953904174 0.006306614444237204 -0.004315464210736402 -200 0.021753072613096884 0.018573023333333702 0.004427859217421257 -623 0.011452678250841558 -0.007224569524583359 0.0027236085578886244 -551 -0.014919499049456707 -0.01686470199682272 -0.009390344835571803 -201 -0.023111043546362873 0.00020560246955362896 -0.006295323851049318 -199 0.0004815918368625051 0.004853422247417755 -0.006061618709908838 -312 0.0008481996440953347 -0.006155473605828348 -0.0017282663370451403 -624 0.001586490607358962 0.004010243402294628 0.0059810887166708345 -350 -0.009760147323275311 -0.016632875743950715 0.016528153602606437 -126 -0.006532699294053725 -0.012656386469316777 0.0068195173267290715 -622 0.0024139583689417247 0.003498498050067583 -0.003655007006662313 -550 -0.0012162513220406828 -0.0033011033267567416 0.004819001835822252 -552 -0.00924649718960619 0.0013741774004242453 0.015653387667881418 -124 0.0001705708408269096 -0.000550279279659424 -0.0013377042655839796 -145 -0.002334830495624088 0.002793853156377406 0.006506801380971504 -40 0 0 2.589283900144793e-05 -599 0.0023217932209911667 -0.01835053819969972 -0.013463199934529201 -251 0.002581923394498151 0.0023298657256145133 0.006255129412513726 -704 -0.005296929928288727 0.01607189461778198 0.010179684267012322 -703 0.0034655840261788758 0.005574906464163651 0.005889701146370732 -705 0.010861930940493255 -0.0003350694921833778 0.01044180291497366 -48 0 0 2.5892839001447932e-05 -559 -0.005483933645194205 -0.0012780353966408038 0.0023721586219114825 -561 0.01337950290190957 0.0044607660522192946 -0.01823291897146361 -675 0.0031193771284579496 0.00217714638874969 7.001676744408073e-06 -222 -0.006345175465281138 0.004820356905560499 0.023282345551168215 -598 -0.0007217641988605089 -0.007385715555506205 -0.0009079271908534197 -177 -0.01851185003563661 -0.00016629752608533365 -0.012976887019520758 -310 0.0012985833227644886 -0.001566855158339641 0.001579031386051685 -458 0.0039239799167950645 -0.007481014210507378 0.009788403085109105 -139 0.00033494528818851267 0.0024585397677852625 0.000660401833580898 -614 -0.0009389256816982662 0.011828643953531368 0.018676419298217065 -600 -0.018094474476051486 0.00023445740586081488 0.008899796958011633 -617 -0.009036194427037533 -0.0025641807901169078 0.005251509094796726 -311 0.0010927413625261679 0.0024725292678410946 -0.0033258539523485773 -530 -0.009543198468485899 0.009194738162092713 0.002932821352048649 -141 0.007530076713547185 -0.010772382425474793 -0.007049312864075332 -531 0.01346275911311354 -0.015519264000711233 -0.013983233267324877 -399 -0.015794023221716955 0.013361754155793227 0.023184548477482157 -380 -0.00016532393637421034 0.005396941650961916 0.003706037154930361 -464 -0.009720016666000888 0.005508521851143906 -0.0010447395388278984 -428 -0.0032295145570997628 0.0073242509948272215 -0.008762443779130127 -397 -0.0019383749400236328 -0.004608215655716036 -0.0033540348251192864 -319 -0.0009038475895158715 0.0004032373568885917 -0.0008893950154038688 -398 0.0008784454978576588 -0.019930509233584276 -0.0023402740275860765 -528 -0.017149344935718215 0.0053125553694975455 -0.0062739095024969055 -321 0.011291342491685402 0.011778478494356572 0.02157510722031055 -490 0.003460299667122343 0.0005008872223548776 -0.003928509480568708 -491 -0.02042787598151604 0.009606293972625789 -0.014609420256501925 -492 -0.01179479155292874 -0.013123603914816054 0.006317741927870814 -659 -0.0069325446438758135 0.001872758468936734 -0.001820683375806924 -249 -0.003689403614427041 -0.009541231217973603 0.0028290387567211457 -164 -0.006400690048675919 -0.013877760093602321 -0.002977622020994794 -162 -0.004855407125325768 -0.01879111496764322 0.020518095513515515 -371 0.0186329030963466 -0.0030361600806192253 0.01127947927515273 -370 -0.006645327540014044 0.0013620044066288777 0.0040028544483149825 -610 0.002198658185540671 -0.005517799631155318 -0.0021977580020232164 -154 -0.0040921640552195535 0.004469932541531453 -0.004074017062258021 -155 0.00946262378435491 0.008912303180476127 -0.007853976504644958 -156 -0.007160039514904957 -0.009309817752610663 -0.004347645837647768 -612 -0.01853211573078728 -0.01727473985951407 0.017215191641891617 -183 -0.004442865646352574 -0.003400423991540166 -0.0018621889463709465 -629 0.020458137445744262 -0.0005441012285127372 -0.016121405666884327 -182 0.010414879082570251 0.030332837986610725 0.005191185967407049 -181 -0.004080198053479511 -0.0019011724834973821 -0.001840667647736802 -611 0.012212859606390776 -0.0026124264131294 -0.005669832465189566 -628 0.0001792339331808534 -0.002433089326052819 -0.001805358970649801 -630 -0.015366679651799057 0.027336154517751083 0.0030786076245146897 -487 -0.006612908041425593 -0.010557716751849671 -0.0004398534728532736 -526 -0.0028150615039515803 0.004044411001066752 -0.0013644193865672359 -151 -0.008568566244765728 0.0059744557184639255 -0.000627104807162225 -160 -0.005288304762918362 -0.004980091259974818 -0.0052020664728392955 -351 -0.014050712299375443 -0.02358677864502768 0.022078468617912066 -372 -0.010000271327845013 -0.0017495788438303597 -0.015743229425643938 -473 -0.008545742194336561 0.03299533080814433 -0.006554398847784694 -669 0.009323919846092737 -0.005503137113750206 -0.01757154792744392 -220 -0.010802030745763268 -0.003946674830891448 0.003347466106919407 -221 0.0031078719584793097 -0.0026986854685907176 -0.005051678138139105 -349 -0.0028467913154277976 0.00619549728782877 0.004513308653347061 -176 0.014573690185444051 0.005701141194454324 0.02429670540436278 -472 0.0034704444931731564 -0.0004223936528461586 0.004682456493386929 -286 -0.0007227944529852624 0.0002044846821905628 0.0005275546923425382 -287 -0.013787536809725281 0.0027725652215363646 0.0028043383019355616 -288 0.013467067943699075 -0.013607004090118587 0.010562692707514431 -667 -0.0033231615840826375 -0.0026754997278682718 -0.0025810158998434453 -557 0.00480046414868641 0.0036381648364985485 0.011568695731040347 -668 -0.010354343669844574 0.01551276249617225 0.001263283616141959 -233 0.018175533457414624 0.0017013730890884599 -0.000542455897216258 -232 0.0005655337868856603 0.005109144050052834 -0.0075456339065252485 -556 -0.002652573873678528 0.0017686267932879897 0.007383198916898972 -613 -0.0015918424196763945 0.004086688266801507 -0.0008860298641209033 -615 -0.0020836681424838757 -0.0005735018872513953 -0.013310568326146311 -447 0.01139703322386246 0.014688114003843386 -0.0018920048987641955 -453 -0.004830305681658932 0.02052395365578583 -0.006460118140426627 -452 -0.006659826339694623 0.0003543348655607981 -0.022845001543426367 -451 -0.005502850804956584 0.00025572828917443384 -0.005940030711587164 -427 0.006878068518221622 -0.00885399992822085 -0.004941337405656671 -429 0.016310095429692206 -0.004246153250381018 -0.0063539068368046086 -14 0 0 2.5892839001447915e-05 -7 0 0 2.5892839001447905e-05 -6 0 0 2.5892839001447912e-05 -15 0 0 2.589283900144791e-05 -410 0.0036773579068940594 0.005088334412447784 -0.00010670193844646754 -411 -0.013294041272967414 0.0018927422415192015 0.004022854780372532 -23 0 0 2.5892839001447915e-05 -22 0 0 2.5892839001447922e-05 -31 0 0 2.589283900144792e-05 -30 0 0 2.5892839001447925e-05 -409 -0.0033332525225770564 -0.00245864319500691 0.003352617057588178 -674 -0.0020876963116493253 0.0012720696117521837 0.004777046069219144 -673 0.001440207298745793 0.0006711067607754656 0.005750751000129193 -616 0.0034399261571874833 -0.0006771518251561286 -0.0008689301882926043 -618 0.011960174137895753 0.02757908212908868 0.006623095130093759 -47 0 0 2.589283900144793e-05 -39 0 0 2.5892839001447925e-05 -46 0 0 2.5892839001447936e-05 -38 0 0 2.5892839001447932e-05 -529 0.005442778008874495 0.007503881077571631 -0.00033589800355411745 -379 -0.001314351775643973 0.002379695621041653 0.003275885323478339 -165 0.00884464006202344 0.015924976929959245 -0.005078073570798919 -660 0.011025274705486485 0.007784764248372991 -0.019723554911707096 -658 -0.0017037660488597379 -0.0011580239500757668 -0.005506394723447372 -560 0.005991317348670128 -0.0022661168537082676 0.009892255799050512 -381 0.012417376249213864 -0.004828502113807977 -0.0018726878888628074 -125 -0.013873333040961978 0.004406736093524685 -0.021053266887589718 -506 -0.026262892601657484 -0.0021543522170194944 0.00442906465538162 -8 0 0 2.589283900144791e-05 -16 0 0 2.5892839001447912e-05 -454 -0.00010663947966301035 -0.005040601246033902 -0.0006922370547977346 -455 0.02289550486644541 -0.006075060916417402 0.0014647034106781431 -456 -0.0058551014431358 -0.028688264965094145 0.009412476538204347 -24 0 0 2.589283900144792e-05 -32 0 0 2.5892839001447922e-05 -474 0.018709003929338164 0.009713859155058282 0.005249922845235266 -320 0.020360034496335867 0.014864835586975439 0.030731515192935176 -173 -0.00013434925230160102 -0.003339721540542993 0.004399850614784226 -175 0.00477366431159889 0.0011728150452943586 0.0044527343392776805 -152 0.0025786212815767234 0.029696509429575725 0.013830328539275497 -505 -0.0004092230325628855 0.007490307555796668 0.004255257179335567 -558 -0.008265759925745195 0.00204552967410164 0.004668247385046733 -510 -0.0053380401606728245 0.0015521061958218008 -0.0005550030486493117 -374 0.02765868826006261 0.0017903292061302555 0.0026621329108467906 -153 -0.001037157082329749 0.005658079883762745 -0.006765436155795196 -163 2.534136430269839e-06 0.0043915276877542625 0.003615456878949748 -507 0.011440010041486237 0.01571871212288878 -0.001231948945091482 -632 -0.009407051140085434 -0.003481475839385426 0.0075372754448969695 +458 -0.004453454965741803 0.01151693825664599 -0.010677660778466836 +683 0.002006864592312675 -0.001932521592507294 0.007967958666679225 +337 0.00532298379239138 -0.00034751751662949557 -0.004166857667771256 +338 0.0016603629103229818 -0.0017397865762328161 -0.00957999859365969 +682 0.0016698034672263812 0.0030447891443300653 0.00044039408065769313 +348 -0.00021294094328660476 0.004583093099033796 -0.01001005910658855 +457 -0.0008224593908121431 -0.003314830306122345 -0.008635784615367802 +459 -0.012681503296362846 0.017812642118668884 -0.016635395617074823 +561 0.0009899334077360467 0.0001731424251618538 -0.01709685733786313 +477 0.017890991540560605 0.023044744293627708 0.01727164269957498 +346 -0.0024113500657761194 -0.0008915681397560844 -0.002866933909544417 +347 -0.00030907946139983243 0.012783515883529635 -0.010760262556093735 +383 0.00026978824638441295 -0.019120299882000577 -0.0053299741104955965 +559 0.0033527725124898465 0.00020920032069335958 -0.001421057700036272 +475 -0.004256602913319302 -0.0003820330120655169 -0.0016705935643949825 +684 0.009507995365094076 0.0040975189770988945 0.030681047245827025 +384 -0.003905065619279562 -0.015693306964610326 -0.026976836972692333 +446 -0.01314179281467131 0.010457284942415785 0.010342490806609185 +445 0.007370602560563622 0.0014877549887467316 0.0016554736956000077 +133 -0.004815017443186935 0.004933367632827598 0.002315306354333984 +169 -0.0016675845196929258 0.0034982453839532803 5.010082749011566e-05 +382 -0.0042602430014256525 0.004979405394323485 0.004287321951494137 +171 0.017489355050716793 -0.0027203439883894246 0.009533976138272483 +187 -0.0067021967344908255 -0.005140391493350062 -0.006739825554255354 +497 -0.0031329388973170137 -0.006870381148723759 -0.009174379123775899 +657 0.009094953874608123 -0.003997316248161227 0.012273025417327945 +496 -0.004018506073186678 -6.0250991078757223e-05 0.0010066456796113128 +560 0.005447947528153172 4.133899569079479e-05 0.012554326660939728 +134 -0.010468953197208536 -0.00141301566854465 -0.0035247336294485466 +320 0.010939719894873903 -0.006111308158447991 0.005510705669252292 +100 -0.006439631792275104 -0.0032604637575588367 0.006157843710305989 +319 0.0004586613107352609 0.00017512609741341151 0.004817206529500011 +218 -0.005861590499754354 0.006035174198167904 -0.006565358518448605 +217 -0.00927802735438625 0.0021411613416093722 -0.00035979020888794 +498 -0.009486138130747779 -0.009962568406838904 -0.011530771353931733 +673 -0.0032156185044286568 -0.00679244674598604 3.673566499860575e-05 +675 -0.0018401625404214392 -0.009727201298305973 0.013087668250224976 +315 -0.009707301914168692 -0.01721237483266019 0.008190693397883272 +313 0.000660323108037615 -0.0008435203791766024 -0.001201442668921443 +656 0.006032271063424584 -0.0009272461863311166 -0.007071956888250187 +321 -0.00020763811907399712 -0.0028938601093705524 0.018645114744037974 +314 -0.008049405263549107 0.02687740660879731 0.026979163799824374 +101 -0.003674543768142281 0.0020827789890460052 0.002260400570604653 +428 0.01084666748215117 0.005054808316931713 -0.014902105812815402 +476 0.008690481584713904 -0.02556846300271008 0.026160686020666322 +423 0.013910777481462026 -0.009511411008047801 0.0028540211424456356 +421 0.011612188198561385 -0.0026694223132784126 0.0033818470417945386 +501 0.015468220636970655 0.010438080393780974 -0.004945516275020853 +312 -0.002462545536414188 0.005876126527338993 -0.018135227561746684 +591 -0.01743483911663255 0.021455065412819035 -0.002183686492698431 +310 -0.0053773678841329406 0.0008674927506035782 -0.0004528722070173591 +589 -0.0012386485417616904 -0.0017282138306678712 -0.0008107377930330979 +590 0.002544170501886611 -0.008266546200100906 -0.002022768967224619 +123 0.004406306552695398 -0.008628826739600838 0.036456556616297355 +462 -0.012625780944026596 0.0012049271716172516 -0.004740855094449574 +460 -0.004602918945460055 0.0033419215840180864 -0.0012471064742344696 +500 0.0005745946112979287 -0.010833932565970476 -0.017234060323223555 +499 0.0039492868236109735 -0.0015522341395646803 -0.000580538309911011 +461 0.009903067749885548 0.006977098057675356 0.0051409212872263665 +642 -0.000572996104770346 -0.0038045280007246215 0.014722330820255243 +188 -0.005224055855005964 -0.010894208422402782 -0.010279011090773036 +189 -0.004059987018326752 0.015241647611207772 -0.017542363604050676 +372 0.0076175418650568155 0.006690596012820997 0.005010167361633111 +277 -0.0021953241214581758 -0.0008056617482451926 0.001429030788825389 +370 2.5618989179768052e-05 -0.0010745088188778996 0.0005190260361002789 +156 0.015908363280927384 0.04400099608067517 0.006820875880862751 +155 -0.026263460243542095 -0.005175555697363144 0.005233067464083874 +154 -0.0010052716041452881 0.0039545195890971305 -0.0011563452326712777 +344 0.011569513758106227 0.006595839522526619 0.010675357213637276 +276 0.0008902438004065535 0.006052118815589002 -0.016549391586186648 +278 0.001391648560168012 0.002754545283931772 0.01420704331285283 +316 0.0026386735229622766 -0.007259833641903415 -0.006735865315450437 +317 0.0008181583165255741 -0.0035049423729615597 0.003854089866584615 +274 0.003053657617358038 0.0018903039329490662 0.006074212569318248 +254 -0.00788095253568809 -0.003433836193123793 0.0030623796223154215 +404 -0.0049975851272486506 0.003207863270533685 -0.0046150272104852445 +253 0.002951741049391973 -0.004649439530868783 0.005054002099742331 +296 -0.037484521576817614 -0.011169130251698519 0.0027717903835696766 +407 0.0034135986321024835 0.004117840206286595 0.028522435572281245 +406 0.0015928936353108761 0.0077451384525304675 0.004491851058267775 +695 0.0026309354834312573 -0.012541984824922494 0.0027759746470715197 +295 -0.006166708890638161 0.0003866585495679127 -0.0024300733345666067 +153 0.019839326987494552 -0.006772161305622675 -0.0038316797962868326 +151 0.007378532055436394 0.0030180910772137507 -0.003228365014435173 +102 -0.0016579727186046321 -0.012121334087903685 -0.014096550825863318 +343 0.0006668380663333271 -0.0017942453065758163 -0.004385951649646588 +345 0.01164883135257315 -0.010951061738589838 -0.01685804900204048 +297 -0.007046341786616999 0.001097330555490314 -0.0024506035298995973 +696 0.017941635117438074 0.008063335474430777 -0.005018028281043851 +266 0.0026926906391473993 0.021374028107235286 0.0274284090331457 +694 0.0028450053423469132 0.0021229606019702507 -0.0022650737882021037 +152 -0.0027320320443689782 0.009085599329626944 0.002194910540824997 +486 0.008361849340413518 -0.013932226428787811 -0.004239444092447094 +479 -0.0004568924463957023 0.007861851582971901 -0.010254773571358275 +108 -0.010757495257343624 0.0027634611708688334 -0.002328970505069851 +318 0.006683022671607315 -0.009871222554567079 -0.01853285509406727 +429 0.0016997829431884698 0.002221213284056755 -0.014320857994167128 +265 0.002858674657937485 -0.000675627050954645 -0.0039084822530039065 +267 0.0025685568390093477 0.007664586210567926 0.010495462494921063 +104 -0.0032248795502721295 0.00477597402308894 0.016728337391690745 +106 0.008955114296811506 -0.0037801259301121735 0.004615860144598737 +107 0.009937444375192441 -0.036561615670364096 -0.03896712350154343 +427 0.002325966105687794 2.8396790669121446e-06 0.00262928512425263 +563 0.008960191925149656 0.0085972921677278 -0.0025751151558926245 +562 0.0027708995692783942 0.007178457942004565 0.006198218244171755 +564 0.003945339492516061 0.005730333339729568 0.012214970111968404 +692 0.0063770981430429155 0.010478020852484268 0.004848510110302704 +105 -0.008798062238208587 -0.008800318212964366 0.00346429968419937 +103 -0.003658142329813034 -0.005784579997167098 -0.0014671438010710129 +233 0.009090526271257277 -0.0062184695742560706 -0.001382677008349951 +234 -0.004221311422288912 -0.0002634133978307307 0.01846918510869164 +232 -0.0019428684489130065 0.0035530807084943167 -0.0015601629497799723 +568 -0.007672837661046987 0.0034112379306174096 0.006511831807789499 +570 -0.02069843625309144 -0.0021434803047988087 -0.006436211340190207 +206 0.018091561297447486 -0.011360475249371652 0.010771343422362996 +569 0.01385510438247273 -0.02824461222278443 0.02000817191701117 +449 -0.0062640201398862306 -0.004083880093706949 0.028264673928104996 +535 0.0002865299360108159 -0.0007091050153554685 -0.003379389599651852 +111 0.0031161313297533564 0.008818355528919599 0.004266550516884637 +713 -0.01374487522776186 0.008049698122091492 -0.012640814194472251 +450 0.004558588424108884 -0.0030889721561236897 0.011149959134927282 +712 -0.0012927532655562502 -0.003088934282594988 -0.0060105712594504595 +405 0.007133977588298567 0.0001635829611879496 -0.0019377217333525977 +448 -0.005273244033613063 -0.0015875839538786653 0.00446427062590491 +403 0.0016510428734420783 0.0014578044868035023 -0.003176578744653797 +714 -0.0023927059963184966 0.008785831579292806 -0.003581739748272074 +650 -0.016777098219426117 -0.004871075620600777 -0.0033774440510938564 +651 0.008519959597897217 0.010919193116972568 0.004569724434992854 +175 -0.006507740244653674 0.0023759619886788144 -0.004086362207230259 +255 0.005154657337248301 -0.011397299623934072 0.007796115715503526 +669 -0.0016770330388842546 0.00354195871084712 -0.0035223516202826963 +176 0.007854497797246245 0.007717151853201273 -0.006910836940798514 +177 -0.011040243716354028 -0.0007863004086489343 0.0012708101697725337 +426 -0.0007247776228948145 -0.00431766218174726 -0.005379200384703384 +667 0.00012300592297947112 0.003225812199644846 -0.0072679512581600774 +668 0.002661739040800462 -0.012651691727378778 -0.009293723873900877 +484 -0.0014183622367791116 -0.000613263702517418 -0.004804169148019453 +515 -0.006283868398267181 0.000790335608025519 -0.019444851544692835 +514 -0.0065821918199453835 0.010120165636838653 -0.003279060305969966 +516 0.0051923068414418 -0.0031679326573676803 0.009334928167008058 +478 -0.0022404381369582516 -0.0025032027851029067 0.0026177665036015135 +480 -0.004378955980298465 -0.022360428255072194 0.02371841500684581 +375 0.05161582552322043 -0.004739446395703063 0.0007236992839865241 +373 -0.0016646762874427128 0.000671379520776821 0.0022426040754076567 +127 -0.0008587937359666531 -0.0050069752991833555 -0.0016805787753368408 +129 -0.0013378481324512878 -0.005437872981490404 -0.003505537216444466 +128 -0.013827482145947348 0.0019439077936375575 -0.0022691818031355523 +670 0.0014166114686243747 9.189141459454448e-05 0.002329817750207777 +716 -0.007201051591719847 -0.004137150401581088 0.008628289475298697 +715 -0.002752602147124547 -0.0014738963744180945 0.0012732303905940907 +717 -0.001623638165314303 -0.0005412460650906025 -0.0012523252731872275 +374 -0.010720609375437756 -0.006840066101110374 -0.003488977404359839 +690 0.011731759537966135 -0.011680413214369936 -0.0032902381686339176 +688 -0.0023432526695829512 -0.005024207900308995 -0.0017992360394882845 +110 -0.027269877807471907 -0.0071249087135035645 -0.02271578221783141 +530 -0.0014545894711619914 0.0008549404321642921 0.013454283055939566 +672 0.006126580559770528 -0.0008299295300290445 0.0009215722575751014 +606 -0.0217602946725711 0.006423491093320408 0.016502930502986252 +604 0.0009371064061770097 -0.0021618327483940887 0.0015352022686043073 +689 0.0016500371723412138 0.004827672044018651 0.0096581934244938 +109 -0.0018356030600717753 0.0030878192102232406 0.0017357958143820603 +205 0.0004901963103920081 -0.004632374784987575 0.0036249981754071722 +207 0.00249538864182957 -0.002789578550669558 0.0036278161641520794 +605 -0.0037278101005000794 -0.0037391736920209554 -0.017195798709130735 +113 0.004202100839877966 0.00869037985549106 0.005737861091520882 +503 -0.005306460311046992 0.010832666840458556 0.016195438221236737 +112 0.005303589864178431 0.002587055451150015 -0.002103199293261842 +719 -0.021705208241774108 0.01797380776302394 -0.011478720275444904 +114 0.01389067167986877 -0.0009017440405471921 -0.0022864095930127176 +618 -0.0049266883701859585 -0.005969697820787827 -0.01308764555877832 +548 0.008219237188495402 -0.0008468110823799887 0.008894882644208648 +711 -0.0031295266853400864 0.02670222993771611 0.022060368649107705 +125 0.01083027713442555 -0.007043193303965716 0.0025025300050564385 +124 0.003263969048198798 -0.0019027285335452002 -0.0027054069888999693 +126 0.017099162347119654 0.003254011304238645 0.002127223362941016 +617 0.018680001577968623 0.009699939146537261 -0.00941566458839324 +534 0.034649079552431204 0.013330207039807017 0.010201392642925146 +467 -0.013892363759942683 -0.007351378919065869 0.00335784613947279 +616 0.00483428547003395 0.006774576548038284 0.0062860892069377125 +575 0.00027383445008849976 0.004016583094381818 -0.00829709451939129 +576 -0.008783216142550267 0.0040588636044731315 -0.010128419370098281 +574 -0.0016775969865822865 -0.0005968248788895583 -0.0026578911497726816 +424 -0.0002301922741549244 -0.0032175881637252803 0.004287613469297561 +578 0.009352734961645504 0.013672106889858487 -0.0009227929306399907 +709 -0.00496763073201381 0.0025027611182727853 0.00510235429818515 +242 -0.003418377167466765 0.016349818602040267 -0.0059902113564397974 +513 0.00397390267204268 0.00039374600345536836 -0.007973982771314087 +468 -0.012814486435939909 0.0040755521071130126 -0.026192943103455563 +466 -0.005299429397025371 0.0007501109317838154 -0.0035689246352978497 +381 -0.019629981695059813 -0.011756570952302245 0.01548910289706504 +532 0.0050526709923365025 -0.003421079885955213 -0.0015514226285473455 +511 0.0003307789612163611 0.003889085381026343 0.002881587074617484 +196 -0.00298297869248531 0.001388768050577565 -0.0005186534865380335 +623 -0.004957425002636128 0.009238105774759022 0.006918342220338828 +198 0.005242159970877225 -0.015318837226863235 -0.012999411375481502 +533 -0.01662847865550599 -0.03144497177091214 -0.009732768777825314 +349 0.0024981024230554434 0.003098959014501823 -0.0028727407879502484 +622 0.001862241541174783 -0.002773140520188012 0.00247465509654927 +643 0.0026910555372190556 0.002841809902343435 0.0005036863975762087 +645 -0.0005984784025519541 0.0031729186888958664 -0.00297806404901472 +644 0.008094203532835017 0.0047546653425713705 0.006562927282045607 +624 0.013044992727950242 0.001253085542446464 -0.003175579191024189 +583 -0.0007762128232164069 -0.006071863656441967 0.003123488997495697 +174 0.018305101923410987 -0.002331359500814445 -0.011556053327268835 +504 -0.014352028342715453 -0.017586422090584135 0.005017015913177833 +172 0.004116241446700985 -0.002838933839490376 0.003931819220934917 +502 -0.00036524779416289514 -0.005919776268394231 0.0025192173783630564 +585 0.000915259730989566 0.015459601003072553 0.012918672662256776 +387 0.008322512910613152 0.004268254367316691 -0.01708955772213072 +369 -0.008255395239693646 -0.005479645633396753 -0.00043990456955236303 +611 0.005548994298900594 -0.012546487352569155 0.005149258644725324 +612 0.01159428062300361 0.007640328803396829 -0.0008741638987789488 +579 0.004041723720307483 -0.01111279086628263 0.0072616837143763165 +385 -0.0009939381015497582 0.0030571781780153605 -0.004456790743997918 +386 -0.008946661149132614 -0.0007819151339354976 0.0033544619495802807 +710 0.0033147082010021225 0.005770806573503135 0.011238620384591214 +368 0.012173584067324118 0.010910852525158018 -0.00266879178359736 +259 0.0023368952297790147 -0.00449400172894597 0.0029559257987906836 +610 0.0014078658509803987 0.0002880667624082518 0.003387331565643165 +367 -0.0005480390088553384 -0.0005002212199953024 -0.00024733010086139143 +577 0.0008060129854294495 0.00017166457742740494 -0.0008561048368534674 +447 0.003110957816921685 0.0015870878646037617 0.003386466414046228 +357 -0.0013244089599512006 0.005682671719952686 -0.004077476907937305 +97 -0.005026548186247709 -0.0006228876009151483 0.0004994507575806001 +99 0.005542039722938562 0.008122195408200614 0.0010263987452825713 +168 -0.006406524125311867 -0.0009283795569643392 -0.010643871191766763 +435 0.002889094957647671 0.0032927184201963135 0.001985253422501464 +558 0.0020818684609235747 0.0013315752509750725 0.006682483396265906 +166 -0.002065917856391013 -1.8249357674565548e-05 -0.009004884427339106 +394 -0.006360340809251226 -0.004631764271186644 -0.0019896860235148264 +433 9.970226124664633e-06 -0.002264497137209541 0.0008963874951089408 +434 0.006722578729253475 0.022022987226261097 -0.014639523717312426 +167 0.012515868958607925 -0.007511932947545252 0.004407940287593755 +396 0.009639020471542682 0.015868844961723555 0.013645724634258357 +355 -0.0038423729832386556 -0.0020561485875147108 -0.0016482325146477514 +647 0.004515614005214671 0.0017631585437073692 0.009255840750581872 +654 -0.01803488108298581 -0.007334531874327409 0.00459546203605296 +652 0.006030985366321212 0.0007332802633593123 0.007333157742779 +653 -0.0032441734777585614 0.00942657943550517 0.00584145591984073 +674 -0.003063583537461951 -0.01179763732350847 0.005449621699469662 +246 -0.0039032258650524136 0.00916267461274836 0.0018688989063795432 +245 -0.006070147810085611 -0.019008826019418862 0.0024655493377629028 +244 0.004443349950521421 -0.001779929667884385 -4.905759538203217e-05 +697 -0.0025146598747406235 0.0014003494787741707 -0.004127061259552191 +698 -0.025149580283357193 0.016768457434997528 -0.0144874983514177 +629 0.002917587732020283 -0.00302708571348339 -0.015068833185973202 +593 0.016860656902253475 0.0041945813998550295 -0.01617254723971546 +592 -0.001640088107429323 0.00034608752630003016 0.00011980474314306386 +210 0.0030620525927574876 0.0020231482000474155 -0.0014920669498859548 +209 0.008438167474285975 0.004612415869938766 -0.006076132368139379 +594 0.0017124075137155519 -0.02127883088608897 0.005679571176231625 +663 -0.0071037256920369884 -0.010590622746788847 -0.0028775474570157606 +208 -0.0016181190895891118 0.005810040655836568 -0.003826524601371058 +419 0.011294433056168247 -0.017192082764488414 -0.0025606502852209465 +641 -0.004309159782487541 -0.01134836619343387 0.0022868440923617607 +640 0.002131003674685546 -0.0035958906763722434 0.0021177994536453588 +137 0.020658105646024473 0.012654733274768187 -0.00524475187829765 +699 -0.002477011112569179 -0.006702064320336806 -0.0008102910909585382 +136 0.001655832574839628 -0.002984834230620339 -0.001550205551684509 +140 -0.002367894732144384 -0.013808356771113755 0.017259877217538223 +139 0.00016545955503963347 0.0028593878711222643 -0.00478898861830347 +138 -0.0007610917048126984 -0.024371966075808788 0.018889687917347905 +286 0.003806028815510772 0.006261665048891517 0.0015881399248088724 +141 -0.0003801668371515948 -0.005163807555196016 -0.022783710942608122 +356 -0.005238652081677789 -0.004610568940166292 -0.0015244708376905992 +395 -0.02253772726868896 -0.0066753490126988365 -0.01245377865903734 +224 -0.004896812910925297 0.01440078235599339 -0.0006724244527572224 +275 -0.010232624432234884 -0.007454174697705406 0.00623684314856214 +223 0.0017215886489852711 0.007433190657071842 -0.004983932946528752 +389 0.0027526981973249394 -0.001328853955471207 0.0045250522716830935 +216 0.001787315873539206 -0.00045360496846752864 0.0009049669331300801 +257 0.004261296558828503 -0.004570633213125906 0.003979725407423219 +225 0.008965912786139717 0.004349498544950998 -0.003737598024944121 +258 -0.004362134593197381 -0.0003247086962529744 0.00034366732486023645 +256 -0.00015823427705910544 -0.0021266545747713815 -0.0011024089803532344 +269 -0.008319123826978143 0.01404268958108163 -0.004439694163606073 +284 0.012850295238607095 0.022727051758484697 0.005093359609976458 +388 -0.003985316056547339 -0.003730455938671166 -1.4913129519033464e-05 +390 -0.006437774483409439 -0.006993671208969723 -0.009592841732820665 +686 0.0027469127614133133 -0.015502593601850094 0.001259923639666192 +630 -0.021173457216339363 -0.0011091433180805937 -0.016290614505972585 +628 -0.004175936326702936 0.0007462313786508353 -0.004601394892569226 +662 0.005642944025171392 -0.0010430524868843781 0.0055280836934935235 +661 -0.0023700931074827777 0.003907110120279919 0.0005913461637964844 +158 0.0007308264358153039 0.010201557032771416 -0.03163567305652864 +157 0.006691459995734248 0.0012902862126745063 -0.007480597572720153 +331 -0.0008817642329219822 0.0021584436857335553 -0.0046638279071666506 +333 -0.004696558133178527 0.0031739435533363293 0.015407996341362732 +332 -0.0034562633997387384 0.0032977621258542494 0.005072135984805667 +159 0.011866957645876842 -0.0033390008407883547 -0.0033111627735487627 +443 -0.0037867595690661946 -0.00871115359911764 -0.006211571371266589 +702 0.0005157925210920148 -0.01862237120048761 -0.02126567931023984 +418 0.009026113380609373 -0.001456993412540531 2.531740961391944e-05 +420 -0.003075346520981788 0.010824922293772271 -0.012527321684136915 +306 0.004513714971309221 0.011303997850601849 0.003190686418946394 +725 0.007345564115088602 -0.007636316783418212 0.01995868814081767 +285 -0.005609283443382429 0.004834271673657035 -0.001514895510926504 +305 -0.002263828369054366 -0.0002202671962814671 -0.0013693734272154441 +304 0.0023625778647756784 0.0007478600013689276 -1.5320980596256273e-05 +726 -0.008627073993775911 -0.003007502632529877 -0.008473947349688779 +724 0.004696955107297542 0.003126541722569592 0.0022891407019057916 +638 -0.0002886107944268399 -0.002939033404521495 0.001082909508838736 +399 0.0015588620175107902 0.008426107228068429 0.013311928846194672 +397 0.000720917424337885 -0.001220682695428885 -0.002757667354356934 +283 -0.0015852605159438105 -0.0029492054997196024 0.007467971709415989 +163 0.0034197098660175623 -0.008623759234314979 0.0033894754736908893 +164 -0.0036430886268036746 -0.009889353036581797 -0.016905603994354437 +685 -0.0004072452236383633 7.326234779933795e-05 0.0014849854340800745 +687 -0.002739165377375687 0.012852384595407756 0.001475285594107675 +649 0.0014134044984482012 0.005542430982887621 0.001928425623653205 +215 0.0008248133702686463 -0.000711839082931538 0.0022444015571633498 +587 -0.00090343187438489 0.0057465020808828635 -0.003124562227116467 +586 -0.0013758332769409187 0.0066525027443663665 -0.00011532120794506751 +588 0.0017245969503470826 -0.0008104661763823836 -0.019712623118666575 +539 0.01065062249850665 0.007827874290134467 0.008909353411428827 +214 1.1165073159270163e-05 -0.0004998991917670403 0.0016292722157333316 +380 0.005271609947690949 0.008510623968010896 0.03016417682914827 +191 -0.010024017672764255 0.008435955357775526 0.0014203923305754962 +192 -0.0005634006302245232 0.002844594940623796 -0.008061642993686067 +190 -0.0113311474598216 0.002504068480918772 -0.0071637988085077545 +538 -0.003914815120454294 -0.0010599684145957344 -0.0019251398636633387 +671 -0.008604964853957753 0.0022601681803426296 -0.002917330408581408 +262 0.005651090143362061 -0.00512272946210163 -0.003691328865025109 +263 0.007201535443275555 0.00399129299903444 0.0021333236289320097 +264 0.013427149538806868 -0.01601168652829063 -0.004041915850761532 +614 0.0002707557590391042 0.0026091616822172554 0.010802883842087075 +442 0.005226368024101791 -0.0005695316462469665 -0.0016155579148242594 +613 0.0026048179177820814 0.000989099002428112 0.00015975554562322683 +615 0.013192848347887254 0.0033089182068860644 0.003037575696524861 +238 -0.0005870292048445432 0.0006514557861283215 -0.0019838483618029763 +240 -0.002724161266270134 -0.008890016938576486 -0.014122848675880794 +444 0.003184028086041916 -0.00969592308061097 0.006605107677339591 +398 -0.012700825129448581 -0.027199099438541145 -0.00517811816842186 +438 0.012850198883246046 0.01254350896533728 0.0008985858090579044 +436 -0.0031691400803140935 -0.0006296353491016456 -0.002516909475513795 +437 0.016350370845538566 -0.005888923943516664 0.007322595965500486 +718 -0.008202093937232093 0.0006798356147457872 0.006084460335497779 +720 -0.017383939897128695 0.001547555597627774 0.02813026643925475 +119 0.012904495443845528 -0.005803951008063301 0.0057169642915285415 +118 -8.916791816294511e-05 0.002839921457979148 -0.004429120787058283 +120 0.0024458285457822767 0.0008570225072119515 -0.00797171583646973 +301 0.004488477270898401 -0.002382353791932725 -0.00503113533793492 +302 -0.014531938953658154 0.006169284631177108 0.03198258656151703 +303 0.011269697663660844 0.0016258321215055099 -0.00033779321643985125 +165 0.010544246432356527 0.0041906490881375436 0.012092698752189768 +379 -0.002237444080661589 0.0021776798197609536 -0.0032771686001432693 +98 -0.001797292289119333 0.005336617607509462 -0.005171911836470949 +135 -0.013489435087016732 0.005274005479841612 0.0005834971857759355 +441 -0.003619860188541455 -0.009877099432817072 -0.016734607567403022 +439 0.0032162625844592064 0.006131533085952244 0.0007794677889147138 +440 -0.0015247454955621903 -0.00847194524210127 -0.0155283189330647 +241 0.0002945523997109585 0.00392985227554616 0.0011371210593021828 +142 -0.004091375383694248 -0.0016351522843879743 0.005389850700728547 +144 -0.00519971551432377 0.001514283314589748 0.02239720321565925 +143 -0.00024269769818795135 0.006517652063452855 0.02991554524096922 +180 -0.00260043894652495 0.005661456277089602 0.004899405120415125 +472 -0.010385072091518802 0.000793619552976975 -0.0025644198832336447 +473 0.0038612261633057367 0.006776939875983214 -0.0065105414163708734 +506 0.002563136031921645 -0.018826103005989525 0.012821459377573856 +505 0.0048905756144497275 0.0031674562591624744 -0.002943038158444379 +507 0.0020402703806653324 -0.010304947986340164 0.003356477351540788 +365 0.009162151172310935 -0.018017936907596357 -0.014922459670158063 +366 0.004788991496382441 0.011526484663629892 -0.0019277315697965043 +364 0.005274226393635851 0.008738558274226052 -0.0018124040481897084 +660 0.011256763151592844 -0.013937460154994532 0.00047620736388687113 +658 -0.002060812958994976 -0.002967001511991565 0.0004188223197400222 +659 -0.0003146377724438938 -0.00197449430694 0.0021276918212970054 +704 0.026040983883360194 0.00900571078277188 -0.018728389329774334 +703 -0.00018274917247401183 -0.004489677456144546 -0.0032681822747904704 +359 -0.019216573251564978 0.004020034964137674 -0.0001220713197680691 +470 0.002151458971045023 -0.01691547094683232 -0.010096527585238893 +239 -0.00955336944238779 -0.010459588551473485 0.0150838573154403 +360 0.0009520175378620087 -0.007749755357701786 6.621489298128217e-05 +358 -0.0005688410126172113 -0.0005560941009629876 -0.0006166527963073808 +261 0.007769959654076087 0.0030896685845212177 -0.015356352591330839 +260 0.03415303140098265 0.0029601298994195455 -0.01936888681418142 +556 -0.00430632092548708 -0.0008430104911118851 0.004546252381393538 +557 0.0024234183721920884 -0.0033865183224814676 0.003988433760516458 +243 -0.013129238813343694 0.001636317301929463 0.009990259161298299 +452 -0.0048729457305857135 0.0020911007888309986 0.00579974498517894 +453 0.003281786789083938 -0.00391762740915676 -0.0010299028840426564 +451 0.001696422880212693 -0.004207545061251571 0.0013962319224258603 +249 -0.012591732409175688 0.007546760090260216 0.0137881393833657 +378 0.002331585205254201 0.0006976292805448998 0.004955162912278944 +469 -0.0026805771897719993 -0.0004716405230935708 -0.008019044858007272 +471 -0.008460133069352805 -0.0015272472151962614 -0.021744863895656705 +247 0.0013791656440794587 -0.0011986359225498989 0.004267660592504868 +248 -0.005492572492239919 0.002279136422665246 -0.02080148750991538 +361 -0.0018411763976671437 -0.0005942530984883047 -0.0013685452755333152 +362 -0.014903366862021108 0.015416563800979116 0.0011815377189573692 +363 -0.006263153757945177 -0.001634641152650846 -0.008304299117032699 +492 -0.009898853143303972 0.0009278981396767927 -0.014424409776254043 +490 0.0030354599548929177 -0.0008554763542258207 -0.0011355049674150834 +292 0.0031516174366246715 -0.0034225721474031405 -0.005529159904321513 +293 0.002956735836415312 -0.011094674280821152 0.006854195142517166 +543 -0.005179278891860961 0.0026890023203280946 0.0041019845447431095 +294 -0.002312663234381566 -0.011632491191280908 -0.0009731604446443048 +648 -0.018524887249069276 0.006747341097991656 0.00043721584014796364 +646 -0.002780716802849935 0.00974551105182296 -0.0023362746862546223 +289 0.0036761718858090257 -0.0059189286326507325 -0.004563750705311 +290 0.01353516337391623 0.002362528393466273 0.030156212537971756 +634 -0.0017400413269816654 0.002599808052717143 -0.006852060617433577 +635 -0.005260474970488028 0.011607443674202134 0.0046228516301874125 +299 0.013814353869601373 -0.035337010958565944 -0.007626054539468647 +291 -0.00040482137834702974 0.020661299343451334 -0.005508713299764413 +393 0.0020839193661128506 -0.008987122251911292 0.010285149255378918 +636 -0.00542331246063746 0.002573690502472132 -0.00035983248231242967 +149 -7.151452506110975e-05 0.0014155855562804176 0.003799179036068636 +325 -0.0031994445410817333 0.0016898813402218538 5.610008907901808e-05 +326 -0.005879386883584325 0.00043078787020088007 -0.0029994617796312204 +327 0.0012732578320217578 0.00011695372302210944 0.006412070349906606 +488 -0.013340276229246531 0.0026358421255856974 -0.002233047173904977 +148 -0.004283396524559887 0.002188703362873204 0.0011359262815233196 +150 -0.0025488005052485218 0.017339969676634374 0.0074911477667229855 +707 0.01170571152298231 -0.02001987373660686 -0.00649732243702941 +706 -0.006734793193523193 -0.009471687918984308 0.0018134332088678151 +708 0.01043771884133765 -0.0004986882167179219 0.007123800182616495 +481 -0.0012496095279962473 -0.0050170088381964045 0.007176809560570978 +483 0.021757811291607868 0.0013571015551912197 -0.002778434524506408 +482 -0.002579975740967915 -0.008193215752828985 -0.002787668411750772 +288 -0.015499272855390864 0.02647484837809114 0.008661371031580349 +287 0.022614602307564537 0.001992062236812065 -0.018683135121062983 +491 0.011544297921842946 -0.016137896705660435 -0.0007621990951202092 +309 -0.005697804934448254 0.013257801661920787 -0.010593091026444944 +307 -0.007946332515966098 0.0011127287367364927 -0.0003225430486488365 +495 0.009728921694623846 0.007093458815640433 0.01411663616256105 +308 -0.006426796104180803 0.005473885485853239 -0.00019725665823820638 +229 -0.007248324751437849 -0.0010717876561419583 0.004254945302504692 +465 9.648842741707659e-05 0.0021202771007501993 0.004485009307726672 +494 -0.0102115961744896 0.002913741214401282 -0.011844630854205436 +493 -0.0029408278389643668 0.0040799464304130464 -0.004200241440017398 +185 -0.0162521258515417 -0.003685671464587334 0.004252604004205645 +463 -0.0006999574156701651 -9.169572366832186e-05 0.006389211866440561 +270 0.002706342445250265 -0.000854151667256604 0.0017919561417045185 +268 -0.006092356100129407 0.005763642048150651 0.005898323411350319 +298 0.011090916008125465 -0.0003158165688766036 0.005085093481222366 +680 -0.003710788712911898 -0.0028345736383161707 -0.0016624377420180994 +334 -0.001646965710106046 0.0022952123315555578 -0.005169634426126912 +335 -0.015980387033825646 8.854938274220335e-05 -0.01816618074336612 +679 0.0037391767248099186 -0.003515059947549784 0.002341736983001597 +456 -0.01622360318359218 -0.009805071213118452 -0.005972719999234521 +681 0.0033464206369857178 0.0018593520182910504 0.0022724593212495423 +573 0.035914631236689136 -0.0119450800550804 -0.0005747405297846915 +336 -0.007825800627969271 0.00768337399894178 0.024983641796735002 +454 -0.003382449833344251 -0.002794494300327384 0.0038418937537501117 +271 0.002357274245352879 -0.0018963943881007829 0.000991809005344159 +300 -0.0052930292674167306 0.006440731283902526 0.024507768165554684 +280 0.0013933865484831655 -0.0056835891176652 -0.0010178666073674726 +272 -0.009893878493973465 -0.008053032005096978 0.007321975230124151 +116 0.01777842565618712 -0.015798889517793326 0.010648066257965523 +581 0.006493419994287206 0.004175731808528304 -0.0038075898663124212 +700 -0.00012801211667683082 0.007213135818384868 -0.0037645643440806908 +701 -0.005371061254240965 0.003171280714125679 -0.011736177812528347 +580 0.0003965496667819459 0.008510042009669427 -0.0008206198182428773 +571 0.0030796331163622714 0.0010922813181917584 0.00524294147881322 +186 0.010106710411003167 0.0028669093917835296 -0.0030228885462384846 +184 0.000618234423049718 0.006116502214680637 -0.0037038602699089123 +723 -0.009190811612737318 -0.00301916681174666 0.003972501122494039 +721 0.002690608751407624 0.004111192795013688 -0.0012263556087446698 +609 -0.004723013294901941 -0.006444730696396147 -0.009982421727072349 +608 0.009553631086994486 0.011356526861422163 0.015033675506505733 +607 6.878304909532546e-05 -0.0013649477213774353 -0.004264282499395178 +572 -0.019023378141821975 -0.016470971915217122 -0.008966007164307524 +161 -0.01101279624639333 -0.0066850105706026805 0.004125450036755977 +582 -0.00895123408997298 0.01696868369163429 0.008724383650402278 +282 0.020129534503988602 0.015622889175302647 -0.015780339990325423 +639 0.00019098000205755987 0.009329257692273055 0.015462469035938337 +637 -0.010268419254502795 -0.0033204995293100513 0.004825941131879525 +722 -0.0040299164143823875 0.010756206409579352 -0.005712198723390781 +510 0.003123806615529003 -0.00420910976538542 0.026586924692775488 +222 0.033926342655610085 0.01796722743346109 0.013820988662122058 +220 0.00027715920489089225 0.0023419707048865914 0.0010301488406650949 +221 0.008938815675509696 -0.005656320360971094 -0.015802209820795506 +194 -0.004034010927275597 -0.015213890966131708 -0.005116856789652635 +195 -0.004214713771335041 -0.012168642805439635 -0.005121574934093348 +193 0.0017790822671230166 -0.001136511971243534 -0.004426554512205668 +432 0.0038236345714522707 -0.018543114978359542 -0.015677964046018428 +431 -0.001025663331694761 -0.005782973744011068 0.01596264261815661 +430 0.007571718701576313 -0.003970543920835715 0.004061428354918659 +544 0.006145853680925427 -0.003558625527309057 0.004712623206101515 +115 0.006044175448204818 -0.005276926085181493 -0.0075267052304545425 +117 0.00851173197882058 0.01829515292881661 -0.005325223451614053 +545 -0.008987292170970546 -0.011842376582473897 -0.02384083346814782 +182 0.010231945925816907 -0.015304728776994486 -0.0006673263213082153 +540 0.009830578561175666 -0.0063710477146009725 -0.0054897712631665485 +602 -0.010904597547356062 -0.01840056375777756 0.009633868126302703 +603 -0.006108645207167538 -0.003919618874412859 -0.002654737241541606 +455 -0.024093029885638655 -0.009662727140350397 -0.004505470448928953 +201 -0.01616960988967848 -0.0106889072942792 0.0072211424288129615 +199 -0.003106260580334742 0.006411349276864501 -0.004044187049429534 +200 -0.007268877343038796 0.026377331525558375 0.009973629248552236 +599 0.016596982966255714 -0.0009207102351199662 0.011239739375562326 +598 0.0029310155213707117 0.0017987730979994118 -0.004743561210319109 +600 0.002549722461997752 0.014429204695832242 -0.009458295897154157 +281 0.002347019290833369 0.010971558742722405 -0.00923509940399437 +324 -0.0037059211296033463 -0.004396986063014179 -0.0060247317044738605 +322 0.003356679576227343 -0.0007637645843901782 0.00431510981022623 +323 -0.0056516057252608 0.003828963776626326 0.017783104019150522 +520 -0.0004117712789830727 0.0020758360785791312 -0.0010373147373874843 +183 -0.003651025803848668 0.0032929972079473687 0.0030004101428539012 +181 -0.0019150084723164162 -0.0031908425462716336 0.002677742267628704 +528 0.009253953756286579 -0.022726699813356732 -0.008302610390435353 +527 -0.026051717388651065 0.0010053188608434838 -0.003041253415411715 +526 0.0049574251594706395 0.0021165055564693483 -0.0020102383692291764 +413 -0.004106465956088772 -0.016318859510594166 -0.002457950382972751 +551 0.005621772762354192 0.0007387800134147048 -0.015994151313742468 +352 0.0051614128129068215 0.004194102342547428 0.002561364532637018 +353 -0.009582724186439616 -0.008705468211864518 -0.02897310442665479 +227 -0.002425607567560221 -0.0010255491124715665 -0.011817554243112533 +228 0.01572585383089693 -0.010614358678638441 0.006968797918117437 +226 0.0020948934110851477 0.0010118620094589947 0.001820602983352382 +354 0.02003265634395509 0.0036127832130803165 0.027605578310224345 +550 -0.003036402506396888 0.004150436699143066 -0.0005610332460767217 +524 -0.008980992467545346 -0.0031730732527052575 -0.005568066520151137 +523 -0.00010365859952221227 0.006353406764959096 -0.009077836112708546 +525 -0.00561652956069597 -0.00016947777707923228 -0.001970220558665862 +519 -0.013125003087740398 -0.011469194804316914 0.013505541673611496 +517 -0.0021159457672736944 -0.004412964989577972 -0.0010413335515586267 +518 0.017717698088592727 0.00909383617404767 -0.028545170133511853 +508 -9.334096172175459e-05 -0.004984656557281299 -0.0017741402555035252 +509 -0.00807954896343497 0.005779725364890536 -0.024610848258642945 +625 0.00011123981380908182 -0.003090808816089336 0.0075573728171250245 +626 0.0026673769851397406 -0.005017498161826362 -0.002425342613874514 +132 0.0015243373893186207 -0.0027646883306819323 -0.003221623582970257 +252 -0.0013259149625935549 0.009976918967493387 -0.003732686159493943 +250 -0.005605206832166627 0.0005297374721552324 -0.006757497850740153 +521 0.00970751081752297 0.013610439017695028 0.0005680707944436813 +251 -0.006993440926208339 0.0010222689560330947 -0.0068145312109414045 +130 0.0026838499920701655 6.702371206137205e-05 -0.0038430739297824227 +131 0.006424327384534665 -0.0008290582942547853 -0.003633462837194579 +203 0.01976027158742386 -0.0030070040964846564 0.013531402987002398 +202 0.003722121963012622 0.00015221250364814748 -0.002188938222165091 +204 0.013775519865558814 0.008467491865954293 -0.02140990942257068 +627 -0.001241750835653223 -0.004773998318539809 -0.0016148153442508185 +542 0.0040385576615968605 -0.0236794923228312 0.00531029427452055 +541 -0.0044262706386558525 0.004325702009483897 0.002700620213851568 +391 -0.0036280169383852046 -0.0026385466357123663 -0.00035216914986367686 +392 0.03994550165719566 0.020318388875604797 -0.0007932428205112993 +601 -0.0030679532557834894 -0.0030977948768668414 -0.005257290455915788 +179 0.0009873232779685616 0.0150955222182782 -0.007871483113870962 +178 0.004964972319261251 -0.0015981668901900738 -0.0041670093710039924 +552 0.006485514253259603 0.008699222840167432 0.0037510563686783617 +235 0.00506871602421843 -0.004086331699518592 -0.008587091653006933 +236 -0.004525226123458464 -0.005764403803617883 -0.015631958239905368 +474 -0.004742466401950209 0.005419182312857254 -0.007895183087680703 +417 -0.003992217731448409 0.00471471491227651 0.005575507084397644 +664 -0.001470104926409589 -0.004799539523296164 -0.0018785513064097103 +665 0.014771918301999913 0.012233594121569095 -0.006419805396723815 +666 -0.016064115068593825 -0.006541236112892163 0.01467853889731523 +237 -0.010721208694025012 -0.008265464412263886 -0.021817776048870266 +415 0.0019835285499536274 -0.0006382734049118419 0.003555718302091666 +705 0.006748710932874935 -0.0024289881322456758 -0.008541878588213401 +566 0.0035570139632815174 -0.01594775034404742 0.033204469911536603 +565 0.006857925902164734 0.005002808848358231 -0.004513258813589546 +567 0.003181874699909625 -0.00924395086885147 0.008880406857908165 +411 0.0024046862441890133 -0.006714458691938653 0.0049164786877966184 +410 -0.0050363826944832555 0.0058218872665497185 0.0027513549821143995 +596 0.001901078088678023 0.00490390977209901 0.00038685323891390026 +621 0.001976086534825697 0.00705420867885171 0.004011231628401452 +597 0.003145095476668829 -0.008305202055624638 0.010789768782981374 +595 0.0014439023253207408 0.0029590199421347775 -0.0011479555839940955 +330 -0.000454105678768917 0.008216820015035884 0.011628436633000498 +328 0.0066591275275407966 0.008310975892370648 -0.0060667992873991265 +329 0.017017016154807146 0.008652068731291183 -0.014679876782369922 +620 0.005144158070704658 -0.013314861626627391 -0.0007373733114238566 +619 0.002431401800346778 -0.001562059500319066 -0.006362047382968646 +677 0.0016833693507279774 -0.002878844060484389 -0.026035855009943563 +376 0.0009064195179465892 -0.003689607748901142 0.00042659566418980867 +342 -0.008722516752092775 -0.01813523558140053 -0.006517638122909407 +340 -0.0025943587604086195 0.0003205205769993526 -0.0013478220706903822 +409 -0.0034768010049023718 0.0003696469494390196 0.0011794583078781075 +341 0.01173657937587064 -0.00415297106778066 -0.011425635722426684 +678 -0.0052315803501361965 -0.0067072042594158625 -0.010510577417418582 +676 0.0012606310408806672 -0.005003835259145005 -0.0006656129032826617 +377 0.009291690772008664 0.0029659788632332255 -0.011218601401370447 +633 0.016838292034210285 -0.002773894853685203 -0.011578170743232821 +631 -0.0004151454548796269 -0.00048078689460954413 -0.0032615663914959997 +632 -0.009643725697380543 0.011621211216499307 0.01722187923853953 +401 0.004081680411837688 0.012757999123689634 -0.003690938434444669 +400 0.0023240152313725193 0.00015111448571084632 0.005748278487826584 +402 -0.0033958888414351786 0.012895292958925782 0.00044643445949813453 +2 5.031892850696456e-35 -7.855971130891077e-35 5.904453902322438e-05 +1 4.912224382206865e-35 -7.879614271110834e-35 5.904453902322439e-05 +11 5.151555499231424e-35 -7.832332373097226e-35 5.9044539023224377e-05 +3 5.208745250310379e-35 -7.656334053677772e-35 5.904453902322437e-05 +10 4.9747030996175e-35 -8.031969450310532e-35 5.904453902322439e-05 +487 -0.001145132860847261 0.002632147874097856 -0.0036232402676173725 +489 -0.006832646046318302 -0.0016267479538157937 -0.007006356048374049 +19 5.094365748152468e-35 -8.008330692516679e-35 5.904453902322438e-05 +18 4.917513348538544e-35 -8.207967769729985e-35 5.9044539023224404e-05 +27 5.037175997073512e-35 -8.184329011936133e-35 5.90445390232244e-05 +26 4.860323597459588e-35 -8.383966089149439e-35 5.904453902322441e-05 +230 0.003849353330259815 0.0036684074545651124 0.0022775018198492644 +464 0.002790472591310625 0.011293591164403627 -0.0033838193904728326 +34 4.803133846380632e-35 -8.559964408568892e-35 5.904453902322442e-05 +35 4.979986245994556e-35 -8.360327331355587e-35 5.9044539023224404e-05 +41 4.626275626812085e-35 -8.759605868208104e-35 5.904453902322443e-05 +33 4.683465377891041e-35 -8.58360754878865e-35 5.9044539023224424e-05 +42 4.745944095301675e-35 -8.735962727988346e-35 5.9044539023224424e-05 +43 4.922796494915599e-35 -8.536325650775041e-35 5.904453902322441e-05 +273 2.6773924918426488e-05 0.009862360798364158 0.010528137597319824 +5 5.505266118413894e-35 -7.43305383624471e-35 5.904453902322435e-05 +13 5.448076367334938e-35 -7.609052155664162e-35 5.9044539023224356e-05 +12 5.271223967721014e-35 -7.808689232877467e-35 5.904453902322437e-05 +4 5.32841371879997e-35 -7.632690913458015e-35 5.904453902322436e-05 +162 0.002600825628699585 -0.026498774387345964 -0.008572244027850005 +160 -0.0019141019315674125 -0.0022742553608968326 0.00756817001187433 +20 5.214034216642059e-35 -7.984687552296922e-35 5.9044539023224377e-05 +21 5.390886616255982e-35 -7.785050475083616e-35 5.904453902322436e-05 +29 5.333696865177026e-35 -7.961048794503069e-35 5.9044539023224377e-05 +28 5.156844465563103e-35 -8.160685871716377e-35 5.904453902322439e-05 +546 0.0012914591513626381 0.0016435905724560078 0.011210878468393162 +44 5.04246496340519e-35 -8.512682510555283e-35 5.9044539023224404e-05 +45 5.219317363019115e-35 -8.313045433341979e-35 5.904453902322439e-05 +37 5.276507114098071e-35 -8.137047113922525e-35 5.904453902322438e-05 +36 5.099654714484147e-35 -8.336684191135829e-35 5.90445390232244e-05 +14 5.56774483582453e-35 -7.585409015444406e-35 5.904453902322435e-05 +7 5.801786986517408e-35 -7.209773618811645e-35 5.904453902322433e-05 +6 5.624934586903485e-35 -7.409410696024952e-35 5.904453902322434e-05 +15 5.744597235438452e-35 -7.3857719382311e-35 5.9044539023224336e-05 +414 -0.003708147781576237 0.0119246471818512 -0.0026955388878462396 +412 -0.002143339343591569 -0.00406550791610511 -0.010899053221742722 +23 5.687407484359497e-35 -7.561770257650554e-35 5.904453902322434e-05 +22 5.510555084745573e-35 -7.76140733486386e-35 5.9044539023224356e-05 +30 5.453365333666617e-35 -7.937405654283313e-35 5.904453902322437e-05 +31 5.630217733280541e-35 -7.737768577070007e-35 5.904453902322435e-05 +522 -0.004517142308117002 -0.0008358029532284763 -0.015871308751386683 +38 5.39617558258766e-35 -8.113403973702766e-35 5.9044539023224377e-05 +46 5.338985831508707e-35 -8.289402293122222e-35 5.904453902322438e-05 +47 5.515838231122628e-35 -8.089765215908915e-35 5.904453902322437e-05 +39 5.573027982201585e-35 -7.913766896489462e-35 5.904453902322436e-05 +553 -0.0040430614584178615 -0.0017027478479088745 0.0013631323055172994 +554 -0.0046472364280754465 -0.0016038689694341643 0.002641643372539294 +145 0.0005734290816721687 -0.003411175879249019 0.0011735571895808842 +147 0.007400185640321636 -0.0006254559473139159 -0.007341801259477273 +146 0.0038951241842126575 0.0020875887784956933 -0.006835347713886058 +9 4.855034631127909e-35 -8.055612590530289e-35 5.90445390232244e-05 +16 5.864265703928043e-35 -7.362128798011342e-35 5.904453902322433e-05 +8 5.921455455006999e-35 -7.186130478591888e-35 5.904453902322432e-05 +416 0.008458867444241406 0.0063709018588346145 0.003787591538194493 +555 -0.020250627732704033 -0.005798271708231511 0.008792666418850497 +17 4.7978448800489525e-35 -8.231610909949741e-35 5.904453902322441e-05 +25 4.7406551289699957e-35 -8.407609229369195e-35 5.904453902322442e-05 +24 5.807075952849089e-35 -7.538127117430798e-35 5.9044539023224336e-05 +32 5.749886201770132e-35 -7.71412543685025e-35 5.904453902322434e-05 +231 -0.001540153496547131 -0.0059338989830543054 0.0024465947155016443 +48 5.63550669961222e-35 -8.066122075689159e-35 5.904453902322436e-05 +40 5.692696450691175e-35 -7.890123756269704e-35 5.9044539023224356e-05 Bonds -1 1 676 677 -2 1 676 678 -3 1 709 710 -4 1 709 711 -5 1 193 194 -6 1 193 195 -7 1 103 104 -8 1 103 105 -9 1 712 713 -10 1 712 714 -11 1 604 605 -12 1 604 606 -13 1 388 389 -14 1 388 390 -15 1 586 587 -16 1 586 588 -17 1 601 602 -18 1 601 603 -19 1 316 317 -20 1 316 318 -21 1 421 422 -22 1 421 423 -23 1 643 644 -24 1 643 645 -25 1 691 692 -26 1 691 693 -27 1 367 368 -28 1 367 369 +1 1 655 656 +2 1 655 657 +3 1 121 122 +4 1 121 123 +5 1 691 692 +6 1 691 693 +7 1 211 212 +8 1 211 213 +9 1 529 530 +10 1 529 531 +11 1 547 548 +12 1 547 549 +13 1 337 338 +14 1 337 339 +15 1 682 683 +16 1 682 684 +17 1 457 458 +18 1 457 459 +19 1 346 347 +20 1 346 348 +21 1 559 560 +22 1 559 561 +23 1 475 476 +24 1 475 477 +25 1 445 446 +26 1 445 447 +27 1 133 134 +28 1 133 135 29 1 169 170 30 1 169 171 -31 1 541 542 -32 1 541 543 -33 1 520 521 -34 1 520 522 -35 1 211 212 -36 1 211 213 -37 1 205 206 -38 1 205 207 -39 1 679 680 -40 1 679 681 -41 1 298 299 -42 1 298 300 -43 1 496 497 -44 1 496 498 -45 1 187 188 -46 1 187 189 -47 1 385 386 -48 1 385 387 -49 1 430 431 -50 1 430 432 -51 1 475 476 -52 1 475 477 -53 1 577 578 -54 1 577 579 -55 1 280 281 -56 1 280 282 -57 1 115 116 -58 1 115 117 -59 1 196 197 -60 1 196 198 -61 1 241 242 -62 1 241 243 -63 1 400 401 -64 1 400 402 -65 1 562 563 -66 1 562 564 -67 1 664 665 -68 1 664 666 -69 1 637 638 -70 1 637 639 -71 1 652 653 -72 1 652 654 -73 1 256 257 -74 1 256 258 -75 1 424 425 -76 1 424 426 -77 1 466 467 -78 1 466 468 -79 1 580 581 -80 1 580 582 -81 1 352 353 -82 1 352 354 -83 1 292 293 -84 1 292 294 -85 1 574 575 -86 1 574 576 -87 1 436 437 -88 1 436 438 -89 1 700 701 -90 1 700 702 -91 1 106 107 -92 1 106 108 -93 1 376 377 -94 1 376 378 -95 1 358 359 -96 1 358 360 -97 1 289 290 -98 1 289 291 -99 1 406 407 -100 1 406 408 -101 1 523 524 -102 1 523 525 -103 1 625 626 -104 1 625 627 -105 1 136 137 -106 1 136 138 -107 1 184 185 -108 1 184 186 -109 1 313 314 -110 1 313 315 -111 1 238 239 -112 1 238 240 -113 1 403 404 -114 1 403 405 -115 1 697 698 -116 1 697 699 -117 1 382 383 -118 1 382 384 -119 1 670 671 -120 1 670 672 -121 1 394 395 -122 1 394 396 -123 1 202 203 -124 1 202 204 -125 1 346 347 -126 1 346 348 -127 1 571 572 -128 1 571 573 -129 1 589 590 -130 1 589 591 -131 1 607 608 -132 1 607 609 -133 1 274 275 -134 1 274 276 -135 1 112 113 -136 1 112 114 -137 1 343 344 -138 1 343 345 -139 1 253 254 -140 1 253 255 -141 1 109 110 -142 1 109 111 -143 1 307 308 -144 1 307 309 -145 1 685 686 -146 1 685 687 -147 1 271 272 -148 1 271 273 -149 1 481 482 -150 1 481 483 -151 1 721 722 -152 1 721 723 -153 1 208 209 -154 1 208 210 -155 1 469 470 -156 1 469 471 -157 1 688 689 -158 1 688 690 -159 1 634 635 -160 1 634 636 -161 1 433 434 -162 1 433 435 -163 1 415 416 -164 1 415 417 -165 1 217 218 -166 1 217 219 -167 1 478 479 -168 1 478 480 -169 1 361 362 -170 1 361 363 -171 1 484 485 -172 1 484 486 -173 1 661 662 -174 1 661 663 -175 1 100 101 -176 1 100 102 -177 1 178 179 -178 1 178 180 -179 1 214 215 -180 1 214 216 -181 1 538 539 -182 1 538 540 -183 1 226 227 -184 1 226 228 -185 1 706 707 -186 1 706 708 -187 1 373 374 -188 1 373 375 -189 1 682 683 -190 1 682 684 -191 1 595 596 -192 1 595 597 -193 1 649 650 -194 1 649 651 -195 1 337 338 -196 1 337 339 -197 1 325 326 -198 1 325 327 -199 1 535 536 -200 1 535 537 -201 1 514 515 -202 1 514 516 -203 1 166 167 -204 1 166 168 -205 1 517 518 -206 1 517 519 -207 1 148 149 -208 1 148 150 -209 1 328 329 -210 1 328 330 -211 1 457 458 -212 1 457 459 -213 1 118 119 -214 1 118 120 -215 1 190 191 -216 1 190 192 -217 1 97 98 -218 1 97 99 -219 1 244 245 -220 1 244 246 -221 1 631 632 -222 1 631 633 -223 1 295 296 -224 1 295 297 -225 1 334 335 -226 1 334 336 -227 1 655 656 -228 1 655 657 -229 1 331 332 -230 1 331 333 -231 1 223 224 -232 1 223 225 -233 1 283 284 -234 1 283 285 -235 1 694 695 -236 1 694 696 -237 1 508 509 -238 1 508 510 -239 1 262 263 -240 1 262 264 -241 1 460 461 -242 1 460 462 -243 1 355 356 -244 1 355 357 -245 1 439 440 -246 1 439 441 -247 1 592 593 -248 1 592 594 -249 1 229 230 -250 1 229 231 -251 1 442 443 -252 1 442 444 -253 1 553 554 -254 1 553 555 -255 1 247 248 -256 1 247 249 -257 1 724 725 -258 1 724 726 -259 1 340 341 -260 1 340 342 -261 1 364 365 -262 1 364 366 -263 1 502 503 -264 1 502 504 -265 1 259 260 -266 1 259 261 -267 1 640 641 -268 1 640 642 -269 1 532 533 -270 1 532 534 -271 1 235 236 -272 1 235 237 -273 1 121 122 -274 1 121 123 -275 1 265 266 -276 1 265 267 -277 1 547 548 -278 1 547 549 -279 1 619 620 -280 1 619 621 -281 1 715 716 -282 1 715 717 -283 1 646 647 -284 1 646 648 -285 1 565 566 -286 1 565 567 -287 1 544 545 -288 1 544 546 -289 1 493 494 -290 1 493 495 -291 1 301 302 -292 1 301 303 -293 1 127 128 -294 1 127 129 -295 1 391 392 -296 1 391 393 -297 1 157 158 -298 1 157 159 -299 1 412 413 -300 1 412 414 -301 1 448 449 -302 1 448 450 -303 1 277 278 -304 1 277 279 -305 1 268 269 -306 1 268 270 -307 1 142 143 -308 1 142 144 -309 1 583 584 -310 1 583 585 -311 1 718 719 -312 1 718 720 -313 1 130 131 -314 1 130 132 -315 1 133 134 -316 1 133 135 -317 1 511 512 -318 1 511 513 -319 1 568 569 -320 1 568 570 -321 1 304 305 -322 1 304 306 -323 1 418 419 -324 1 418 420 -325 1 445 446 -326 1 445 447 -327 1 463 464 -328 1 463 465 -329 1 172 173 -330 1 172 174 -331 1 499 500 -332 1 499 501 -333 1 250 251 -334 1 250 252 -335 1 322 323 -336 1 322 324 -337 1 199 200 -338 1 199 201 -339 1 622 623 -340 1 622 624 -341 1 550 551 -342 1 550 552 -343 1 124 125 -344 1 124 126 -345 1 145 146 -346 1 145 147 -347 1 703 704 -348 1 703 705 -349 1 559 560 -350 1 559 561 -351 1 598 599 -352 1 598 600 -353 1 310 311 -354 1 310 312 -355 1 139 140 -356 1 139 141 -357 1 397 398 -358 1 397 399 -359 1 319 320 -360 1 319 321 -361 1 490 491 -362 1 490 492 -363 1 370 371 -364 1 370 372 -365 1 610 611 -366 1 610 612 -367 1 154 155 -368 1 154 156 -369 1 181 182 -370 1 181 183 -371 1 628 629 -372 1 628 630 -373 1 487 488 -374 1 487 489 -375 1 526 527 -376 1 526 528 -377 1 151 152 -378 1 151 153 -379 1 160 161 -380 1 160 162 -381 1 220 221 -382 1 220 222 -383 1 349 350 -384 1 349 351 -385 1 472 473 -386 1 472 474 -387 1 286 287 -388 1 286 288 -389 1 667 668 -390 1 667 669 -391 1 232 233 -392 1 232 234 -393 1 556 557 -394 1 556 558 -395 1 613 614 -396 1 613 615 -397 1 451 452 -398 1 451 453 -399 1 427 428 -400 1 427 429 -401 1 409 410 -402 1 409 411 -403 1 673 674 -404 1 673 675 -405 1 616 617 -406 1 616 618 -407 1 529 530 -408 1 529 531 -409 1 379 380 -410 1 379 381 -411 1 658 659 -412 1 658 660 -413 1 454 455 -414 1 454 456 -415 1 175 176 -416 1 175 177 -417 1 505 506 -418 1 505 507 -419 1 163 164 -420 1 163 165 +31 1 382 383 +32 1 382 384 +33 1 187 188 +34 1 187 189 +35 1 496 497 +36 1 496 498 +37 1 100 101 +38 1 100 102 +39 1 319 320 +40 1 319 321 +41 1 217 218 +42 1 217 219 +43 1 673 674 +44 1 673 675 +45 1 313 314 +46 1 313 315 +47 1 421 422 +48 1 421 423 +49 1 310 311 +50 1 310 312 +51 1 589 590 +52 1 589 591 +53 1 460 461 +54 1 460 462 +55 1 499 500 +56 1 499 501 +57 1 277 278 +58 1 277 279 +59 1 370 371 +60 1 370 372 +61 1 154 155 +62 1 154 156 +63 1 316 317 +64 1 316 318 +65 1 274 275 +66 1 274 276 +67 1 253 254 +68 1 253 255 +69 1 406 407 +70 1 406 408 +71 1 295 296 +72 1 295 297 +73 1 151 152 +74 1 151 153 +75 1 343 344 +76 1 343 345 +77 1 694 695 +78 1 694 696 +79 1 265 266 +80 1 265 267 +81 1 106 107 +82 1 106 108 +83 1 427 428 +84 1 427 429 +85 1 562 563 +86 1 562 564 +87 1 103 104 +88 1 103 105 +89 1 232 233 +90 1 232 234 +91 1 568 569 +92 1 568 570 +93 1 535 536 +94 1 535 537 +95 1 712 713 +96 1 712 714 +97 1 448 449 +98 1 448 450 +99 1 403 404 +100 1 403 405 +101 1 175 176 +102 1 175 177 +103 1 667 668 +104 1 667 669 +105 1 484 485 +106 1 484 486 +107 1 514 515 +108 1 514 516 +109 1 478 479 +110 1 478 480 +111 1 373 374 +112 1 373 375 +113 1 127 128 +114 1 127 129 +115 1 670 671 +116 1 670 672 +117 1 715 716 +118 1 715 717 +119 1 688 689 +120 1 688 690 +121 1 604 605 +122 1 604 606 +123 1 109 110 +124 1 109 111 +125 1 205 206 +126 1 205 207 +127 1 112 113 +128 1 112 114 +129 1 124 125 +130 1 124 126 +131 1 616 617 +132 1 616 618 +133 1 574 575 +134 1 574 576 +135 1 424 425 +136 1 424 426 +137 1 709 710 +138 1 709 711 +139 1 466 467 +140 1 466 468 +141 1 532 533 +142 1 532 534 +143 1 511 512 +144 1 511 513 +145 1 196 197 +146 1 196 198 +147 1 349 350 +148 1 349 351 +149 1 622 623 +150 1 622 624 +151 1 643 644 +152 1 643 645 +153 1 583 584 +154 1 583 585 +155 1 172 173 +156 1 172 174 +157 1 502 503 +158 1 502 504 +159 1 385 386 +160 1 385 387 +161 1 259 260 +162 1 259 261 +163 1 610 611 +164 1 610 612 +165 1 367 368 +166 1 367 369 +167 1 577 578 +168 1 577 579 +169 1 97 98 +170 1 97 99 +171 1 166 167 +172 1 166 168 +173 1 394 395 +174 1 394 396 +175 1 433 434 +176 1 433 435 +177 1 355 356 +178 1 355 357 +179 1 652 653 +180 1 652 654 +181 1 244 245 +182 1 244 246 +183 1 697 698 +184 1 697 699 +185 1 592 593 +186 1 592 594 +187 1 208 209 +188 1 208 210 +189 1 640 641 +190 1 640 642 +191 1 136 137 +192 1 136 138 +193 1 139 140 +194 1 139 141 +195 1 286 287 +196 1 286 288 +197 1 223 224 +198 1 223 225 +199 1 256 257 +200 1 256 258 +201 1 388 389 +202 1 388 390 +203 1 628 629 +204 1 628 630 +205 1 661 662 +206 1 661 663 +207 1 157 158 +208 1 157 159 +209 1 331 332 +210 1 331 333 +211 1 418 419 +212 1 418 420 +213 1 304 305 +214 1 304 306 +215 1 724 725 +216 1 724 726 +217 1 397 398 +218 1 397 399 +219 1 283 284 +220 1 283 285 +221 1 163 164 +222 1 163 165 +223 1 685 686 +224 1 685 687 +225 1 649 650 +226 1 649 651 +227 1 586 587 +228 1 586 588 +229 1 214 215 +230 1 214 216 +231 1 190 191 +232 1 190 192 +233 1 538 539 +234 1 538 540 +235 1 262 263 +236 1 262 264 +237 1 442 443 +238 1 442 444 +239 1 613 614 +240 1 613 615 +241 1 238 239 +242 1 238 240 +243 1 436 437 +244 1 436 438 +245 1 718 719 +246 1 718 720 +247 1 118 119 +248 1 118 120 +249 1 301 302 +250 1 301 303 +251 1 379 380 +252 1 379 381 +253 1 439 440 +254 1 439 441 +255 1 241 242 +256 1 241 243 +257 1 142 143 +258 1 142 144 +259 1 472 473 +260 1 472 474 +261 1 505 506 +262 1 505 507 +263 1 364 365 +264 1 364 366 +265 1 658 659 +266 1 658 660 +267 1 703 704 +268 1 703 705 +269 1 358 359 +270 1 358 360 +271 1 556 557 +272 1 556 558 +273 1 451 452 +274 1 451 453 +275 1 469 470 +276 1 469 471 +277 1 247 248 +278 1 247 249 +279 1 361 362 +280 1 361 363 +281 1 490 491 +282 1 490 492 +283 1 292 293 +284 1 292 294 +285 1 646 647 +286 1 646 648 +287 1 289 290 +288 1 289 291 +289 1 634 635 +290 1 634 636 +291 1 325 326 +292 1 325 327 +293 1 148 149 +294 1 148 150 +295 1 706 707 +296 1 706 708 +297 1 481 482 +298 1 481 483 +299 1 307 308 +300 1 307 309 +301 1 229 230 +302 1 229 231 +303 1 493 494 +304 1 493 495 +305 1 463 464 +306 1 463 465 +307 1 268 269 +308 1 268 270 +309 1 298 299 +310 1 298 300 +311 1 334 335 +312 1 334 336 +313 1 679 680 +314 1 679 681 +315 1 454 455 +316 1 454 456 +317 1 271 272 +318 1 271 273 +319 1 280 281 +320 1 280 282 +321 1 700 701 +322 1 700 702 +323 1 580 581 +324 1 580 582 +325 1 571 572 +326 1 571 573 +327 1 184 185 +328 1 184 186 +329 1 721 722 +330 1 721 723 +331 1 607 608 +332 1 607 609 +333 1 637 638 +334 1 637 639 +335 1 220 221 +336 1 220 222 +337 1 193 194 +338 1 193 195 +339 1 430 431 +340 1 430 432 +341 1 544 545 +342 1 544 546 +343 1 115 116 +344 1 115 117 +345 1 199 200 +346 1 199 201 +347 1 598 599 +348 1 598 600 +349 1 322 323 +350 1 322 324 +351 1 520 521 +352 1 520 522 +353 1 181 182 +354 1 181 183 +355 1 526 527 +356 1 526 528 +357 1 352 353 +358 1 352 354 +359 1 226 227 +360 1 226 228 +361 1 550 551 +362 1 550 552 +363 1 523 524 +364 1 523 525 +365 1 517 518 +366 1 517 519 +367 1 508 509 +368 1 508 510 +369 1 625 626 +370 1 625 627 +371 1 250 251 +372 1 250 252 +373 1 130 131 +374 1 130 132 +375 1 202 203 +376 1 202 204 +377 1 541 542 +378 1 541 543 +379 1 391 392 +380 1 391 393 +381 1 601 602 +382 1 601 603 +383 1 178 179 +384 1 178 180 +385 1 235 236 +386 1 235 237 +387 1 664 665 +388 1 664 666 +389 1 415 416 +390 1 415 417 +391 1 565 566 +392 1 565 567 +393 1 595 596 +394 1 595 597 +395 1 328 329 +396 1 328 330 +397 1 619 620 +398 1 619 621 +399 1 376 377 +400 1 376 378 +401 1 340 341 +402 1 340 342 +403 1 409 410 +404 1 409 411 +405 1 676 677 +406 1 676 678 +407 1 631 632 +408 1 631 633 +409 1 400 401 +410 1 400 402 +411 1 487 488 +412 1 487 489 +413 1 160 161 +414 1 160 162 +415 1 412 413 +416 1 412 414 +417 1 553 554 +418 1 553 555 +419 1 145 146 +420 1 145 147 Angles -1 1 677 676 678 -2 1 710 709 711 -3 1 194 193 195 -4 1 104 103 105 -5 1 713 712 714 -6 1 605 604 606 -7 1 389 388 390 -8 1 587 586 588 -9 1 602 601 603 -10 1 317 316 318 -11 1 422 421 423 -12 1 644 643 645 -13 1 692 691 693 -14 1 368 367 369 +1 1 656 655 657 +2 1 122 121 123 +3 1 692 691 693 +4 1 212 211 213 +5 1 530 529 531 +6 1 548 547 549 +7 1 338 337 339 +8 1 683 682 684 +9 1 458 457 459 +10 1 347 346 348 +11 1 560 559 561 +12 1 476 475 477 +13 1 446 445 447 +14 1 134 133 135 15 1 170 169 171 -16 1 542 541 543 -17 1 521 520 522 -18 1 212 211 213 -19 1 206 205 207 -20 1 680 679 681 -21 1 299 298 300 -22 1 497 496 498 -23 1 188 187 189 -24 1 386 385 387 -25 1 431 430 432 -26 1 476 475 477 -27 1 578 577 579 -28 1 281 280 282 -29 1 116 115 117 -30 1 197 196 198 -31 1 242 241 243 -32 1 401 400 402 -33 1 563 562 564 -34 1 665 664 666 -35 1 638 637 639 -36 1 653 652 654 -37 1 257 256 258 -38 1 425 424 426 -39 1 467 466 468 -40 1 581 580 582 -41 1 353 352 354 -42 1 293 292 294 -43 1 575 574 576 -44 1 437 436 438 -45 1 701 700 702 -46 1 107 106 108 -47 1 377 376 378 -48 1 359 358 360 -49 1 290 289 291 -50 1 407 406 408 -51 1 524 523 525 -52 1 626 625 627 -53 1 137 136 138 -54 1 185 184 186 -55 1 314 313 315 -56 1 239 238 240 -57 1 404 403 405 -58 1 698 697 699 -59 1 383 382 384 -60 1 671 670 672 -61 1 395 394 396 -62 1 203 202 204 -63 1 347 346 348 -64 1 572 571 573 -65 1 590 589 591 -66 1 608 607 609 -67 1 275 274 276 -68 1 113 112 114 -69 1 344 343 345 -70 1 254 253 255 -71 1 110 109 111 -72 1 308 307 309 -73 1 686 685 687 -74 1 272 271 273 -75 1 482 481 483 -76 1 722 721 723 -77 1 209 208 210 -78 1 470 469 471 -79 1 689 688 690 -80 1 635 634 636 -81 1 434 433 435 -82 1 416 415 417 -83 1 218 217 219 -84 1 479 478 480 -85 1 362 361 363 -86 1 485 484 486 -87 1 662 661 663 -88 1 101 100 102 -89 1 179 178 180 -90 1 215 214 216 -91 1 539 538 540 -92 1 227 226 228 -93 1 707 706 708 -94 1 374 373 375 -95 1 683 682 684 -96 1 596 595 597 -97 1 650 649 651 -98 1 338 337 339 -99 1 326 325 327 -100 1 536 535 537 -101 1 515 514 516 -102 1 167 166 168 -103 1 518 517 519 -104 1 149 148 150 -105 1 329 328 330 -106 1 458 457 459 -107 1 119 118 120 -108 1 191 190 192 -109 1 98 97 99 -110 1 245 244 246 -111 1 632 631 633 -112 1 296 295 297 -113 1 335 334 336 -114 1 656 655 657 -115 1 332 331 333 -116 1 224 223 225 -117 1 284 283 285 -118 1 695 694 696 -119 1 509 508 510 -120 1 263 262 264 -121 1 461 460 462 -122 1 356 355 357 -123 1 440 439 441 -124 1 593 592 594 -125 1 230 229 231 -126 1 443 442 444 -127 1 554 553 555 -128 1 248 247 249 -129 1 725 724 726 -130 1 341 340 342 -131 1 365 364 366 -132 1 503 502 504 -133 1 260 259 261 -134 1 641 640 642 -135 1 533 532 534 -136 1 236 235 237 -137 1 122 121 123 -138 1 266 265 267 -139 1 548 547 549 -140 1 620 619 621 -141 1 716 715 717 -142 1 647 646 648 -143 1 566 565 567 -144 1 545 544 546 -145 1 494 493 495 -146 1 302 301 303 -147 1 128 127 129 -148 1 392 391 393 -149 1 158 157 159 -150 1 413 412 414 -151 1 449 448 450 -152 1 278 277 279 -153 1 269 268 270 -154 1 143 142 144 -155 1 584 583 585 -156 1 719 718 720 -157 1 131 130 132 -158 1 134 133 135 -159 1 512 511 513 -160 1 569 568 570 -161 1 305 304 306 -162 1 419 418 420 -163 1 446 445 447 -164 1 464 463 465 -165 1 173 172 174 -166 1 500 499 501 -167 1 251 250 252 -168 1 323 322 324 -169 1 200 199 201 -170 1 623 622 624 -171 1 551 550 552 -172 1 125 124 126 -173 1 146 145 147 -174 1 704 703 705 -175 1 560 559 561 -176 1 599 598 600 -177 1 311 310 312 -178 1 140 139 141 -179 1 398 397 399 -180 1 320 319 321 -181 1 491 490 492 -182 1 371 370 372 -183 1 611 610 612 -184 1 155 154 156 -185 1 182 181 183 -186 1 629 628 630 -187 1 488 487 489 -188 1 527 526 528 -189 1 152 151 153 -190 1 161 160 162 -191 1 221 220 222 -192 1 350 349 351 -193 1 473 472 474 -194 1 287 286 288 -195 1 668 667 669 -196 1 233 232 234 -197 1 557 556 558 -198 1 614 613 615 -199 1 452 451 453 -200 1 428 427 429 -201 1 410 409 411 -202 1 674 673 675 -203 1 617 616 618 -204 1 530 529 531 -205 1 380 379 381 -206 1 659 658 660 -207 1 455 454 456 -208 1 176 175 177 -209 1 506 505 507 -210 1 164 163 165 +16 1 383 382 384 +17 1 188 187 189 +18 1 497 496 498 +19 1 101 100 102 +20 1 320 319 321 +21 1 218 217 219 +22 1 674 673 675 +23 1 314 313 315 +24 1 422 421 423 +25 1 311 310 312 +26 1 590 589 591 +27 1 461 460 462 +28 1 500 499 501 +29 1 278 277 279 +30 1 371 370 372 +31 1 155 154 156 +32 1 317 316 318 +33 1 275 274 276 +34 1 254 253 255 +35 1 407 406 408 +36 1 296 295 297 +37 1 152 151 153 +38 1 344 343 345 +39 1 695 694 696 +40 1 266 265 267 +41 1 107 106 108 +42 1 428 427 429 +43 1 563 562 564 +44 1 104 103 105 +45 1 233 232 234 +46 1 569 568 570 +47 1 536 535 537 +48 1 713 712 714 +49 1 449 448 450 +50 1 404 403 405 +51 1 176 175 177 +52 1 668 667 669 +53 1 485 484 486 +54 1 515 514 516 +55 1 479 478 480 +56 1 374 373 375 +57 1 128 127 129 +58 1 671 670 672 +59 1 716 715 717 +60 1 689 688 690 +61 1 605 604 606 +62 1 110 109 111 +63 1 206 205 207 +64 1 113 112 114 +65 1 125 124 126 +66 1 617 616 618 +67 1 575 574 576 +68 1 425 424 426 +69 1 710 709 711 +70 1 467 466 468 +71 1 533 532 534 +72 1 512 511 513 +73 1 197 196 198 +74 1 350 349 351 +75 1 623 622 624 +76 1 644 643 645 +77 1 584 583 585 +78 1 173 172 174 +79 1 503 502 504 +80 1 386 385 387 +81 1 260 259 261 +82 1 611 610 612 +83 1 368 367 369 +84 1 578 577 579 +85 1 98 97 99 +86 1 167 166 168 +87 1 395 394 396 +88 1 434 433 435 +89 1 356 355 357 +90 1 653 652 654 +91 1 245 244 246 +92 1 698 697 699 +93 1 593 592 594 +94 1 209 208 210 +95 1 641 640 642 +96 1 137 136 138 +97 1 140 139 141 +98 1 287 286 288 +99 1 224 223 225 +100 1 257 256 258 +101 1 389 388 390 +102 1 629 628 630 +103 1 662 661 663 +104 1 158 157 159 +105 1 332 331 333 +106 1 419 418 420 +107 1 305 304 306 +108 1 725 724 726 +109 1 398 397 399 +110 1 284 283 285 +111 1 164 163 165 +112 1 686 685 687 +113 1 650 649 651 +114 1 587 586 588 +115 1 215 214 216 +116 1 191 190 192 +117 1 539 538 540 +118 1 263 262 264 +119 1 443 442 444 +120 1 614 613 615 +121 1 239 238 240 +122 1 437 436 438 +123 1 719 718 720 +124 1 119 118 120 +125 1 302 301 303 +126 1 380 379 381 +127 1 440 439 441 +128 1 242 241 243 +129 1 143 142 144 +130 1 473 472 474 +131 1 506 505 507 +132 1 365 364 366 +133 1 659 658 660 +134 1 704 703 705 +135 1 359 358 360 +136 1 557 556 558 +137 1 452 451 453 +138 1 470 469 471 +139 1 248 247 249 +140 1 362 361 363 +141 1 491 490 492 +142 1 293 292 294 +143 1 647 646 648 +144 1 290 289 291 +145 1 635 634 636 +146 1 326 325 327 +147 1 149 148 150 +148 1 707 706 708 +149 1 482 481 483 +150 1 308 307 309 +151 1 230 229 231 +152 1 494 493 495 +153 1 464 463 465 +154 1 269 268 270 +155 1 299 298 300 +156 1 335 334 336 +157 1 680 679 681 +158 1 455 454 456 +159 1 272 271 273 +160 1 281 280 282 +161 1 701 700 702 +162 1 581 580 582 +163 1 572 571 573 +164 1 185 184 186 +165 1 722 721 723 +166 1 608 607 609 +167 1 638 637 639 +168 1 221 220 222 +169 1 194 193 195 +170 1 431 430 432 +171 1 545 544 546 +172 1 116 115 117 +173 1 200 199 201 +174 1 599 598 600 +175 1 323 322 324 +176 1 521 520 522 +177 1 182 181 183 +178 1 527 526 528 +179 1 353 352 354 +180 1 227 226 228 +181 1 551 550 552 +182 1 524 523 525 +183 1 518 517 519 +184 1 509 508 510 +185 1 626 625 627 +186 1 251 250 252 +187 1 131 130 132 +188 1 203 202 204 +189 1 542 541 543 +190 1 392 391 393 +191 1 602 601 603 +192 1 179 178 180 +193 1 236 235 237 +194 1 665 664 666 +195 1 416 415 417 +196 1 566 565 567 +197 1 596 595 597 +198 1 329 328 330 +199 1 620 619 621 +200 1 377 376 378 +201 1 341 340 342 +202 1 410 409 411 +203 1 677 676 678 +204 1 632 631 633 +205 1 401 400 402 +206 1 488 487 489 +207 1 161 160 162 +208 1 413 412 414 +209 1 554 553 555 +210 1 146 145 147 diff --git a/examples/PACKAGES/electrode/piston/in.piston b/examples/PACKAGES/electrode/piston/in.piston index 35b4790935..f277e7cebd 100644 --- a/examples/PACKAGES/electrode/piston/in.piston +++ b/examples/PACKAGES/electrode/piston/in.piston @@ -42,7 +42,11 @@ fix fxforce_au gold setforce 0.0 0.0 0.0 # equilibrate z-coordinate of upper electrode while keeping the electrode rigid fix fxforce_wa wall setforce 0.0 0.0 NULL -fix fxpressure wall aveforce 0 0 -0.005246 # atomspheric pressure: area/force->nktv2p +variable atm equal 1/68568.415 # 1/force->nktv2p +variable area equal (xhi-xlo)*(yhi-ylo) +variable wall_force equal -v_atm*v_area/count(wall) +print "Wall force per atom: ${wall_force}" +fix fxpressure wall aveforce 0 0 ${wall_force} # atomspheric pressure: area/force->nktv2p fix fxdrag wall viscous 100 fix fxrigid wall rigid/nve single diff --git a/examples/PACKAGES/electrode/piston/log.1Dec2022.piston.g++.1 b/examples/PACKAGES/electrode/piston/log.22May2024.piston.g++.1 similarity index 64% rename from examples/PACKAGES/electrode/piston/log.1Dec2022.piston.g++.1 rename to examples/PACKAGES/electrode/piston/log.22May2024.piston.g++.1 index a5b6d4cd4f..a52061a57b 100644 --- a/examples/PACKAGES/electrode/piston/log.1Dec2022.piston.g++.1 +++ b/examples/PACKAGES/electrode/piston/log.22May2024.piston.g++.1 @@ -1,4 +1,5 @@ -LAMMPS (3 Nov 2022) +LAMMPS (7 Feb 2024 - Development - patch_7Feb2024_update1-217-g1909233c69-modified) + using 1 OpenMP thread(s) per MPI task # The intention is to find the average position of one wall at atmospheric # pressure. The output is the wall position over time which can be used to # find the average position for a run with fixed wall position. @@ -40,8 +41,8 @@ Finding 1-2 1-3 1-4 neighbors ... 1 = max # of 1-3 neighbors 1 = max # of 1-4 neighbors 2 = max # of special neighbors - special bonds CPU = 0.001 seconds - read_data CPU = 0.011 seconds + special bonds CPU = 0.000 seconds + read_data CPU = 0.012 seconds # ----------------- Settings Section ----------------- @@ -77,7 +78,13 @@ fix fxforce_au gold setforce 0.0 0.0 0.0 # equilibrate z-coordinate of upper electrode while keeping the electrode rigid fix fxforce_wa wall setforce 0.0 0.0 NULL -fix fxpressure wall aveforce 0 0 -0.005246 # atomspheric pressure: area/force->nktv2p +variable atm equal 1/68568.415 # 1/force->nktv2p +variable area equal (xhi-xlo)*(yhi-ylo) +variable wall_force equal -v_atm*v_area/count(wall) +print "Wall force per atom: ${wall_force}" +Wall force per atom: -0.000109285996244287 +fix fxpressure wall aveforce 0 0 ${wall_force} # atomspheric pressure: area/force->nktv2p +fix fxpressure wall aveforce 0 0 -0.000109285996244287 fix fxdrag wall viscous 100 fix fxrigid wall rigid/nve single 1 rigid bodies with 48 atoms @@ -134,7 +141,7 @@ PPPM/electrode initialization ... stencil order = 5 estimated absolute RMS force accuracy = 0.02930901 estimated relative force accuracy = 8.8263214e-05 - using double precision MKL FFT + using double precision FFTW3 3d grid and FFT values/proc = 15884 6480 Generated 6 of 6 mixed pair_coeff terms from arithmetic mixing rule Neighbor list info ... @@ -157,54 +164,54 @@ Neighbor list info ... Per MPI rank memory allocation (min/avg/max) = 11.7 | 11.7 | 11.7 Mbytes Step c_temp_mobile c_qwa c_qau v_top_wall 0 303.38967 -0.042963484 0.042963484 21.4018 - 5000 285.08828 -0.26105255 0.26105255 25.155629 - 10000 323.19176 -0.26264003 0.26264003 24.541676 - 15000 310.479 -0.27318148 0.27318148 23.141522 - 20000 295.18544 -0.11313444 0.11313444 23.828735 - 25000 295.38607 -0.25433086 0.25433086 23.673314 - 30000 288.0613 -0.30099901 0.30099901 23.438086 - 35000 278.5591 -0.15823576 0.15823576 24.311915 - 40000 303.95751 -0.19941381 0.19941381 23.69594 - 45000 279.026 -0.1659962 0.1659962 23.588604 - 50000 298.79278 -0.28866703 0.28866703 23.372508 - 55000 301.03353 -0.078370381 0.078370381 23.192985 - 60000 306.77965 -0.12807205 0.12807205 23.968574 - 65000 309.86008 -0.27162663 0.27162663 23.616704 - 70000 287.31116 -0.029751882 0.029751882 23.667495 - 75000 312.48654 -0.10759866 0.10759866 23.504105 - 80000 309.94267 -0.2558548 0.2558548 23.810576 - 85000 328.04389 -0.1575471 0.1575471 24.013437 - 90000 302.9806 -0.032002164 0.032002164 24.264432 - 95000 294.20804 -0.27797238 0.27797238 23.291758 - 100000 307.63019 -0.19047448 0.19047448 23.632147 -Loop time of 530.844 on 1 procs for 100000 steps with 726 atoms + 5000 311.85363 0.03543775 -0.03543775 24.79665 + 10000 285.91321 -0.16873703 0.16873703 23.103088 + 15000 295.39476 -0.44424612 0.44424612 23.767107 + 20000 296.12969 -0.14120993 0.14120993 23.96361 + 25000 306.59629 -0.29333182 0.29333182 23.884488 + 30000 297.98559 -0.10749684 0.10749684 23.73316 + 35000 297.98503 -0.11809975 0.11809975 23.984669 + 40000 300.26292 -0.32784184 0.32784184 23.462748 + 45000 295.68441 -0.25940165 0.25940165 23.516403 + 50000 315.12883 -0.36037614 0.36037614 23.627879 + 55000 290.55151 -0.0032838106 0.0032838106 23.684931 + 60000 316.4625 -0.17245368 0.17245368 24.126883 + 65000 296.79343 -0.054061851 0.054061851 23.695094 + 70000 305.99923 -0.11363801 0.11363801 23.55476 + 75000 297.40131 -0.27054153 0.27054153 23.928994 + 80000 306.54811 -0.25409719 0.25409719 23.869448 + 85000 303.95231 -0.17895561 0.17895561 23.658833 + 90000 313.43739 -0.059036514 0.059036514 23.36056 + 95000 290.3077 -0.31394478 0.31394478 23.885538 + 100000 297.5156 -0.30730083 0.30730083 23.511674 +Loop time of 1586.06 on 1 procs for 100000 steps with 726 atoms -Performance: 32.552 ns/day, 0.737 hours/ns, 188.379 timesteps/s, 136.763 katom-step/s -100.0% CPU use with 1 MPI tasks x no OpenMP threads +Performance: 10.895 ns/day, 2.203 hours/ns, 63.049 timesteps/s, 45.774 katom-step/s +99.6% CPU use with 1 MPI tasks x 1 OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 190.47 | 190.47 | 190.47 | 0.0 | 35.88 -Bond | 0.10754 | 0.10754 | 0.10754 | 0.0 | 0.02 -Kspace | 73.179 | 73.179 | 73.179 | 0.0 | 13.79 -Neigh | 24.209 | 24.209 | 24.209 | 0.0 | 4.56 -Comm | 1.6857 | 1.6857 | 1.6857 | 0.0 | 0.32 -Output | 0.0016861 | 0.0016861 | 0.0016861 | 0.0 | 0.00 -Modify | 240.23 | 240.23 | 240.23 | 0.0 | 45.26 -Other | | 0.9595 | | | 0.18 +Pair | 460.91 | 460.91 | 460.91 | 0.0 | 29.06 +Bond | 0.047873 | 0.047873 | 0.047873 | 0.0 | 0.00 +Kspace | 341.4 | 341.4 | 341.4 | 0.0 | 21.53 +Neigh | 52.868 | 52.868 | 52.868 | 0.0 | 3.33 +Comm | 5.2321 | 5.2321 | 5.2321 | 0.0 | 0.33 +Output | 0.00099102 | 0.00099102 | 0.00099102 | 0.0 | 0.00 +Modify | 724.63 | 724.63 | 724.63 | 0.0 | 45.69 +Other | | 0.9741 | | | 0.06 Nlocal: 726 ave 726 max 726 min Histogram: 1 0 0 0 0 0 0 0 0 0 -Nghost: 2335 ave 2335 max 2335 min +Nghost: 2336 ave 2336 max 2336 min Histogram: 1 0 0 0 0 0 0 0 0 0 -Neighs: 120271 ave 120271 max 120271 min +Neighs: 120321 ave 120321 max 120321 min Histogram: 1 0 0 0 0 0 0 0 0 0 -Total # of neighbors = 120271 -Ave neighs/atom = 165.66253 +Total # of neighbors = 120321 +Ave neighs/atom = 165.7314 Ave special neighs/atom = 1.7355372 -Neighbor list builds = 7722 +Neighbor list builds = 7670 Dangerous builds = 0 write_data "data.piston.final" System init for write_data ... @@ -213,11 +220,11 @@ PPPM/electrode initialization ... G vector (1/distance) = 0.32814871 grid = 12 15 36 stencil order = 5 - estimated absolute RMS force accuracy = 0.029311365 - estimated relative force accuracy = 8.8270304e-05 - using double precision MKL FFT + estimated absolute RMS force accuracy = 0.029311329 + estimated relative force accuracy = 8.8270197e-05 + using double precision FFTW3 3d grid and FFT values/proc = 15884 6480 Generated 6 of 6 mixed pair_coeff terms from arithmetic mixing rule Average conjugate gradient steps: 1.981 -Total wall time: 0:08:50 +Total wall time: 0:26:26 diff --git a/examples/PACKAGES/electrode/piston/log.1Dec2022.piston.g++.4 b/examples/PACKAGES/electrode/piston/log.22May2024.piston.g++.4 similarity index 61% rename from examples/PACKAGES/electrode/piston/log.1Dec2022.piston.g++.4 rename to examples/PACKAGES/electrode/piston/log.22May2024.piston.g++.4 index ffb6bcc61c..2534176dc6 100644 --- a/examples/PACKAGES/electrode/piston/log.1Dec2022.piston.g++.4 +++ b/examples/PACKAGES/electrode/piston/log.22May2024.piston.g++.4 @@ -1,4 +1,5 @@ -LAMMPS (3 Nov 2022) +LAMMPS (7 Feb 2024 - Development - patch_7Feb2024_update1-217-g1909233c69-modified) + using 1 OpenMP thread(s) per MPI task # The intention is to find the average position of one wall at atmospheric # pressure. The output is the wall position over time which can be used to # find the average position for a run with fixed wall position. @@ -41,8 +42,8 @@ Finding 1-2 1-3 1-4 neighbors ... 1 = max # of 1-3 neighbors 1 = max # of 1-4 neighbors 2 = max # of special neighbors - special bonds CPU = 0.001 seconds - read_data CPU = 0.017 seconds + special bonds CPU = 0.000 seconds + read_data CPU = 0.012 seconds # ----------------- Settings Section ----------------- @@ -66,7 +67,7 @@ Finding SHAKE clusters ... 0 = # of size 3 clusters 0 = # of size 4 clusters 210 = # of frozen angles - find clusters CPU = 0.002 seconds + find clusters CPU = 0.000 seconds pair_modify mix arithmetic # ----------------- Run Section ----------------- @@ -78,7 +79,13 @@ fix fxforce_au gold setforce 0.0 0.0 0.0 # equilibrate z-coordinate of upper electrode while keeping the electrode rigid fix fxforce_wa wall setforce 0.0 0.0 NULL -fix fxpressure wall aveforce 0 0 -0.005246 # atomspheric pressure: area/force->nktv2p +variable atm equal 1/68568.415 # 1/force->nktv2p +variable area equal (xhi-xlo)*(yhi-ylo) +variable wall_force equal -v_atm*v_area/count(wall) +print "Wall force per atom: ${wall_force}" +Wall force per atom: -0.000109285996244287 +fix fxpressure wall aveforce 0 0 ${wall_force} # atomspheric pressure: area/force->nktv2p +fix fxpressure wall aveforce 0 0 -0.000109285996244287 fix fxdrag wall viscous 100 fix fxrigid wall rigid/nve single 1 rigid bodies with 48 atoms @@ -135,7 +142,7 @@ PPPM/electrode initialization ... stencil order = 5 estimated absolute RMS force accuracy = 0.02930901 estimated relative force accuracy = 8.8263214e-05 - using double precision MKL FFT + using double precision FFTW3 3d grid and FFT values/proc = 8512 2880 Generated 6 of 6 mixed pair_coeff terms from arithmetic mixing rule Neighbor list info ... @@ -158,54 +165,54 @@ Neighbor list info ... Per MPI rank memory allocation (min/avg/max) = 10.06 | 10.22 | 10.41 Mbytes Step c_temp_mobile c_qwa c_qau v_top_wall 0 303.38967 -0.042963484 0.042963484 21.4018 - 5000 292.03027 -0.19040435 0.19040435 24.581338 - 10000 309.52764 -0.48308301 0.48308301 23.776985 - 15000 295.00243 -0.16591109 0.16591109 23.672038 - 20000 293.5536 -0.086669084 0.086669084 23.426455 - 25000 303.0079 -0.16488112 0.16488112 23.862966 - 30000 306.31463 -0.23192653 0.23192653 23.819882 - 35000 303.66268 -0.2317907 0.2317907 23.495344 - 40000 301.39435 -0.34661329 0.34661329 23.657835 - 45000 291.61205 -0.30539427 0.30539427 23.437303 - 50000 298.65319 -0.096107034 0.096107034 23.57809 - 55000 282.65069 -0.14943539 0.14943539 23.823728 - 60000 310.64182 -0.17418813 0.17418813 23.286959 - 65000 308.47141 -0.02075662 0.02075662 23.91313 - 70000 292.5186 -0.080163162 0.080163162 23.96283 - 75000 270.13928 -0.029528648 0.029528648 23.488972 - 80000 322.10914 0.030761045 -0.030761045 23.47592 - 85000 310.60347 -0.24069996 0.24069996 23.987091 - 90000 294.35695 -0.070458235 0.070458235 23.397929 - 95000 308.69043 -0.2652581 0.2652581 23.473813 - 100000 318.71883 0.024035956 -0.024035956 23.449863 -Loop time of 590.232 on 4 procs for 100000 steps with 726 atoms + 5000 291.6303 -0.1820085 0.1820085 24.641399 + 10000 299.42886 -0.19823095 0.19823095 23.820522 + 15000 288.23071 -0.065261869 0.065261869 23.360845 + 20000 299.4644 -0.042993777 0.042993777 23.987554 + 25000 304.26497 -0.15665293 0.15665293 23.729006 + 30000 292.29674 -0.25142779 0.25142779 23.960725 + 35000 295.57492 -0.01269228 0.01269228 23.445383 + 40000 303.38438 -0.13941727 0.13941727 23.517483 + 45000 302.211 -0.19589892 0.19589892 23.704043 + 50000 281.64939 -0.18057298 0.18057298 23.542137 + 55000 274.90565 -0.15453379 0.15453379 23.734347 + 60000 290.70459 -0.27977436 0.27977436 23.835365 + 65000 293.42241 -0.2454241 0.2454241 23.59269 + 70000 295.20229 -0.041314995 0.041314995 23.73856 + 75000 297.79519 -0.11231755 0.11231755 23.57262 + 80000 285.17858 -0.070796508 0.070796508 23.817135 + 85000 311.71609 -0.068920177 0.068920177 23.861127 + 90000 287.80446 -0.19183387 0.19183387 23.369393 + 95000 309.43345 -0.15238671 0.15238671 23.597792 + 100000 294.12422 -0.14284353 0.14284353 23.526286 +Loop time of 876.546 on 4 procs for 100000 steps with 726 atoms -Performance: 29.277 ns/day, 0.820 hours/ns, 169.425 timesteps/s, 123.003 katom-step/s -72.5% CPU use with 4 MPI tasks x no OpenMP threads +Performance: 19.714 ns/day, 1.217 hours/ns, 114.084 timesteps/s, 82.825 katom-step/s +98.6% CPU use with 4 MPI tasks x 1 OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 57.391 | 75.867 | 96.292 | 212.1 | 12.85 -Bond | 0.10177 | 0.11042 | 0.12415 | 2.7 | 0.02 -Kspace | 102.79 | 123.16 | 141.5 | 165.7 | 20.87 -Neigh | 12.808 | 12.895 | 12.982 | 2.3 | 2.18 -Comm | 18.885 | 19.973 | 21.064 | 24.0 | 3.38 -Output | 0.0022573 | 0.0022749 | 0.0023225 | 0.1 | 0.00 -Modify | 355.89 | 356.74 | 357.61 | 4.2 | 60.44 -Other | | 1.478 | | | 0.25 +Pair | 123.63 | 171.23 | 215.73 | 336.6 | 19.53 +Bond | 0.068261 | 0.075883 | 0.081822 | 1.9 | 0.01 +Kspace | 187.59 | 231.71 | 279.01 | 287.1 | 26.43 +Neigh | 29.28 | 29.462 | 29.637 | 2.5 | 3.36 +Comm | 12.544 | 13.731 | 14.929 | 29.1 | 1.57 +Output | 0.0010182 | 0.0014585 | 0.0016071 | 0.7 | 0.00 +Modify | 428.74 | 429.25 | 429.74 | 2.3 | 48.97 +Other | | 1.092 | | | 0.12 -Nlocal: 181.5 ave 207 max 169 min -Histogram: 2 0 1 0 0 0 0 0 0 1 -Nghost: 1961.5 ave 1984 max 1926 min -Histogram: 1 0 0 0 0 0 1 0 1 1 -Neighs: 30051 ave 41646 max 20775 min -Histogram: 1 1 0 0 0 0 1 0 0 1 +Nlocal: 181.5 ave 195 max 166 min +Histogram: 1 1 0 0 0 0 0 0 0 2 +Nghost: 1955.5 ave 1978 max 1931 min +Histogram: 1 0 0 0 1 0 1 0 0 1 +Neighs: 30343 ave 39847 max 20428 min +Histogram: 2 0 0 0 0 0 0 0 0 2 -Total # of neighbors = 120204 -Ave neighs/atom = 165.57025 +Total # of neighbors = 121372 +Ave neighs/atom = 167.17906 Ave special neighs/atom = 1.7355372 -Neighbor list builds = 7663 +Neighbor list builds = 7698 Dangerous builds = 0 write_data "data.piston.final" System init for write_data ... @@ -214,11 +221,11 @@ PPPM/electrode initialization ... G vector (1/distance) = 0.32814871 grid = 12 15 36 stencil order = 5 - estimated absolute RMS force accuracy = 0.029311028 - estimated relative force accuracy = 8.8269289e-05 - using double precision MKL FFT + estimated absolute RMS force accuracy = 0.029310954 + estimated relative force accuracy = 8.8269069e-05 + using double precision FFTW3 3d grid and FFT values/proc = 8512 2880 Generated 6 of 6 mixed pair_coeff terms from arithmetic mixing rule -Average conjugate gradient steps: 1.982 -Total wall time: 0:09:50 +Average conjugate gradient steps: 1.981 +Total wall time: 0:14:36 From 37f32330404a80c674470596cb3d2c42ce31385f Mon Sep 17 00:00:00 2001 From: Ludwig Ahrens-Iwers Date: Thu, 13 Jun 2024 17:14:13 +0200 Subject: [PATCH 113/385] Check the atom style has an atom map --- src/ELECTRODE/fix_electrode_conp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ELECTRODE/fix_electrode_conp.cpp b/src/ELECTRODE/fix_electrode_conp.cpp index 94c085de5c..14cc8fb119 100644 --- a/src/ELECTRODE/fix_electrode_conp.cpp +++ b/src/ELECTRODE/fix_electrode_conp.cpp @@ -79,6 +79,9 @@ FixElectrodeConp::FixElectrodeConp(LAMMPS *lmp, int narg, char **arg) : potential_i(nullptr), potential_iele(nullptr) { if (lmp->citeme) lmp->citeme->add(cite_fix_electrode); + if (!atom->map_style) + error->all(FLERR, + "Atom style does not have an atom map. Use 'atom_modify map yes' to activate it."); // fix.h output flags scalar_flag = 1; vector_flag = 1; From 1349d7632e7a7cb0f483bde4e41bd5b935c913cd Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jun 2024 20:26:45 -0400 Subject: [PATCH 114/385] flag KOKKOS support for added styles in commands lists --- doc/src/Commands_bond.rst | 2 +- doc/src/Commands_pair.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/Commands_bond.rst b/doc/src/Commands_bond.rst index fcd725d787..9558735858 100644 --- a/doc/src/Commands_bond.rst +++ b/doc/src/Commands_bond.rst @@ -100,7 +100,7 @@ OPT. * :doc:`mesocnt ` * :doc:`mm3 ` * :doc:`quartic (o) ` - * :doc:`spica (o) ` + * :doc:`spica (ko) ` * :doc:`table (o) ` .. _dihedral: diff --git a/doc/src/Commands_pair.rst b/doc/src/Commands_pair.rst index 514785c15c..cd0ada6a4a 100644 --- a/doc/src/Commands_pair.rst +++ b/doc/src/Commands_pair.rst @@ -190,7 +190,7 @@ OPT. * :doc:`lj/mdf ` * :doc:`lj/relres (o) ` * :doc:`lj/spica (gko) ` - * :doc:`lj/spica/coul/long (go) ` + * :doc:`lj/spica/coul/long (gko) ` * :doc:`lj/spica/coul/msm (o) ` * :doc:`lj/sf/dipole/sf (go) ` * :doc:`lj/smooth (go) ` From 7e7f3c08f4ffaf1944d900eb4f18a64ffb54fef5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jun 2024 20:29:26 -0400 Subject: [PATCH 115/385] make check more specific but accelerator compatible --- unittest/force-styles/test_angle_style.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index afee85d263..ecb6c44c71 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -645,7 +645,7 @@ TEST(AngleStyle, single) "extra/angle/per/atom 2 extra/special/per/atom 2", nangletypes)); - if (utils::strmatch(test_config.angle_style, "spica")) { + if (utils::strmatch(test_config.angle_style, "^spica")) { command("pair_style lj/spica 8.0"); command("pair_coeff * * lj9_6 0.02 2.5"); } else { From 5207b93fd8a1d0d54f9100d4a43b0ebbf35cd36e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jun 2024 20:33:44 -0400 Subject: [PATCH 116/385] small update for consistency --- unittest/force-styles/tests/angle-spica.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/unittest/force-styles/tests/angle-spica.yaml b/unittest/force-styles/tests/angle-spica.yaml index 7654be0345..7f88553c70 100644 --- a/unittest/force-styles/tests/angle-spica.yaml +++ b/unittest/force-styles/tests/angle-spica.yaml @@ -1,6 +1,6 @@ --- lammps_version: 7 Feb 2024 -tags: generated +tags: date_generated: Wed Jun 5 18:31:11 2024 epsilon: 1e-12 skip_tests: @@ -14,7 +14,11 @@ post_commands: ! | pair_style lj/spica 8.0 input_file: in.spica angle_style: spica -angle_coeff: ! "1 33.5 110.1 \n2 46.1 111.3 \n3 40.0 120.0 \n4 33.0 108.5 \n" +angle_coeff: ! | + 1 33.5 110.1 + 2 46.1 111.3 + 3 40.0 120.0 + 4 33.0 108.5 equilibrium: 4 1.9216075064457565 1.9425514574696887 2.0943951023931953 1.8936822384138474 extract: ! "" natoms: 29 From 21a42c1304ee9534bfd18b09cee8f4b51622d8a4 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jun 2024 14:08:47 -0600 Subject: [PATCH 117/385] Small cleanup --- src/KOKKOS/angle_spica_kokkos.cpp | 5 +---- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 22 ++----------------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 25cbc1dced..b36923e8b1 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -84,11 +84,8 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) d_vatom = k_vatom.template view(); } - //atomKK->sync(execution_space,datamask_read); k_k.template sync(); k_theta0.template sync(); - // if (eflag || vflag) atomKK->modified(execution_space,datamask_modify); - // else atomKK->modified(execution_space,F_MASK); x = atomKK->k_x.template view(); f = atomKK->k_f.template view(); @@ -244,7 +241,6 @@ void AngleSPICAKokkos::operator()(TagAngleSPICACompute::ev_tally13(EV_FLOAT &ev, const int i, const i } } } + /* ---------------------------------------------------------------------- */ namespace LAMMPS_NS { diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp index 37cbe7d17f..860055b62b 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -75,7 +75,6 @@ void PairLJSPICACoulLongKokkos::compute(int eflag_in, int vflag_in) eflag = eflag_in; vflag = vflag_in; - if (neighflag == FULL) no_virial_fdotr_compute = 1; ev_init(eflag,vflag,0); @@ -119,11 +118,8 @@ void PairLJSPICACoulLongKokkos::compute(int eflag_in, int vflag_in) // loop over neighbors of my atoms - // FIXME: taken from pair_lj_charmmfsw_coul_long, is it needed ??? copymode = 1; - //EV_FLOAT ev = pair_compute,void >(this,(NeighListKokkos*)list); - EV_FLOAT ev; if (ncoultablebits) ev = pair_compute,CoulLongTable<1> > @@ -132,7 +128,7 @@ void PairLJSPICACoulLongKokkos::compute(int eflag_in, int vflag_in) ev = pair_compute,CoulLongTable<0> > (this,(NeighListKokkos*)list); - if (eflag) { + if (eflag_global) { eng_vdwl += ev.evdwl; eng_coul += ev.ecoul; } @@ -158,6 +154,7 @@ void PairLJSPICACoulLongKokkos::compute(int eflag_in, int vflag_in) if (vflag_fdotr) pair_virial_fdotr_compute(this); + copymode = 0; } /* ---------------------------------------------------------------------- @@ -208,7 +205,6 @@ compute_fpair(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, c return a* ( lj_1*r6inv*b - lj_2 * r2inv); } - /* ---------------------------------------------------------------------- compute pair potential energy between atoms i and j ---------------------------------------------------------------------- */ @@ -325,11 +321,8 @@ compute_fcoul(const F_FLOAT& rsq, const int& /*i*/, const int&j, return forcecoul*rinv*rinv; } - - } - /* ---------------------------------------------------------------------- compute coulomb pair potential energy between atoms i and j ------------------------------------------------------------------------- */ @@ -366,8 +359,6 @@ compute_ecoul(const F_FLOAT& rsq, const int& /*i*/, const int&j, } } - - /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ @@ -403,12 +394,10 @@ void PairLJSPICACoulLongKokkos::settings(int narg, char **arg) PairLJSPICACoulLong::settings(1,arg); } - /* ---------------------------------------------------------------------- init tables ------------------------------------------------------------------------- */ - template void PairLJSPICACoulLongKokkos::init_tables(double cut_coul, double *cut_respa) { @@ -512,8 +501,6 @@ void PairLJSPICACoulLongKokkos::init_tables(double cut_coul, double } } - - /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ @@ -523,9 +510,6 @@ void PairLJSPICACoulLongKokkos::init_style() { PairLJSPICACoulLong::init_style(); - //Kokkos::deep_copy(d_cut_ljsq,cut_ljsq); - //Kokkos::deep_copy(d_cut_coulsq,cut_coulsq); - // error if rRESPA with inner levels if (update->whichflag == 1 && utils::strmatch(update->integrate_style,"^respa")) { @@ -581,8 +565,6 @@ double PairLJSPICACoulLongKokkos::init_one(int i, int j) return cutone; } - - namespace LAMMPS_NS { template class PairLJSPICACoulLongKokkos; #ifdef LMP_KOKKOS_GPU From 43bace67481b259978929e94ea709fc06898ced7 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 24 Jun 2024 15:16:37 -0600 Subject: [PATCH 118/385] Fix typo --- src/KOKKOS/Install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index 62fa0d1cec..ed1e093642 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -346,8 +346,8 @@ action pair_lj_gromacs_coul_gromacs_kokkos.cpp pair_lj_gromacs_coul_gromacs.cpp action pair_lj_gromacs_coul_gromacs_kokkos.h pair_lj_gromacs_coul_gromacs.h action pair_lj_gromacs_kokkos.cpp pair_lj_gromacs.cpp action pair_lj_gromacs_kokkos.h pair_lj_gromacs.h -action pair_lj_spica_coul_long_kokkos.cpp pair_lj_coul_long_spica.cpp -action pair_lj_spica_coul_long_kokkos.h pair_lj_coul_long_spica.h +action pair_lj_spica_coul_long_kokkos.cpp pair_lj_spica_coul_long.cpp +action pair_lj_spica_coul_long_kokkos.h pair_lj_spica_coul_long.h action pair_lj_spica_kokkos.cpp pair_lj_spica.cpp action pair_lj_spica_kokkos.h pair_lj_spica.h action pair_meam_kokkos.cpp pair_meam.cpp From 5442446460131bfed3b19bf86501f112ddf60db1 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Mon, 24 Jun 2024 17:44:07 -0400 Subject: [PATCH 119/385] remove commented out code --- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 66 ------------------- src/KOKKOS/pair_lj_spica_kokkos.cpp | 28 -------- 2 files changed, 94 deletions(-) diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp index 860055b62b..1f7573836a 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -174,30 +174,6 @@ compute_fpair(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, c const F_FLOAT lj_1 = (STACKPARAMS?m_params[itype][jtype].lj1:params(itype,jtype).lj1); const F_FLOAT lj_2 = (STACKPARAMS?m_params[itype][jtype].lj2:params(itype,jtype).lj2); - /*if (ljt == LJ12_4) { - - const F_FLOAT r4inv=r2inv*r2inv; - return r4inv*(lj_1*r4inv*r4inv - lj_2) * r2inv; - - } else if (ljt == LJ9_6) { - - const F_FLOAT r3inv = r2inv*sqrt(r2inv); - const F_FLOAT r6inv = r3inv*r3inv; - return r6inv*(lj_1*r3inv - lj_2) * r2inv; - - } else if (ljt == LJ12_6) { - - const double r6inv = r2inv*r2inv*r2inv; - return r6inv*(lj_1*r6inv - lj_2) * r2inv; - - } else if (ljt == LJ12_5) { - - const F_FLOAT r5inv = r2inv*r2inv*sqrt(r2inv); - const F_FLOAT r7inv = r5inv*r2inv; - return r5inv*(lj_1*r7inv - lj_2) * r2inv; - - } - if (ljt!=LJ12_4 && ljt!=LJ9_6 && ljt!=LJ12_6 && ljt!=LJ12_5) return 0.0;*/ const F_FLOAT r4inv=r2inv*r2inv; const F_FLOAT r6inv=r2inv*r4inv; const F_FLOAT a = ljt==LJ12_4?r4inv:(ljt==LJ12_5?r4inv*sqrt(r2inv):r6inv); @@ -225,18 +201,14 @@ compute_evdwl(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, c if (ljt == LJ12_4) { const F_FLOAT r4inv=r2inv*r2inv; - return r4inv*(lj_3*r4inv*r4inv - lj_4) - offset; - } else if (ljt == LJ9_6) { const F_FLOAT r3inv = r2inv*sqrt(r2inv); const F_FLOAT r6inv = r3inv*r3inv; return r6inv*(lj_3*r3inv - lj_4) - offset; - } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; return r6inv*(lj_3*r6inv - lj_4) - offset; - } else if (ljt == LJ12_5) { const F_FLOAT r5inv = r2inv*r2inv*sqrt(r2inv); const F_FLOAT r7inv = r5inv*r2inv; @@ -257,44 +229,6 @@ compute_fcoul(const F_FLOAT& rsq, const int& /*i*/, const int&j, const int& /*itype*/, const int& /*jtype*/, const F_FLOAT& factor_coul, const F_FLOAT& qtmp) const { -/* - - r2inv = 1.0 / rsq; - const int ljt = lj_type[itype][jtype]; - - if (rsq < cut_coulsq) { - if (!ncoultablebits || rsq <= tabinnersq) { - r = sqrt(rsq); - grij = g_ewald * r; - expm2 = exp(-grij * grij); - t = 1.0 / (1.0 + EWALD_P * grij); - erfc = t * (A1 + t * (A2 + t * (A3 + t * (A4 + t * A5)))) * expm2; - prefactor = qqrd2e * qtmp * q[j] / r; - forcecoul = prefactor * (erfc + EWALD_F * grij * expm2); - if (EFLAG) ecoul = prefactor * erfc; - if (factor_coul < 1.0) { - forcecoul -= (1.0 - factor_coul) * prefactor; - if (EFLAG) ecoul -= (1.0 - factor_coul) * prefactor; - } - } else { - union_int_float_t rsq_lookup; - rsq_lookup.f = rsq; - itable = rsq_lookup.i & ncoulmask; - itable >>= ncoulshiftbits; - fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; - table = ftable[itable] + fraction * dftable[itable]; - forcecoul = qtmp * q[j] * table; - if (EFLAG) ecoul = qtmp * q[j] * (etable[itable] + fraction * detable[itable]); - if (factor_coul < 1.0) { - table = ctable[itable] + fraction * dctable[itable]; - prefactor = qtmp * q[j] * table; - forcecoul -= (1.0 - factor_coul) * prefactor; - if (EFLAG) ecoul -= (1.0 - factor_coul) * prefactor; - } - } - } -*/ - if (Specialisation::DoTable && rsq > tabinnersq) { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; diff --git a/src/KOKKOS/pair_lj_spica_kokkos.cpp b/src/KOKKOS/pair_lj_spica_kokkos.cpp index a6a31b31a2..70376d1f63 100644 --- a/src/KOKKOS/pair_lj_spica_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_kokkos.cpp @@ -147,30 +147,6 @@ compute_fpair(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, c const F_FLOAT lj_1 = (STACKPARAMS?m_params[itype][jtype].lj1:params(itype,jtype).lj1); const F_FLOAT lj_2 = (STACKPARAMS?m_params[itype][jtype].lj2:params(itype,jtype).lj2); - /*if (ljt == LJ12_4) { - - const F_FLOAT r4inv=r2inv*r2inv; - return r4inv*(lj_1*r4inv*r4inv - lj_2) * r2inv; - - } else if (ljt == LJ9_6) { - - const F_FLOAT r3inv = r2inv*sqrt(r2inv); - const F_FLOAT r6inv = r3inv*r3inv; - return r6inv*(lj_1*r3inv - lj_2) * r2inv; - - } else if (ljt == LJ12_6) { - - const double r6inv = r2inv*r2inv*r2inv; - return r6inv*(lj_1*r6inv - lj_2) * r2inv; - - } else if (ljt == LJ12_5) { - - const F_FLOAT r5inv = r2inv*r2inv*sqrt(r2inv); - const F_FLOAT r7inv = r5inv*r2inv; - return r5inv*(lj_1*r7inv - lj_2) * r2inv; - - } - if (ljt!=LJ12_4 && ljt!=LJ9_6 && ljt!=LJ12_6 && ljt!=LJ12_5) return 0.0;*/ const F_FLOAT r4inv=r2inv*r2inv; const F_FLOAT r6inv=r2inv*r4inv; const F_FLOAT a = ljt==LJ12_4?r4inv:(ljt==LJ12_5?r4inv*sqrt(r2inv):r6inv); @@ -194,18 +170,14 @@ compute_evdwl(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, c if (ljt == LJ12_4) { const F_FLOAT r4inv=r2inv*r2inv; - return r4inv*(lj_3*r4inv*r4inv - lj_4) - offset; - } else if (ljt == LJ9_6) { const F_FLOAT r3inv = r2inv*sqrt(r2inv); const F_FLOAT r6inv = r3inv*r3inv; return r6inv*(lj_3*r3inv - lj_4) - offset; - } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; return r6inv*(lj_3*r6inv - lj_4) - offset; - } else if (ljt == LJ12_5) { const F_FLOAT r5inv = r2inv*r2inv*sqrt(r2inv); const F_FLOAT r7inv = r5inv*r2inv; From bf4aab68d353cd7bd54c0baa8f900aa87b584ad6 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Mon, 24 Jun 2024 17:45:53 -0400 Subject: [PATCH 120/385] update sdk -> spica --- examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular b/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular index e64882aaa0..2f80847fe0 100644 --- a/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular +++ b/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular @@ -5,9 +5,9 @@ dimension 3 atom_style full processors * * 1 -pair_style lj/sdk/coul/long 15.0 # compatible with "lj/spica/coul/long" +pair_style lj/spica/coul/long 15.0 bond_style harmonic -angle_style sdk # compatible with "spica" +angle_style spica special_bonds lj/coul 0.0 0.0 1.0 read_data data.sds.gz From 4bb71195aa8157cbdd49ac80546f0e93318c63f4 Mon Sep 17 00:00:00 2001 From: Ludwig Ahrens-Iwers Date: Wed, 26 Jun 2024 12:08:45 +0200 Subject: [PATCH 121/385] Allow NULL for eta in fix electrode --- doc/src/fix_electrode.rst | 2 +- examples/PACKAGES/electrode/madelung/in.eta_cg | 2 +- examples/PACKAGES/electrode/madelung/in.eta_mix | 2 +- src/ELECTRODE/fix_electrode_conp.cpp | 17 +++++++++-------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/doc/src/fix_electrode.rst b/doc/src/fix_electrode.rst index 3759ff23ca..1a28f88bc1 100644 --- a/doc/src/fix_electrode.rst +++ b/doc/src/fix_electrode.rst @@ -38,7 +38,7 @@ Syntax *electrode/thermo* args = potential eta *temp* values potential = electrode potential charge = electrode charge - eta = reciprocal width of electrode charge smearing + eta = reciprocal width of electrode charge smearing (can be NULL if eta keyword is used) *temp* values = T_v tau_v rng_v T_v = temperature of thermo-potentiostat tau_v = time constant of thermo-potentiostat diff --git a/examples/PACKAGES/electrode/madelung/in.eta_cg b/examples/PACKAGES/electrode/madelung/in.eta_cg index 5ac8cddf17..c36f56bd82 100644 --- a/examples/PACKAGES/electrode/madelung/in.eta_cg +++ b/examples/PACKAGES/electrode/madelung/in.eta_cg @@ -8,7 +8,7 @@ thermo_style custom step pe c_qbot c_qtop fix feta all property/atom d_eta ghost on set group bot d_eta 0.5 set group top d_eta 3.0 -fix conp bot electrode/conp 0 2 couple top 1 symm on eta d_eta algo cg 1e-6 +fix conp bot electrode/conp 0 NULL couple top 1 symm on eta d_eta algo cg 1e-6 run 0 diff --git a/examples/PACKAGES/electrode/madelung/in.eta_mix b/examples/PACKAGES/electrode/madelung/in.eta_mix index d00e008fa4..3176dddcf8 100644 --- a/examples/PACKAGES/electrode/madelung/in.eta_mix +++ b/examples/PACKAGES/electrode/madelung/in.eta_mix @@ -8,7 +8,7 @@ thermo_style custom step pe c_qbot c_qtop fix feta all property/atom d_eta ghost on set group bot d_eta 0.5 set group top d_eta 3.0 -fix conp bot electrode/conp 0 2 couple top 1 symm on eta d_eta write_inv inv.csv write_vec vec.csv +fix conp bot electrode/conp 0 NULL couple top 1 symm on eta d_eta write_inv inv.csv write_vec vec.csv run 0 diff --git a/src/ELECTRODE/fix_electrode_conp.cpp b/src/ELECTRODE/fix_electrode_conp.cpp index 14cc8fb119..a4b9d5b3b9 100644 --- a/src/ELECTRODE/fix_electrode_conp.cpp +++ b/src/ELECTRODE/fix_electrode_conp.cpp @@ -126,7 +126,8 @@ FixElectrodeConp::FixElectrodeConp(LAMMPS *lmp, int narg, char **arg) : } else group_psi_const[0] = utils::numeric(FLERR, arg[3], false, lmp); char *eta_str = arg[4]; - eta = utils::numeric(FLERR, eta_str, false, lmp); + bool etanull = (strcmp(eta_str, "NULL") == 0); + if (!etanull) eta = utils::numeric(FLERR, eta_str, false, lmp); int iarg = 5; while (iarg < narg) { if ((strcmp(arg[iarg], "couple") == 0)) { @@ -217,7 +218,7 @@ FixElectrodeConp::FixElectrodeConp(LAMMPS *lmp, int narg, char **arg) : qtotal_var_style = VarStyle::CONST; } } else if ((strcmp(arg[iarg], "eta") == 0)) { - if (iarg + 2 > narg) error->all(FLERR, "Need two arguments after eta command"); + if (iarg + 2 > narg) error->all(FLERR, "Need one argument after eta command"); etaflag = true; int is_double, cols, ghost; eta_index = atom->find_custom_ghost(arg[++iarg] + 2, is_double, cols, ghost); @@ -243,6 +244,7 @@ FixElectrodeConp::FixElectrodeConp(LAMMPS *lmp, int narg, char **arg) : if (qtotal_var_style != VarStyle::UNSET) { if (symm) error->all(FLERR, "{} cannot use qtotal keyword with symm on", this->style); } + if (etanull && !etaflag) error->all(FLERR, "If eta is NULL the eta keyword must be used"); // computatonal potential group_psi = std::vector(groups.size()); @@ -430,12 +432,11 @@ void FixElectrodeConp::init() } if (comm->me == 0) for (char *fix_id : integrate_ids) - error->warning( - FLERR, - "Electrode atoms are integrated by fix {}, but fix electrode is using a matrix method. " - "For " - "mobile electrodes use the conjugate gradient algorithm without matrix ('algo cg').", - fix_id); + error->warning(FLERR, + "Electrode atoms are integrated by fix {}, but fix electrode is using a " + "matrix method. For mobile electrodes use the conjugate gradient algorithm " + "without matrix ('algo cg').", + fix_id); } // check for package intel From cdb4a331a62a5a3cd8ab4e2717228d7f232ecdbb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 27 Jun 2024 06:27:25 -0400 Subject: [PATCH 122/385] remove INTEL package from cross-compiler config. It doesn't do much goos since we're not using an Intel compiler and we are running out of capacity for auto-exported symbols for the LAMMPS shared library (limited to 65k). --- cmake/presets/mingw-cross.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/presets/mingw-cross.cmake b/cmake/presets/mingw-cross.cmake index 5f40c487e8..100ce13632 100644 --- a/cmake/presets/mingw-cross.cmake +++ b/cmake/presets/mingw-cross.cmake @@ -33,7 +33,6 @@ set(WIN_PACKAGES FEP GPU GRANULAR - INTEL INTERLAYER KSPACE LEPTON From 3c0eaf6870d59e72a81191f50a7198b160af45be Mon Sep 17 00:00:00 2001 From: jtclemm Date: Thu, 27 Jun 2024 16:57:53 -0600 Subject: [PATCH 123/385] Moving stress calculation to rheo/prop/atom --- doc/src/compute_rheo_property_atom.rst | 53 +++--- src/RHEO/compute_rheo_property_atom.cpp | 221 +++++++++++++++++------- src/RHEO/compute_rheo_property_atom.h | 8 +- src/RHEO/pair_rheo.cpp | 19 +- src/bond_hybrid.cpp | 2 +- src/pair.cpp | 102 ----------- src/pair.h | 2 - 7 files changed, 202 insertions(+), 205 deletions(-) diff --git a/doc/src/compute_rheo_property_atom.rst b/doc/src/compute_rheo_property_atom.rst index a7e1bff383..861fd04688 100644 --- a/doc/src/compute_rheo_property_atom.rst +++ b/doc/src/compute_rheo_property_atom.rst @@ -17,13 +17,11 @@ Syntax .. parsed-literal:: possible attributes = phase, surface, surface/r, - surface/divr, surface/n/x, surface/n/y, - surface/n/z, coordination, cv, shift/v/x, - shift/v/y, shift/v/z, energy, temperature, heatflow, - conductivity, cv, viscosity, pressure, - rho, grad/v/xx, grad/v/xy, grad/v/xz, - grad/v/yx, grad/v/yy/, grad/v/yz, grad/v/zx, - grad/v/zy, grad/v/zz + surface/divr, surface/n/:math:`\alpha`, coordination, + shift/v/:math:`\alpha`, energy, temperature, heatflow, + conductivity, cv, viscosity, pressure, rho, + grad/v/:math:`\alpha \beta`, stress/v/:math:`\alpha \beta`, + stress/t/:math:`\alpha \beta`, nbond/shell .. parsed-literal:: @@ -31,9 +29,9 @@ Syntax *surface* = atom surface status *surface/r* = atom distance from the surface *surface/divr* = divergence of position at atom position - *surface/n/\** = surface normal vector + *surface/n/:math:`\alpha`* = surface normal vector *coordination* = coordination number - *shift/v/\** = atom shifting velocity + *shift/v/:math:`\alpha`* = atom shifting velocity *energy* = atom energy *temperature* = atom temperature *heatflow* = atom heat flow @@ -42,7 +40,9 @@ Syntax *viscosity* = atom viscosity *pressure* = atom pressure *rho* = atom density - *grad/v/\** = atom velocity gradient + *grad/v/:math:`\alpha \beta`* = atom velocity gradient + *stress/v/:math:`\alpha \beta`* = atom viscous stress + *stress/t/:math:`\alpha \beta`* = atom total stress (pressure and viscous) *nbond/shell* = number of oxide bonds Examples @@ -50,8 +50,8 @@ Examples .. code-block:: LAMMPS - compute 1 all rheo/property/atom phase surface/r pressure - compute 2 all rheo/property/atom shift/v/x grad/v/xx + compute 1 all rheo/property/atom phase surface/r surface/n/* pressure + compute 2 all rheo/property/atom shift/v/x grad/v/xx stress/v/* Description """"""""""" @@ -68,6 +68,17 @@ computes as inputs. See for example, the :doc:`fix ave/chunk `, and :doc:`atom-style variable ` commands. +For vector attributes, e.g. *shift/v/:math:`\alpha`*, one must specify +:math:`\alpha` as the *x*, *y*, or *z* component, e.g. *shift/v/x*. +Alternatively, a wild card \* will include all components, *x* and *y* in +2D or *x*, *y*, and *z* in 3D. + +For tensor attributes, e.g. *grad/v/:math:`\alpha \beta`*, one must specify +both :math:`\alpha` and :math:`\beta` as *x*, *y*, or *z*, e.g. *grad/v/xy*. +Alternatively, a wild card \* will include all components. In 2D, this +includes *xx*, *xy*, *yx*, and *yy*. In 3D, this includes *xx*, *xy*, *xz*, +*yx*, *yy*, *yz*, *zx*, *zy*, and *zz*. + Many properties require their respective fixes, listed below in related commands, be defined. For instance, the *viscosity* attribute is the viscosity of a particle calculated by @@ -85,19 +96,12 @@ distance from the surface, up to the kernel cutoff length. Surface particles have a value of 0. The *surface/n* properties are the components of the surface normal vector. -The *shift/v* properties are the components of the shifting velocity +The *shift/v/:math:`\alpha`* properties are the components of the shifting velocity produced by the *shift* option of :doc:`fix rheo `. -The *surface/n/\** and *shift/v/\** attributes are vectors that require -specification of the *x*, *y*, or *z* component, e.g. *surface/n/x*. - The *nbond/shell* property is the number of shell bonds that have been activated from :doc:`bond style rheo/shell `. -The *grad/v/\** attribute is a tensor and requires specification of -the *xx*, *yy*, *zz*, *xy*, *xz*, *yx*, *yz*, *zx*, or *zy* component, -e.g. *grad/v/xy*. - The values are stored in a per-atom vector or array as discussed below. Zeroes are stored for atoms not in the specified group or for quantities that are not defined for a particular particle in the group @@ -109,9 +113,12 @@ This compute calculates a per-atom vector or per-atom array depending on the number of input values. If a single input is specified, a per-atom vector is produced. If two or more inputs are specified, a per-atom array is produced where the number of columns = the number of -inputs. The vector or array can be accessed by any command that uses -per-atom values from a compute as input. See the :doc:`Howto output -` page for an overview of LAMMPS output options. +inputs. If a wild card \* is used for a vector or tensor, then the number +of inputs is considered to be incremented by the dimensiod or dimension +squared, respectively. The vector or array can be accessed by any command +that uses per-atom values from a compute as input. See the +:doc:`Howto output ` page for an overview of LAMMPS output +options. The vector or array values will be in whatever :doc:`units ` the corresponding attribute is in (e.g., density units for *rho*). diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index d6d8c2a07a..533822bbdd 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -53,7 +53,26 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (narg < 4) utils::missing_cmd_args(FLERR, "compute property/atom", error); peratom_flag = 1; - nvalues = narg - 3; + int dim = domain->dimension; + + // Determine number of values + nvalues = 0; + for (int iarg = 3; iarg < narg; iarg++) { + if (strcmp(arg[iarg], "surface/n/*") == 0) { + nvalues += dim; + } else if (strcmp(arg[iarg], "shift/v/*") == 0) { + nvalues += dim; + } else if (strcmp(arg[iarg], "grad/v/*") == 0) { + nvalues += dim * dim; + } else if (strcmp(arg[iarg], "stress/v/*") == 0) { + nvalues += dim * dim; + } else if (strcmp(arg[iarg], "stress/t/*") == 0) { + nvalues += dim * dim; + } else { + nvalues += 1; + } + } + if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; @@ -66,11 +85,11 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a pack_choice = new FnPtrPack[nvalues]; avec_index = new int[nvalues]; col_index = new int[nvalues]; + col_t_index = new int[nvalues]; - int i; + int i = 0; + int index, a, b; for (int iarg = 3; iarg < narg; iarg++) { - i = iarg-3; - if (strcmp(arg[iarg], "phase") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_phase; } else if (strcmp(arg[iarg], "rho") == 0) { @@ -87,10 +106,6 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a } else if (strcmp(arg[iarg], "surface/divr") == 0) { surface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_divr; - } else if (utils::strmatch(arg[iarg], "^surface/n")) { - surface_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_surface_n; - col_index[i] = get_vector_index(arg[iarg]); } else if (strcmp(arg[iarg], "coordination") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_coordination; } else if (strcmp(arg[iarg], "pressure") == 0) { @@ -101,13 +116,18 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a } else if (strcmp(arg[iarg], "cv") == 0) { thermal_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; - } else if (utils::strmatch(arg[iarg], "^shift/v")) { + } else if (utils::strmatch(arg[iarg], "^surface/n/")) { + surface_flag = 1; + i += add_vector_component(arg[iarg], i, &ComputeRHEOPropertyAtom::pack_surface_n) - 1; + } else if (utils::strmatch(arg[iarg], "^shift/v/")) { shift_flag = 1; - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_shift_v; - col_index[i] = get_vector_index(arg[iarg]); - } else if (utils::strmatch(arg[iarg], "^grad/v")) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_gradv; - col_index[i] = get_tensor_index(arg[iarg]); + i += add_vector_component(arg[iarg], i, &ComputeRHEOPropertyAtom::pack_shift_v) - 1; + } else if (utils::strmatch(arg[iarg], "^grad/v/")) { + i += add_tensor_component(arg[iarg], i, &ComputeRHEOPropertyAtom::pack_gradv) - 1; + } else if (utils::strmatch(arg[iarg], "^stress/v/")) { + i += add_tensor_component(arg[iarg], i, &ComputeRHEOPropertyAtom::pack_viscous_stress) - 1; + } else if (utils::strmatch(arg[iarg], "^stress/t/")) { + i += add_tensor_component(arg[iarg], i, &ComputeRHEOPropertyAtom::pack_total_stress) - 1; } else if (strcmp(arg[iarg], "energy") == 0) { avec_index[i] = atom->avec->property_atom("esph"); if (avec_index[i] < 0) @@ -131,6 +151,7 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a if (strcmp(arg[iarg], "heatflow") == 0) thermal_flag = 1; if (strcmp(arg[iarg], "conductivity") == 0) thermal_flag = 1; } + i++; } nmax = 0; @@ -143,6 +164,7 @@ ComputeRHEOPropertyAtom::~ComputeRHEOPropertyAtom() delete[] pack_choice; delete[] avec_index; delete[] col_index; + delete[] col_t_index; memory->destroy(vector_atom); memory->destroy(array_atom); } @@ -413,6 +435,56 @@ void ComputeRHEOPropertyAtom::pack_viscosity(int n) /* ---------------------------------------------------------------------- */ +void ComputeRHEOPropertyAtom::pack_viscous_stress(int n) +{ + double **gradv = compute_grad->gradv; + double *viscosity = atom->viscosity; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int index = col_index[n]; + int dim = domain->dimension; + int a = index / dim; + int b = index % dim; + int index_transpose = b * dim + a; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = viscosity[i] * (gradv[i][index] + gradv[i][index_transpose]); + else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeRHEOPropertyAtom::pack_total_stress(int n) +{ + double **gradv = compute_grad->gradv; + double *viscosity = atom->viscosity; + double *rho = atom->rho; + int *type = atom->type; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int index = col_index[n]; + int dim = domain->dimension; + int a = index / dim; + int b = index % dim; + int index_transpose = b * dim + a; + double p; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) { + if (index == index_transpose) + p = fix_pressure->calc_pressure(rho[i], type[i]); + else + p = 0.0; + buf[n] = viscosity[i] * (gradv[i][index] + gradv[i][index_transpose]) + p; + } else buf[n] = 0.0; + n += nvalues; + } +} + +/* ---------------------------------------------------------------------- */ + void ComputeRHEOPropertyAtom::pack_nbond_shell(int n) { int *nbond = fix_oxidation->nbond; @@ -467,63 +539,92 @@ void ComputeRHEOPropertyAtom::pack_atom_style(int n) /* ---------------------------------------------------------------------- */ -int ComputeRHEOPropertyAtom::get_tensor_index(char* option) +int ComputeRHEOPropertyAtom::add_tensor_component(char* option, int i, FnPtrPack pack_function) { - int index; + int shift; int dim = domain->dimension; - int dim_error = 0; - - if (utils::strmatch(option, "xx$")) { - index = 0; - } else if (utils::strmatch(option, "xy$")) { - index = 1; - } else if (utils::strmatch(option, "xz$")) { - index = 2; - if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option, "yx$")) { - if (dim == 2) index = 2; - else index = 3; - } else if (utils::strmatch(option, "yy$")) { - if (dim == 2) index = 3; - else index = 4; - } else if (utils::strmatch(option, "yz$")) { - index = 5; - if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option, "zx$")) { - index = 6; - if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option, "zy$")) { - index = 7; - if (dim == 2) dim_error = 1; - } else if (utils::strmatch(option, "zz$")) { - index = 8; - if (dim == 2) dim_error = 1; + if (((std::string) option).back() == '*') { + for (int a = 0; a < dim; a++) { + for (int b = 0; b < dim; b++) { + pack_choice[i + a * dim + b] = pack_function; + col_index[i + a * dim + b] = a * dim + b; + } + } + shift = dim * dim; } else { - error->all(FLERR, "Invalid compute rheo/property/atom property {}", option); + int index; + int dim_error = 0; + + if (utils::strmatch(option, "xx$")) { + index = 0; + } else if (utils::strmatch(option, "xy$")) { + index = 1; + } else if (utils::strmatch(option, "xz$")) { + index = 2; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option, "yx$")) { + if (dim == 2) index = 2; + else index = 3; + } else if (utils::strmatch(option, "yy$")) { + if (dim == 2) index = 3; + else index = 4; + } else if (utils::strmatch(option, "yz$")) { + index = 5; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option, "zx$")) { + index = 6; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option, "zy$")) { + index = 7; + if (dim == 2) dim_error = 1; + } else if (utils::strmatch(option, "zz$")) { + index = 8; + if (dim == 2) dim_error = 1; + } else { + error->all(FLERR, "Invalid compute rheo/property/atom property {}", option); + } + + if (dim_error) + error->all(FLERR, "Invalid compute rheo/property/atom property {} in 2D", option); + + pack_choice[i] = pack_function; + col_index[i] = index; + shift = 1; } - if (dim_error) - error->all(FLERR, "Invalid compute rheo/property/atom property {} in 2D", option); - - return index; + return shift; } /* ---------------------------------------------------------------------- */ -int ComputeRHEOPropertyAtom::get_vector_index(char* option) +int ComputeRHEOPropertyAtom::add_vector_component(char* option, int i, FnPtrPack pack_function) { - int index; - if (utils::strmatch(option, "x$")) { - index = 0; - } else if (utils::strmatch(option, "y$")) { - index = 1; - } else if (utils::strmatch(option, "z$")) { - if (domain->dimension == 2) - error->all(FLERR, "Invalid compute rheo/property/atom property {} in 2D", option); - index = 2; + int shift; + int dim = domain->dimension; + if (((std::string) option).back() == '*') { + for (int a = 0; a < dim; a++) { + pack_choice[i + a] = pack_function; + col_index[i + a] = a; + } + shift = dim; } else { - error->all(FLERR, "Invalid compute rheo/property/atom property {}", option); + int index; + if (utils::strmatch(option, "x$")) { + index = 0; + } else if (utils::strmatch(option, "y$")) { + index = 1; + } else if (utils::strmatch(option, "z$")) { + if (dim == 2) + error->all(FLERR, "Invalid compute rheo/property/atom property {} in 2D", option); + index = 2; + } else { + error->all(FLERR, "Invalid compute rheo/property/atom property {}", option); + } + + pack_choice[i] = pack_function; + col_index[i] = index; + shift = 1; } - return index; + return shift; } diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index a61455f0c5..b3d247b102 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -38,7 +38,7 @@ class ComputeRHEOPropertyAtom : public Compute { int pressure_flag, thermal_flag, interface_flag; int surface_flag, shift_flag, shell_flag; int *avec_index; - int *col_index; + int *col_index, *col_t_index; double *buf; typedef void (ComputeRHEOPropertyAtom::*FnPtrPack)(int); @@ -57,11 +57,13 @@ class ComputeRHEOPropertyAtom : public Compute { void pack_gradv(int); void pack_pressure(int); void pack_viscosity(int); + void pack_viscous_stress(int); + void pack_total_stress(int); void pack_nbond_shell(int); void pack_atom_style(int); - int get_vector_index(char*); - int get_tensor_index(char*); + int add_vector_component(char*, int, FnPtrPack); + int add_tensor_component(char*, int, FnPtrPack); class FixRHEO *fix_rheo; class FixRHEOPressure *fix_pressure; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 0a52bd53bc..f206512950 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -306,13 +306,9 @@ void PairRHEO::compute(int eflag, int vflag) f[i][1] += ft[1]; f[i][2] += ft[2]; - if (evflag) { - fnorm = dot3(ft, dx) * rinv * rinv * 0.5; - ftang[0] = ft[0] * 0.5 - dx[0] * fnorm; - ftang[1] = ft[1] * 0.5 - dx[1] * fnorm; - ftang[2] = ft[2] * 0.5 - dx[2] * fnorm; - ev_tally_nt(i, j, nlocal, newton_pair, 0.0, 0.0, fnorm, ftang[0], ftang[1], ftang[2], dx[0], dx[1], dx[2]); - } + // Note the virial's definition is hazy, e.g. viscous contributions will depend on rotation + if (evflag) + ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], dx[0], dx[1], dx[2]); if (newton_pair || j < nlocal) { for (a = 0; a < dim; a ++) { @@ -331,13 +327,8 @@ void PairRHEO::compute(int eflag, int vflag) f[j][1] -= ft[1]; f[j][2] -= ft[2]; - if (evflag) { - fnorm = - dot3(ft, dx) * rinv * rinv * 0.5; - ftang[0] = ft[0] * 0.5 + dx[0] * fnorm; - ftang[1] = ft[1] * 0.5 + dx[1] * fnorm; - ftang[2] = ft[2] * 0.5 + dx[2] * fnorm; - ev_tally_nt(i, j, nlocal, newton_pair, 0.0, 0.0, fnorm, ftang[0], ftang[1], ftang[2], -dx[0], -dx[1], -dx[2]); - } + if (evflag) + ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, ft[0], ft[1], ft[2], -dx[0], -dx[1], -dx[2]); } if (compute_interface) { diff --git a/src/bond_hybrid.cpp b/src/bond_hybrid.cpp index 555ded4469..1e3e3c66f9 100644 --- a/src/bond_hybrid.cpp +++ b/src/bond_hybrid.cpp @@ -195,7 +195,7 @@ void BondHybrid::deallocate() delete[] maxbond; for (int i = 0; i < nstyles; i++) memory->destroy(bondlist[i]); delete[] bondlist; - for (i = 0; i < nstyles; i++) memory->destroy(orig_map[i]); + for (int i = 0; i < nstyles; i++) memory->destroy(orig_map[i]); delete[] orig_map; } diff --git a/src/pair.cpp b/src/pair.cpp index 896cfda29d..34c8e4978e 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -1247,108 +1247,6 @@ void Pair::ev_tally_xyz(int i, int j, int nlocal, int newton_pair, } } - -/* ---------------------------------------------------------------------- - tally eng_vdwl and virial into global or per-atom accumulators - for virial, have delx,dely,delz and fnormal and ftangential -------------------------------------------------------------------------- */ - -void Pair::ev_tally_nt(int i, int j, int nlocal, int newton_pair, - double evdwl, double ecoul, double fn, - double ftx, double fty, double ftz, - double delx, double dely, double delz) -{ - double evdwlhalf,ecoulhalf,epairhalf,v[6]; - - if (eflag_either) { - if (eflag_global) { - if (newton_pair) { - eng_vdwl += evdwl; - eng_coul += ecoul; - } else { - evdwlhalf = 0.5*evdwl; - ecoulhalf = 0.5*ecoul; - if (i < nlocal) { - eng_vdwl += evdwlhalf; - eng_coul += ecoulhalf; - } - if (j < nlocal) { - eng_vdwl += evdwlhalf; - eng_coul += ecoulhalf; - } - } - } - if (eflag_atom) { - epairhalf = 0.5 * (evdwl + ecoul); - if (newton_pair || i < nlocal) eatom[i] += epairhalf; - if (newton_pair || j < nlocal) eatom[j] += epairhalf; - } - } - - if (vflag_either) { - v[0] = delx*delx*fn; - v[1] = dely*dely*fn; - v[2] = delz*delz*fn; - v[3] = delx*dely*fn; - v[4] = delx*delz*fn; - v[5] = dely*delz*fn; - - v[0] += delx*ftx; - v[1] += dely*fty; - v[2] += delz*ftz; - v[3] += delx*fty + dely*ftx; - v[4] += delx*ftz + delz*ftx; - v[5] += dely*ftz + delz*fty; - - if (vflag_global) { - if (newton_pair) { - virial[0] += v[0]; - virial[1] += v[1]; - virial[2] += v[2]; - virial[3] += v[3]; - virial[4] += v[4]; - virial[5] += v[5]; - } else { - if (i < nlocal) { - virial[0] += 0.5*v[0]; - virial[1] += 0.5*v[1]; - virial[2] += 0.5*v[2]; - virial[3] += 0.5*v[3]; - virial[4] += 0.5*v[4]; - virial[5] += 0.5*v[5]; - } - if (j < nlocal) { - virial[0] += 0.5*v[0]; - virial[1] += 0.5*v[1]; - virial[2] += 0.5*v[2]; - virial[3] += 0.5*v[3]; - virial[4] += 0.5*v[4]; - virial[5] += 0.5*v[5]; - } - } - } - - if (vflag_atom) { - if (newton_pair || i < nlocal) { - vatom[i][0] += 0.5*v[0]; - vatom[i][1] += 0.5*v[1]; - vatom[i][2] += 0.5*v[2]; - vatom[i][3] += 0.5*v[3]; - vatom[i][4] += 0.5*v[4]; - vatom[i][5] += 0.5*v[5]; - } - if (newton_pair || j < nlocal) { - vatom[j][0] += 0.5*v[0]; - vatom[j][1] += 0.5*v[1]; - vatom[j][2] += 0.5*v[2]; - vatom[j][3] += 0.5*v[3]; - vatom[j][4] += 0.5*v[4]; - vatom[j][5] += 0.5*v[5]; - } - } - } -} - /* ---------------------------------------------------------------------- tally eng_vdwl and virial into global or per-atom accumulators for virial, have delx,dely,delz and fx,fy,fz diff --git a/src/pair.h b/src/pair.h index 153250260a..d36b48f340 100644 --- a/src/pair.h +++ b/src/pair.h @@ -297,8 +297,6 @@ class Pair : protected Pointers { void ev_tally_tip4p(int, int *, double *, double, double); void ev_tally_xyz(int, int, int, int, double, double, double, double, double, double, double, double); - void ev_tally_nt(int, int, int, int, double, double, double, double, double, double, double, - double, double); void v_tally2(int, int, double, double *); void v_tally_tensor(int, int, int, int, double, double, double, double, double, double); void virial_fdotr_compute(); From 0de8192a9b92c52908d6022db07b42a8b2946cab Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Thu, 27 Jun 2024 22:31:59 -0600 Subject: [PATCH 124/385] add kokkosable variable --- src/angle.cpp | 2 +- src/angle.h | 2 +- src/dihedral.cpp | 2 +- src/dihedral.h | 2 +- src/improper.cpp | 2 +- src/improper.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/angle.cpp b/src/angle.cpp index 79893cc52f..ccb53dc84f 100644 --- a/src/angle.cpp +++ b/src/angle.cpp @@ -50,7 +50,7 @@ Angle::Angle(LAMMPS *_lmp) : Pointers(_lmp) datamask_read = ALL_MASK; datamask_modify = ALL_MASK; - copymode = 0; + copymode = kokkosable = 0; } /* ---------------------------------------------------------------------- */ diff --git a/src/angle.h b/src/angle.h index 542bad4911..759f1a1aa9 100644 --- a/src/angle.h +++ b/src/angle.h @@ -44,7 +44,7 @@ class Angle : protected Pointers { ExecutionSpace execution_space; unsigned int datamask_read, datamask_modify; - int copymode; + int copymode, kokkosable; Angle(class LAMMPS *); ~Angle() override; diff --git a/src/dihedral.cpp b/src/dihedral.cpp index 3e995fc405..2f591b1fc1 100644 --- a/src/dihedral.cpp +++ b/src/dihedral.cpp @@ -48,7 +48,7 @@ Dihedral::Dihedral(LAMMPS *_lmp) : Pointers(_lmp) datamask_read = ALL_MASK; datamask_modify = ALL_MASK; - copymode = 0; + copymode = kokkosable = 0; } /* ---------------------------------------------------------------------- */ diff --git a/src/dihedral.h b/src/dihedral.h index cf3d3f7d9a..34210929cd 100644 --- a/src/dihedral.h +++ b/src/dihedral.h @@ -41,7 +41,7 @@ class Dihedral : protected Pointers { ExecutionSpace execution_space; unsigned int datamask_read, datamask_modify; - int copymode; + int copymode, kokkosable; Dihedral(class LAMMPS *); ~Dihedral() override; diff --git a/src/improper.cpp b/src/improper.cpp index dd4b1b2b25..3476bcdb50 100644 --- a/src/improper.cpp +++ b/src/improper.cpp @@ -47,7 +47,7 @@ Improper::Improper(LAMMPS *_lmp) : Pointers(_lmp) datamask_read = ALL_MASK; datamask_modify = ALL_MASK; - copymode = 0; + copymode = kokkosable = 0; } /* ---------------------------------------------------------------------- */ diff --git a/src/improper.h b/src/improper.h index 22a5d09926..400e950967 100644 --- a/src/improper.h +++ b/src/improper.h @@ -46,7 +46,7 @@ class Improper : protected Pointers { ExecutionSpace execution_space; unsigned int datamask_read, datamask_modify; - int copymode; + int copymode, kokkosable; Improper(class LAMMPS *); ~Improper() override; From 9fef3b68e02c86ecf6a489d9fef19155e2be05ae Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Thu, 27 Jun 2024 22:36:15 -0600 Subject: [PATCH 125/385] update deallocate, suffix flags --- src/angle_hybrid.cpp | 37 +++++++++++++++++++------------------ src/angle_hybrid.h | 6 +++--- src/dihedral_hybrid.cpp | 35 +++++++++++++++++------------------ src/dihedral_hybrid.h | 5 +++-- src/improper_hybrid.cpp | 37 +++++++++++++++++++------------------ src/improper_hybrid.h | 5 +++-- 6 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/angle_hybrid.cpp b/src/angle_hybrid.cpp index 0c61970a1f..a015882a15 100644 --- a/src/angle_hybrid.cpp +++ b/src/angle_hybrid.cpp @@ -48,14 +48,7 @@ AngleHybrid::~AngleHybrid() delete[] keywords; } - if (allocated) { - memory->destroy(setflag); - memory->destroy(map); - delete[] nanglelist; - delete[] maxangle; - for (int i = 0; i < nstyles; i++) memory->destroy(anglelist[i]); - delete[] anglelist; - } + deallocate(); } /* ---------------------------------------------------------------------- */ @@ -171,6 +164,22 @@ void AngleHybrid::allocate() for (int m = 0; m < nstyles; m++) anglelist[m] = nullptr; } +/* ---------------------------------------------------------------------- */ + +void AngleHybrid::deallocate() +{ + if (!allocated) return; + + allocated = 0; + + memory->destroy(setflag); + memory->destroy(map); + delete[] nanglelist; + delete[] maxangle; + for (int i = 0; i < nstyles; i++) memory->destroy(anglelist[i]); + delete[] anglelist; +} + /* ---------------------------------------------------------------------- create one angle style for each arg in list ------------------------------------------------------------------------- */ @@ -190,15 +199,7 @@ void AngleHybrid::settings(int narg, char **arg) delete[] keywords; } - if (allocated) { - memory->destroy(setflag); - memory->destroy(map); - delete[] nanglelist; - delete[] maxangle; - for (i = 0; i < nstyles; i++) memory->destroy(anglelist[i]); - delete[] anglelist; - } - allocated = 0; + deallocate(); // allocate list of sub-styles @@ -367,7 +368,7 @@ void AngleHybrid::read_restart(FILE *fp) keywords[m] = new char[n]; if (me == 0) utils::sfread(FLERR, keywords[m], sizeof(char), n, fp, nullptr, error); MPI_Bcast(keywords[m], n, MPI_CHAR, 0, world); - styles[m] = force->new_angle(keywords[m], 0, dummy); + styles[m] = force->new_angle(keywords[m], 1, dummy); styles[m]->read_restart_settings(fp); } } diff --git a/src/angle_hybrid.h b/src/angle_hybrid.h index 474ce89673..a6da29245e 100644 --- a/src/angle_hybrid.h +++ b/src/angle_hybrid.h @@ -42,14 +42,14 @@ class AngleHybrid : public Angle { double single(int, int, int, int) override; double memory_usage() override; - private: + protected: int *map; // which style each angle type points to - int *nanglelist; // # of angles in sub-style anglelists int *maxangle; // max # of angles sub-style lists can store int ***anglelist; // anglelist for each sub-style - void allocate(); + virtual void allocate(); + virtual void deallocate(); }; } // namespace LAMMPS_NS diff --git a/src/dihedral_hybrid.cpp b/src/dihedral_hybrid.cpp index 4ee0ffdad9..3671391f5d 100644 --- a/src/dihedral_hybrid.cpp +++ b/src/dihedral_hybrid.cpp @@ -48,14 +48,7 @@ DihedralHybrid::~DihedralHybrid() delete[] keywords; } - if (allocated) { - memory->destroy(setflag); - memory->destroy(map); - delete[] ndihedrallist; - delete[] maxdihedral; - for (int i = 0; i < nstyles; i++) memory->destroy(dihedrallist[i]); - delete[] dihedrallist; - } + deallocate(); } /* ---------------------------------------------------------------------- */ @@ -172,6 +165,20 @@ void DihedralHybrid::allocate() for (int m = 0; m < nstyles; m++) dihedrallist[m] = nullptr; } +void DihedralHybrid::deallocate() +{ + if (!allocated) return; + + allocated = 0; + + memory->destroy(setflag); + memory->destroy(map); + delete[] ndihedrallist; + delete[] maxdihedral; + for (int i = 0; i < nstyles; i++) memory->destroy(dihedrallist[i]); + delete[] dihedrallist; +} + /* ---------------------------------------------------------------------- create one dihedral style for each arg in list ------------------------------------------------------------------------- */ @@ -191,15 +198,7 @@ void DihedralHybrid::settings(int narg, char **arg) delete[] keywords; } - if (allocated) { - memory->destroy(setflag); - memory->destroy(map); - delete[] ndihedrallist; - delete[] maxdihedral; - for (i = 0; i < nstyles; i++) memory->destroy(dihedrallist[i]); - delete[] dihedrallist; - } - allocated = 0; + deallocate(); // allocate list of sub-styles @@ -365,7 +364,7 @@ void DihedralHybrid::read_restart(FILE *fp) keywords[m] = new char[n]; if (me == 0) utils::sfread(FLERR, keywords[m], sizeof(char), n, fp, nullptr, error); MPI_Bcast(keywords[m], n, MPI_CHAR, 0, world); - styles[m] = force->new_dihedral(keywords[m], 0, dummy); + styles[m] = force->new_dihedral(keywords[m], 1, dummy); styles[m]->read_restart_settings(fp); } } diff --git a/src/dihedral_hybrid.h b/src/dihedral_hybrid.h index b7d4013afe..debc8a9d8d 100644 --- a/src/dihedral_hybrid.h +++ b/src/dihedral_hybrid.h @@ -40,14 +40,15 @@ class DihedralHybrid : public Dihedral { void read_restart(FILE *) override; double memory_usage() override; - private: + protected: int *map; // which style each dihedral type points to int *ndihedrallist; // # of dihedrals in sub-style dihedrallists int *maxdihedral; // max # of dihedrals sub-style lists can store int ***dihedrallist; // dihedrallist for each sub-style - void allocate(); + virtual void allocate(); + virtual void deallocate(); }; } // namespace LAMMPS_NS diff --git a/src/improper_hybrid.cpp b/src/improper_hybrid.cpp index a847b7bc95..5337f062b4 100644 --- a/src/improper_hybrid.cpp +++ b/src/improper_hybrid.cpp @@ -48,14 +48,7 @@ ImproperHybrid::~ImproperHybrid() delete[] keywords; } - if (allocated) { - memory->destroy(setflag); - memory->destroy(map); - delete[] nimproperlist; - delete[] maximproper; - for (int i = 0; i < nstyles; i++) memory->destroy(improperlist[i]); - delete[] improperlist; - } + deallocate(); } /* ---------------------------------------------------------------------- */ @@ -172,6 +165,22 @@ void ImproperHybrid::allocate() for (int m = 0; m < nstyles; m++) improperlist[m] = nullptr; } +/* ---------------------------------------------------------------------- */ + +void ImproperHybrid::deallocate() +{ + if (!allocated) return; + + allocated = 0; + + memory->destroy(setflag); + memory->destroy(map); + delete[] nimproperlist; + delete[] maximproper; + for (int i = 0; i < nstyles; i++) memory->destroy(improperlist[i]); + delete[] improperlist; +} + /* ---------------------------------------------------------------------- create one improper style for each arg in list ------------------------------------------------------------------------- */ @@ -191,15 +200,7 @@ void ImproperHybrid::settings(int narg, char **arg) delete[] keywords; } - if (allocated) { - memory->destroy(setflag); - memory->destroy(map); - delete[] nimproperlist; - delete[] maximproper; - for (i = 0; i < nstyles; i++) memory->destroy(improperlist[i]); - delete[] improperlist; - } - allocated = 0; + deallocate(); // allocate list of sub-styles @@ -357,7 +358,7 @@ void ImproperHybrid::read_restart(FILE *fp) keywords[m] = new char[n]; if (me == 0) utils::sfread(FLERR, keywords[m], sizeof(char), n, fp, nullptr, error); MPI_Bcast(keywords[m], n, MPI_CHAR, 0, world); - styles[m] = force->new_improper(keywords[m], 0, dummy); + styles[m] = force->new_improper(keywords[m], 1, dummy); styles[m]->read_restart_settings(fp); } } diff --git a/src/improper_hybrid.h b/src/improper_hybrid.h index e7cb8383d4..89a4664da2 100644 --- a/src/improper_hybrid.h +++ b/src/improper_hybrid.h @@ -40,14 +40,15 @@ class ImproperHybrid : public Improper { void read_restart(FILE *) override; double memory_usage() override; - private: + protected: int *map; // which style each improper type points to int *nimproperlist; // # of impropers in sub-style improperlists int *maximproper; // max # of impropers sub-style lists can store int ***improperlist; // improperlist for each sub-style - void allocate(); + virtual void allocate(); + virtual void deallocate(); }; } // namespace LAMMPS_NS From 4fd14f4e1c151687993de7fa6976363c88d931d3 Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Thu, 27 Jun 2024 22:44:25 -0600 Subject: [PATCH 126/385] update install actions --- src/KOKKOS/Install.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index aa920981e2..35a578867b 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -53,6 +53,8 @@ action angle_cosine_kokkos.cpp angle_cosine.cpp action angle_cosine_kokkos.h angle_cosine.h action angle_harmonic_kokkos.cpp angle_harmonic.cpp action angle_harmonic_kokkos.h angle_harmonic.h +action angle_hybrid_kokkos.cpp angle_hybrid.cpp +action angle_hybrid_kokkos.h angle_hybrid.h action atom_kokkos.cpp action atom_kokkos.h action atom_map_kokkos.cpp @@ -116,6 +118,8 @@ action dihedral_harmonic_kokkos.cpp dihedral_harmonic.cpp action dihedral_harmonic_kokkos.h dihedral_harmonic.h action dihedral_opls_kokkos.cpp dihedral_opls.cpp action dihedral_opls_kokkos.h dihedral_opls.h +action dihedral_hybrid_kokkos.cpp dihedral_hybrid.cpp +action dihedral_hybrid_kokkos.h dihedral_hybrid.h action domain_kokkos.cpp action domain_kokkos.h action dynamical_matrix_kokkos.cpp dynamical_matrix.cpp @@ -205,6 +209,8 @@ action improper_class2_kokkos.cpp improper_class2.cpp action improper_class2_kokkos.h improper_class2.h action improper_harmonic_kokkos.cpp improper_harmonic.cpp action improper_harmonic_kokkos.h improper_harmonic.h +action improper_hybrid_kokkos.cpp improper_hybrid.cpp +action improper_hybrid_kokkos.h improper_hybrid.h action kissfft_kokkos.h kissfft.h action kokkos_base_fft.h fft3d.h action kokkos_base.h From 62d564f81a3afdf9ac144f9d8069fbd95c5d06d7 Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Thu, 27 Jun 2024 22:49:03 -0600 Subject: [PATCH 127/385] add hybrid kk for angle, dihedral, improper styles --- src/KOKKOS/angle_hybrid_kokkos.cpp | 215 ++++++++++++++++++++++++++ src/KOKKOS/angle_hybrid_kokkos.h | 58 +++++++ src/KOKKOS/dihedral_hybrid_kokkos.cpp | 215 ++++++++++++++++++++++++++ src/KOKKOS/dihedral_hybrid_kokkos.h | 58 +++++++ src/KOKKOS/improper_hybrid_kokkos.cpp | 215 ++++++++++++++++++++++++++ src/KOKKOS/improper_hybrid_kokkos.h | 58 +++++++ 6 files changed, 819 insertions(+) create mode 100644 src/KOKKOS/angle_hybrid_kokkos.cpp create mode 100644 src/KOKKOS/angle_hybrid_kokkos.h create mode 100644 src/KOKKOS/dihedral_hybrid_kokkos.cpp create mode 100644 src/KOKKOS/dihedral_hybrid_kokkos.h create mode 100644 src/KOKKOS/improper_hybrid_kokkos.cpp create mode 100644 src/KOKKOS/improper_hybrid_kokkos.h diff --git a/src/KOKKOS/angle_hybrid_kokkos.cpp b/src/KOKKOS/angle_hybrid_kokkos.cpp new file mode 100644 index 0000000000..a3ec21a5c5 --- /dev/null +++ b/src/KOKKOS/angle_hybrid_kokkos.cpp @@ -0,0 +1,215 @@ +/* ---------------------------------------------------------------------- + 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 "angle_hybrid_kokkos.h" + +#include "atom_kokkos.h" +#include "atom_masks.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "kokkos.h" +#include "memory_kokkos.h" +#include "neighbor_kokkos.h" + +#include + +using namespace LAMMPS_NS; + +#define EXTRA 1000 + +/* ---------------------------------------------------------------------- */ + +AngleHybridKokkos::AngleHybridKokkos(LAMMPS *lmp) : AngleHybrid(lmp) +{ + kokkosable = 1; + + atomKK = (AtomKokkos *) atom; + neighborKK = (NeighborKokkos *) neighbor; + + execution_space = Device; + + datamask_read = EMPTY_MASK; + datamask_modify = EMPTY_MASK; +} + +/* ---------------------------------------------------------------------- */ + +AngleHybridKokkos::~AngleHybridKokkos() +{ + deallocate(); +} + +/* ---------------------------------------------------------------------- */ + +void AngleHybridKokkos::compute(int eflag, int vflag) +{ + // save ptrs to original anglelist + + int nanglelist_orig = neighbor->nanglelist; + neighborKK->k_anglelist.sync_device(); + auto k_anglelist_orig = neighborKK->k_anglelist; + auto d_anglelist_orig = k_anglelist_orig.d_view; + auto d_nanglelist = k_nanglelist.d_view; + auto h_nanglelist = k_nanglelist.h_view; + + // if this is re-neighbor step, create sub-style anglelists + // nanglelist[] = length of each sub-style list + // realloc sub-style anglelist if necessary + // load sub-style anglelist with 3 values from original anglelist + + if (neighbor->ago == 0) { + Kokkos::deep_copy(d_nanglelist,0); + + k_map.sync_device(); + auto d_map = k_map.d_view; + + Kokkos::parallel_for(nanglelist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_anglelist_orig(i,2)]; + if (m >= 0) Kokkos::atomic_increment(&d_nanglelist[m]); + }); + + k_nanglelist.modify_device(); + k_nanglelist.sync_host(); + + maxangle_all = 0; + for (int m = 0; m < nstyles; m++) + if (h_nanglelist[m] > maxangle_all) + maxangle_all = h_nanglelist[m] + EXTRA; + + if (k_anglelist.d_view.extent(1) < maxangle_all) + MemKK::realloc_kokkos(k_anglelist, "angle_hybrid:anglelist", nstyles, maxangle_all, 3); + auto d_anglelist = k_anglelist.d_view; + + Kokkos::deep_copy(d_nanglelist,0); + + Kokkos::parallel_for(nanglelist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_anglelist_orig(i,2)]; + if (m < 0) return; + const int n = Kokkos::atomic_fetch_add(&d_nanglelist[m],1); + d_anglelist(m,n,0) = d_anglelist_orig(i,0); + d_anglelist(m,n,1) = d_anglelist_orig(i,1); + d_anglelist(m,n,2) = d_anglelist_orig(i,2); + }); + } + + // call each sub-style's compute function + // set neighbor->anglelist to sub-style anglelist before call + // accumulate sub-style global/peratom energy/virial in hybrid + + ev_init(eflag, vflag); + + k_nanglelist.modify_device(); + k_nanglelist.sync_host(); + + for (int m = 0; m < nstyles; m++) { + neighbor->nanglelist = h_nanglelist[m]; + auto k_anglelist_m = Kokkos::subview(k_anglelist,m,Kokkos::ALL,Kokkos::ALL); + k_anglelist_m.modify_device(); + neighborKK->k_anglelist = k_anglelist_m; + + auto style = styles[m]; + atomKK->sync(style->execution_space,style->datamask_read); + style->compute(eflag, vflag); + atomKK->modified(style->execution_space,style->datamask_modify); + + if (eflag_global) energy += style->energy; + if (vflag_global) + for (int n = 0; n < 6; n++) virial[n] += style->virial[n]; + + if (eflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double *eatom_substyle = styles[m]->eatom; + for (int i = 0; i < n; i++) eatom[i] += eatom_substyle[i]; + } + if (vflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double **vatom_substyle = styles[m]->vatom; + for (int i = 0; i < n; i++) + for (int j = 0; j < 6; j++) vatom[i][j] += vatom_substyle[i][j]; + } + } + + // restore ptrs to original anglelist + + neighbor->nanglelist = nanglelist_orig; + neighborKK->k_anglelist = k_anglelist_orig; +} + +/* ---------------------------------------------------------------------- */ + +void AngleHybridKokkos::allocate() +{ + allocated = 1; + int n = atom->nangletypes; + + memoryKK->create_kokkos(k_map, map, n + 1, "angle:map"); + memory->create(setflag, n + 1, "angle:setflag"); + for (int i = 1; i <= n; i++) setflag[i] = 0; + + k_nanglelist = DAT::tdual_int_1d("angle:nanglelist", nstyles); +} + +/* ---------------------------------------------------------------------- */ + +void AngleHybridKokkos::deallocate() +{ + if (!allocated) return; + + allocated = 0; + + memory->destroy(setflag); + memoryKK->destroy_kokkos(k_map,map); +} + +/* ---------------------------------------------------------------------- + set coeffs for one type +---------------------------------------------------------------------- */ + +void AngleHybridKokkos::coeff(int narg, char **arg) +{ + AngleHybrid::coeff(narg,arg); + + k_map.modify_host(); +} + +/* ---------------------------------------------------------------------- */ + +void AngleHybridKokkos::init_style() +{ + AngleHybrid::init_style(); + + for (int m = 0; m < nstyles; m++) { + if (!styles[m]->kokkosable) + error->all(FLERR,"Must use only Kokkos-enabled angle styles with angle_style hybrid/kk"); + + if (styles[m]->execution_space == Host) + lmp->kokkos->allow_overlap = 0; + } +} + +/* ---------------------------------------------------------------------- + memory usage +------------------------------------------------------------------------- */ + +double AngleHybridKokkos::memory_usage() +{ + double bytes = (double) maxeatom * sizeof(double); + bytes += (double) maxvatom * 6 * sizeof(double); + for (int m = 0; m < nstyles; m++) bytes += (double) maxangle_all * 3 * sizeof(int); + for (int m = 0; m < nstyles; m++) + if (styles[m]) bytes += styles[m]->memory_usage(); + return bytes; +} diff --git a/src/KOKKOS/angle_hybrid_kokkos.h b/src/KOKKOS/angle_hybrid_kokkos.h new file mode 100644 index 0000000000..09b51958eb --- /dev/null +++ b/src/KOKKOS/angle_hybrid_kokkos.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef ANGLE_CLASS +// clang-format off +AngleStyle(hybrid/kk,AngleHybridKokkos); +AngleStyle(hybrid/kk/device,AngleHybridKokkos); +AngleStyle(hybrid/kk/host,AngleHybridKokkos); +// clang-format on +#else + +// clang-format off +#ifndef LMP_ANGLE_HYBRID_KOKKOS_H +#define LMP_ANGLE_HYBRID_KOKKOS_H + +#include "angle_hybrid.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +class AngleHybridKokkos : public AngleHybrid { + friend class Force; + + public: + AngleHybridKokkos(class LAMMPS *); + ~AngleHybridKokkos() override; + void compute(int, int) override; + void coeff(int, char **) override; + void init_style() override; + double memory_usage() override; + + private: + int maxangle_all; + + class NeighborKokkos *neighborKK; + + DAT::tdual_int_1d k_map; // which style each angle type points to + DAT::tdual_int_1d k_nanglelist; // # of angles in sub-style anglelists + DAT::tdual_int_3d k_anglelist; // anglelist for each sub-style + + void allocate() override; + void deallocate() override; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.cpp b/src/KOKKOS/dihedral_hybrid_kokkos.cpp new file mode 100644 index 0000000000..4adbb7f18b --- /dev/null +++ b/src/KOKKOS/dihedral_hybrid_kokkos.cpp @@ -0,0 +1,215 @@ +/* ---------------------------------------------------------------------- + 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 "bond_hybrid_kokkos.h" + +#include "atom_kokkos.h" +#include "atom_masks.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "kokkos.h" +#include "memory_kokkos.h" +#include "neighbor_kokkos.h" + +#include + +using namespace LAMMPS_NS; + +#define EXTRA 1000 + +/* ---------------------------------------------------------------------- */ + +DihedralHybridKokkos::DihedralHybridKokkos(LAMMPS *lmp) : DihedralHybrid(lmp) +{ + kokkosable = 1; + + atomKK = (AtomKokkos *) atom; + neighborKK = (NeighborKokkos *) neighbor; + + execution_space = Device; + + datamask_read = EMPTY_MASK; + datamask_modify = EMPTY_MASK; +} + +/* ---------------------------------------------------------------------- */ + +DihedralHybridKokkos::~DihedralHybridKokkos() +{ + deallocate(); +} + +/* ---------------------------------------------------------------------- */ + +void DihedralHybridKokkos::compute(int eflag, int vflag) +{ + // save ptrs to original bondlist + + int nbondlist_orig = neighbor->nbondlist; + neighborKK->k_bondlist.sync_device(); + auto k_bondlist_orig = neighborKK->k_bondlist; + auto d_bondlist_orig = k_bondlist_orig.d_view; + auto d_nbondlist = k_nbondlist.d_view; + auto h_nbondlist = k_nbondlist.h_view; + + // if this is re-neighbor step, create sub-style bondlists + // nbondlist[] = length of each sub-style list + // realloc sub-style bondlist if necessary + // load sub-style bondlist with 3 values from original bondlist + + if (neighbor->ago == 0) { + Kokkos::deep_copy(d_nbondlist,0); + + k_map.sync_device(); + auto d_map = k_map.d_view; + + Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_bondlist_orig(i,2)]; + if (m >= 0) Kokkos::atomic_increment(&d_nbondlist[m]); + }); + + k_nbondlist.modify_device(); + k_nbondlist.sync_host(); + + maxbond_all = 0; + for (int m = 0; m < nstyles; m++) + if (h_nbondlist[m] > maxbond_all) + maxbond_all = h_nbondlist[m] + EXTRA; + + if (k_bondlist.d_view.extent(1) < maxbond_all) + MemKK::realloc_kokkos(k_bondlist, "bond_hybrid:bondlist", nstyles, maxbond_all, 3); + auto d_bondlist = k_bondlist.d_view; + + Kokkos::deep_copy(d_nbondlist,0); + + Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_bondlist_orig(i,2)]; + if (m < 0) return; + const int n = Kokkos::atomic_fetch_add(&d_nbondlist[m],1); + d_bondlist(m,n,0) = d_bondlist_orig(i,0); + d_bondlist(m,n,1) = d_bondlist_orig(i,1); + d_bondlist(m,n,2) = d_bondlist_orig(i,2); + }); + } + + // call each sub-style's compute function + // set neighbor->bondlist to sub-style bondlist before call + // accumulate sub-style global/peratom energy/virial in hybrid + + ev_init(eflag, vflag); + + k_nbondlist.modify_device(); + k_nbondlist.sync_host(); + + for (int m = 0; m < nstyles; m++) { + neighbor->nbondlist = h_nbondlist[m]; + auto k_bondlist_m = Kokkos::subview(k_bondlist,m,Kokkos::ALL,Kokkos::ALL); + k_bondlist_m.modify_device(); + neighborKK->k_bondlist = k_bondlist_m; + + auto style = styles[m]; + atomKK->sync(style->execution_space,style->datamask_read); + style->compute(eflag, vflag); + atomKK->modified(style->execution_space,style->datamask_modify); + + if (eflag_global) energy += style->energy; + if (vflag_global) + for (int n = 0; n < 6; n++) virial[n] += style->virial[n]; + + if (eflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double *eatom_substyle = styles[m]->eatom; + for (int i = 0; i < n; i++) eatom[i] += eatom_substyle[i]; + } + if (vflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double **vatom_substyle = styles[m]->vatom; + for (int i = 0; i < n; i++) + for (int j = 0; j < 6; j++) vatom[i][j] += vatom_substyle[i][j]; + } + } + + // restore ptrs to original bondlist + + neighbor->nbondlist = nbondlist_orig; + neighborKK->k_bondlist = k_bondlist_orig; +} + +/* ---------------------------------------------------------------------- */ + +void DihedralHybridKokkos::allocate() +{ + allocated = 1; + int n = atom->nbondtypes; + + memoryKK->create_kokkos(k_map, map, n + 1, "bond:map"); + memory->create(setflag, n + 1, "bond:setflag"); + for (int i = 1; i <= n; i++) setflag[i] = 0; + + k_nbondlist = DAT::tdual_int_1d("bond:nbondlist", nstyles); +} + +/* ---------------------------------------------------------------------- */ + +void DihedralHybridKokkos::deallocate() +{ + if (!allocated) return; + + allocated = 0; + + memory->destroy(setflag); + memoryKK->destroy_kokkos(k_map,map); +} + +/* ---------------------------------------------------------------------- + set coeffs for one type +---------------------------------------------------------------------- */ + +void DihedralHybridKokkos::coeff(int narg, char **arg) +{ + DihedralHybrid::coeff(narg,arg); + + k_map.modify_host(); +} + +/* ---------------------------------------------------------------------- */ + +void DihedralHybridKokkos::init_style() +{ + DihedralHybrid::init_style(); + + for (int m = 0; m < nstyles; m++) { + if (!styles[m]->kokkosable) + error->all(FLERR,"Must use only Kokkos-enabled bond styles with bond_style hybrid/kk"); + + if (styles[m]->execution_space == Host) + lmp->kokkos->allow_overlap = 0; + } +} + +/* ---------------------------------------------------------------------- + memory usage +------------------------------------------------------------------------- */ + +double DihedralHybridKokkos::memory_usage() +{ + double bytes = (double) maxeatom * sizeof(double); + bytes += (double) maxvatom * 6 * sizeof(double); + for (int m = 0; m < nstyles; m++) bytes += (double) maxbond_all * 3 * sizeof(int); + for (int m = 0; m < nstyles; m++) + if (styles[m]) bytes += styles[m]->memory_usage(); + return bytes; +} diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.h b/src/KOKKOS/dihedral_hybrid_kokkos.h new file mode 100644 index 0000000000..8b090d46c2 --- /dev/null +++ b/src/KOKKOS/dihedral_hybrid_kokkos.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef BOND_CLASS +// clang-format off +DihedralStyle(hybrid/kk,DihedralHybridKokkos); +DihedralStyle(hybrid/kk/device,DihedralHybridKokkos); +DihedralStyle(hybrid/kk/host,DihedralHybridKokkos); +// clang-format on +#else + +// clang-format off +#ifndef LMP_BOND_HYBRID_KOKKOS_H +#define LMP_BOND_HYBRID_KOKKOS_H + +#include "bond_hybrid.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +class DihedralHybridKokkos : public DihedralHybrid { + friend class Force; + + public: + DihedralHybridKokkos(class LAMMPS *); + ~DihedralHybridKokkos() override; + void compute(int, int) override; + void coeff(int, char **) override; + void init_style() override; + double memory_usage() override; + + private: + int maxbond_all; + + class NeighborKokkos *neighborKK; + + DAT::tdual_int_1d k_map; // which style each bond type points to + DAT::tdual_int_1d k_nbondlist; // # of bonds in sub-style bondlists + DAT::tdual_int_3d k_bondlist; // bondlist for each sub-style + + void allocate() override; + void deallocate() override; +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/src/KOKKOS/improper_hybrid_kokkos.cpp b/src/KOKKOS/improper_hybrid_kokkos.cpp new file mode 100644 index 0000000000..d63ebccac6 --- /dev/null +++ b/src/KOKKOS/improper_hybrid_kokkos.cpp @@ -0,0 +1,215 @@ +/* ---------------------------------------------------------------------- + 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 "bond_hybrid_kokkos.h" + +#include "atom_kokkos.h" +#include "atom_masks.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "kokkos.h" +#include "memory_kokkos.h" +#include "neighbor_kokkos.h" + +#include + +using namespace LAMMPS_NS; + +#define EXTRA 1000 + +/* ---------------------------------------------------------------------- */ + +BondHybridKokkos::BondHybridKokkos(LAMMPS *lmp) : BondHybrid(lmp) +{ + kokkosable = 1; + + atomKK = (AtomKokkos *) atom; + neighborKK = (NeighborKokkos *) neighbor; + + execution_space = Device; + + datamask_read = EMPTY_MASK; + datamask_modify = EMPTY_MASK; +} + +/* ---------------------------------------------------------------------- */ + +BondHybridKokkos::~BondHybridKokkos() +{ + deallocate(); +} + +/* ---------------------------------------------------------------------- */ + +void BondHybridKokkos::compute(int eflag, int vflag) +{ + // save ptrs to original bondlist + + int nbondlist_orig = neighbor->nbondlist; + neighborKK->k_bondlist.sync_device(); + auto k_bondlist_orig = neighborKK->k_bondlist; + auto d_bondlist_orig = k_bondlist_orig.d_view; + auto d_nbondlist = k_nbondlist.d_view; + auto h_nbondlist = k_nbondlist.h_view; + + // if this is re-neighbor step, create sub-style bondlists + // nbondlist[] = length of each sub-style list + // realloc sub-style bondlist if necessary + // load sub-style bondlist with 3 values from original bondlist + + if (neighbor->ago == 0) { + Kokkos::deep_copy(d_nbondlist,0); + + k_map.sync_device(); + auto d_map = k_map.d_view; + + Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_bondlist_orig(i,2)]; + if (m >= 0) Kokkos::atomic_increment(&d_nbondlist[m]); + }); + + k_nbondlist.modify_device(); + k_nbondlist.sync_host(); + + maxbond_all = 0; + for (int m = 0; m < nstyles; m++) + if (h_nbondlist[m] > maxbond_all) + maxbond_all = h_nbondlist[m] + EXTRA; + + if (k_bondlist.d_view.extent(1) < maxbond_all) + MemKK::realloc_kokkos(k_bondlist, "bond_hybrid:bondlist", nstyles, maxbond_all, 3); + auto d_bondlist = k_bondlist.d_view; + + Kokkos::deep_copy(d_nbondlist,0); + + Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_bondlist_orig(i,2)]; + if (m < 0) return; + const int n = Kokkos::atomic_fetch_add(&d_nbondlist[m],1); + d_bondlist(m,n,0) = d_bondlist_orig(i,0); + d_bondlist(m,n,1) = d_bondlist_orig(i,1); + d_bondlist(m,n,2) = d_bondlist_orig(i,2); + }); + } + + // call each sub-style's compute function + // set neighbor->bondlist to sub-style bondlist before call + // accumulate sub-style global/peratom energy/virial in hybrid + + ev_init(eflag, vflag); + + k_nbondlist.modify_device(); + k_nbondlist.sync_host(); + + for (int m = 0; m < nstyles; m++) { + neighbor->nbondlist = h_nbondlist[m]; + auto k_bondlist_m = Kokkos::subview(k_bondlist,m,Kokkos::ALL,Kokkos::ALL); + k_bondlist_m.modify_device(); + neighborKK->k_bondlist = k_bondlist_m; + + auto style = styles[m]; + atomKK->sync(style->execution_space,style->datamask_read); + style->compute(eflag, vflag); + atomKK->modified(style->execution_space,style->datamask_modify); + + if (eflag_global) energy += style->energy; + if (vflag_global) + for (int n = 0; n < 6; n++) virial[n] += style->virial[n]; + + if (eflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double *eatom_substyle = styles[m]->eatom; + for (int i = 0; i < n; i++) eatom[i] += eatom_substyle[i]; + } + if (vflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double **vatom_substyle = styles[m]->vatom; + for (int i = 0; i < n; i++) + for (int j = 0; j < 6; j++) vatom[i][j] += vatom_substyle[i][j]; + } + } + + // restore ptrs to original bondlist + + neighbor->nbondlist = nbondlist_orig; + neighborKK->k_bondlist = k_bondlist_orig; +} + +/* ---------------------------------------------------------------------- */ + +void BondHybridKokkos::allocate() +{ + allocated = 1; + int n = atom->nbondtypes; + + memoryKK->create_kokkos(k_map, map, n + 1, "bond:map"); + memory->create(setflag, n + 1, "bond:setflag"); + for (int i = 1; i <= n; i++) setflag[i] = 0; + + k_nbondlist = DAT::tdual_int_1d("bond:nbondlist", nstyles); +} + +/* ---------------------------------------------------------------------- */ + +void BondHybridKokkos::deallocate() +{ + if (!allocated) return; + + allocated = 0; + + memory->destroy(setflag); + memoryKK->destroy_kokkos(k_map,map); +} + +/* ---------------------------------------------------------------------- + set coeffs for one type +---------------------------------------------------------------------- */ + +void BondHybridKokkos::coeff(int narg, char **arg) +{ + BondHybrid::coeff(narg,arg); + + k_map.modify_host(); +} + +/* ---------------------------------------------------------------------- */ + +void BondHybridKokkos::init_style() +{ + BondHybrid::init_style(); + + for (int m = 0; m < nstyles; m++) { + if (!styles[m]->kokkosable) + error->all(FLERR,"Must use only Kokkos-enabled bond styles with bond_style hybrid/kk"); + + if (styles[m]->execution_space == Host) + lmp->kokkos->allow_overlap = 0; + } +} + +/* ---------------------------------------------------------------------- + memory usage +------------------------------------------------------------------------- */ + +double BondHybridKokkos::memory_usage() +{ + double bytes = (double) maxeatom * sizeof(double); + bytes += (double) maxvatom * 6 * sizeof(double); + for (int m = 0; m < nstyles; m++) bytes += (double) maxbond_all * 3 * sizeof(int); + for (int m = 0; m < nstyles; m++) + if (styles[m]) bytes += styles[m]->memory_usage(); + return bytes; +} diff --git a/src/KOKKOS/improper_hybrid_kokkos.h b/src/KOKKOS/improper_hybrid_kokkos.h new file mode 100644 index 0000000000..217beaca5f --- /dev/null +++ b/src/KOKKOS/improper_hybrid_kokkos.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- ---------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifdef BOND_CLASS +// clang-format off +BondStyle(hybrid/kk,BondHybridKokkos); +BondStyle(hybrid/kk/device,BondHybridKokkos); +BondStyle(hybrid/kk/host,BondHybridKokkos); +// clang-format on +#else + +// clang-format off +#ifndef LMP_BOND_HYBRID_KOKKOS_H +#define LMP_BOND_HYBRID_KOKKOS_H + +#include "bond_hybrid.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +class BondHybridKokkos : public BondHybrid { + friend class Force; + + public: + BondHybridKokkos(class LAMMPS *); + ~BondHybridKokkos() override; + void compute(int, int) override; + void coeff(int, char **) override; + void init_style() override; + double memory_usage() override; + + private: + int maxbond_all; + + class NeighborKokkos *neighborKK; + + DAT::tdual_int_1d k_map; // which style each bond type points to + DAT::tdual_int_1d k_nbondlist; // # of bonds in sub-style bondlists + DAT::tdual_int_3d k_bondlist; // bondlist for each sub-style + + void allocate() override; + void deallocate() override; +}; + +} // namespace LAMMPS_NS + +#endif +#endif From d7da58752bb6c77f65ecdf021042b3b38207914e Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Thu, 27 Jun 2024 22:54:00 -0600 Subject: [PATCH 128/385] update commands, zero functors --- src/KOKKOS/angle_harmonic_kokkos.cpp | 17 ++++++++----- src/KOKKOS/angle_harmonic_kokkos.h | 7 +++--- src/KOKKOS/dihedral_harmonic_kokkos.cpp | 33 ++++++++++++++----------- src/KOKKOS/dihedral_harmonic_kokkos.h | 6 ++--- src/KOKKOS/improper_harmonic_kokkos.cpp | 25 ++++++++++--------- src/KOKKOS/improper_harmonic_kokkos.h | 8 +++--- 6 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/KOKKOS/angle_harmonic_kokkos.cpp b/src/KOKKOS/angle_harmonic_kokkos.cpp index d7be418326..4e6aae9c1b 100644 --- a/src/KOKKOS/angle_harmonic_kokkos.cpp +++ b/src/KOKKOS/angle_harmonic_kokkos.cpp @@ -38,6 +38,7 @@ static constexpr double SMALL = 0.001; template AngleHarmonicKokkos::AngleHarmonicKokkos(LAMMPS *lmp) : AngleHarmonic(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -71,14 +72,18 @@ void AngleHarmonicKokkos::compute(int eflag_in, int vflag_in) // reallocate per-atom arrays if necessary if (eflag_atom) { + if(k_eatom.extent(0) < maxeatom) { memoryKK->destroy_kokkos(k_eatom,eatom); memoryKK->create_kokkos(k_eatom,eatom,maxeatom,"angle:eatom"); d_eatom = k_eatom.template view(); + } else Kokkos::deep_copy(d_eatom,0.0); } if (vflag_atom) { + if(k_vatom.extent(0) < maxvatom) { memoryKK->destroy_kokkos(k_vatom,vatom); memoryKK->create_kokkos(k_vatom,vatom,maxvatom,"angle:vatom"); d_vatom = k_vatom.template view(); + } else Kokkos::deep_copy(d_vatom,0.0); } //atomKK->sync(execution_space,datamask_read); @@ -127,12 +132,12 @@ void AngleHarmonicKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -264,8 +269,8 @@ void AngleHarmonicKokkos::coeff(int narg, char **arg) k_theta0.h_view[i] = theta0[i]; } - k_k.template modify(); - k_theta0.template modify(); + k_k.modify_host(); + k_theta0.modify_host(); } /* ---------------------------------------------------------------------- @@ -283,8 +288,8 @@ void AngleHarmonicKokkos::read_restart(FILE *fp) k_theta0.h_view[i] = theta0[i]; } - k_k.template modify(); - k_theta0.template modify(); + k_k.modify_host(); + k_theta0.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_harmonic_kokkos.h b/src/KOKKOS/angle_harmonic_kokkos.h index ce4b9d9976..4e427d2417 100644 --- a/src/KOKKOS/angle_harmonic_kokkos.h +++ b/src/KOKKOS/angle_harmonic_kokkos.h @@ -37,6 +37,7 @@ class AngleHarmonicKokkos : public AngleHarmonic { public: typedef DeviceType device_type; typedef EV_FLOAT value_type; + typedef ArrayTypes AT; AngleHarmonicKokkos(class LAMMPS *); ~AngleHarmonicKokkos() override; @@ -59,6 +60,9 @@ class AngleHarmonicKokkos : public AngleHarmonic { const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const; + typename AT::tdual_efloat_1d k_eatom; + typename AT::tdual_virial_array k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -66,9 +70,6 @@ class AngleHarmonicKokkos : public AngleHarmonic { typename ArrayTypes::t_x_array_randomread x; typename ArrayTypes::t_f_array f; typename ArrayTypes::t_int_2d anglelist; - - typename ArrayTypes::tdual_efloat_1d k_eatom; - typename ArrayTypes::tdual_virial_array k_vatom; typename ArrayTypes::t_efloat_1d d_eatom; typename ArrayTypes::t_virial_array d_vatom; diff --git a/src/KOKKOS/dihedral_harmonic_kokkos.cpp b/src/KOKKOS/dihedral_harmonic_kokkos.cpp index 78860800be..c451c880ca 100644 --- a/src/KOKKOS/dihedral_harmonic_kokkos.cpp +++ b/src/KOKKOS/dihedral_harmonic_kokkos.cpp @@ -37,6 +37,7 @@ static constexpr double TOLERANCE = 0.05; template DihedralHarmonicKokkos::DihedralHarmonicKokkos(LAMMPS *lmp) : DihedralHarmonic(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -74,14 +75,18 @@ void DihedralHarmonicKokkos::compute(int eflag_in, int vflag_in) // reallocate per-atom arrays if necessary if (eflag_atom) { + if(k_eatom.extent(0) < maxeatom) { memoryKK->destroy_kokkos(k_eatom,eatom); memoryKK->create_kokkos(k_eatom,eatom,maxeatom,"dihedral:eatom"); d_eatom = k_eatom.view(); + } else Kokkos::deep_copy(d_eatom,0.0); } if (vflag_atom) { + if(k_vatom.extent(0) < maxvatom) { memoryKK->destroy_kokkos(k_vatom,vatom); memoryKK->create_kokkos(k_vatom,vatom,maxvatom,"dihedral:vatom"); d_vatom = k_vatom.view(); + } else Kokkos::deep_copy(d_vatom,0.0); } k_k.template sync(); @@ -99,7 +104,7 @@ void DihedralHarmonicKokkos::compute(int eflag_in, int vflag_in) newton_bond = force->newton_bond; h_warning_flag() = 0; - k_warning_flag.template modify(); + k_warning_flag.modify_host(); k_warning_flag.template sync(); copymode = 1; @@ -125,7 +130,7 @@ void DihedralHarmonicKokkos::compute(int eflag_in, int vflag_in) // error check k_warning_flag.template modify(); - k_warning_flag.template sync(); + k_warning_flag.sync_host(); if (h_warning_flag()) error->warning(FLERR,"Dihedral problem"); @@ -141,12 +146,12 @@ void DihedralHarmonicKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -362,11 +367,11 @@ void DihedralHarmonicKokkos::coeff(int narg, char **arg) k_multiplicity.h_view[i] = multiplicity[i]; } - k_k.template modify(); - k_cos_shift.template modify(); - k_sin_shift.template modify(); - k_sign.template modify(); - k_multiplicity.template modify(); + k_k.modify_host(); + k_cos_shift.modify_host(); + k_sin_shift.modify_host(); + k_sign.modify_host(); + k_multiplicity.modify_host(); } /* ---------------------------------------------------------------------- @@ -387,11 +392,11 @@ void DihedralHarmonicKokkos::read_restart(FILE *fp) k_multiplicity.h_view[i] = multiplicity[i]; } - k_k.template modify(); - k_cos_shift.template modify(); - k_sin_shift.template modify(); - k_sign.template modify(); - k_multiplicity.template modify(); + k_k.modify_host(); + k_cos_shift.modify_host(); + k_sin_shift.modify_host(); + k_sign.modify_host(); + k_multiplicity.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/dihedral_harmonic_kokkos.h b/src/KOKKOS/dihedral_harmonic_kokkos.h index e73f19afd1..1ad62398f7 100644 --- a/src/KOKKOS/dihedral_harmonic_kokkos.h +++ b/src/KOKKOS/dihedral_harmonic_kokkos.h @@ -60,6 +60,9 @@ class DihedralHarmonicKokkos : public DihedralHarmonic { const F_FLOAT &vb2x, const F_FLOAT &vb2y, const F_FLOAT &vb2z, const F_FLOAT &vb3x, const F_FLOAT &vb3y, const F_FLOAT &vb3z) const; + DAT::tdual_efloat_1d k_eatom; + DAT::tdual_virial_array k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -67,9 +70,6 @@ class DihedralHarmonicKokkos : public DihedralHarmonic { typename AT::t_x_array_randomread x; typename AT::t_f_array f; typename AT::t_int_2d dihedrallist; - - DAT::tdual_efloat_1d k_eatom; - DAT::tdual_virial_array k_vatom; typename ArrayTypes::t_efloat_1d d_eatom; typename ArrayTypes::t_virial_array d_vatom; diff --git a/src/KOKKOS/improper_harmonic_kokkos.cpp b/src/KOKKOS/improper_harmonic_kokkos.cpp index a075238f22..31eac00828 100644 --- a/src/KOKKOS/improper_harmonic_kokkos.cpp +++ b/src/KOKKOS/improper_harmonic_kokkos.cpp @@ -36,6 +36,7 @@ static constexpr double SMALL = 0.001; template ImproperHarmonicKokkos::ImproperHarmonicKokkos(LAMMPS *lmp) : ImproperHarmonic(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -73,18 +74,18 @@ void ImproperHarmonicKokkos::compute(int eflag_in, int vflag_in) // reallocate per-atom arrays if necessary if (eflag_atom) { - //if(k_eatom.extent(0)destroy_kokkos(k_eatom,eatom); memoryKK->create_kokkos(k_eatom,eatom,maxeatom,"improper:eatom"); d_eatom = k_eatom.template view(); - //} + } else Kokkos::deep_copy(d_eatom,0.0); } if (vflag_atom) { - //if(k_vatom.extent(0)destroy_kokkos(k_vatom,vatom); memoryKK->create_kokkos(k_vatom,vatom,maxvatom,"improper:vatom"); d_vatom = k_vatom.template view(); - //} + } else Kokkos::deep_copy(d_vatom,0.0); } //atomKK->sync(execution_space,datamask_read); @@ -102,7 +103,7 @@ void ImproperHarmonicKokkos::compute(int eflag_in, int vflag_in) newton_bond = force->newton_bond; h_warning_flag() = 0; - k_warning_flag.template modify(); + k_warning_flag.modify_host(); k_warning_flag.template sync(); copymode = 1; @@ -128,7 +129,7 @@ void ImproperHarmonicKokkos::compute(int eflag_in, int vflag_in) // error check k_warning_flag.template modify(); - k_warning_flag.template sync(); + k_warning_flag.sync_host(); if (h_warning_flag()) error->warning(FLERR,"Dihedral problem"); @@ -144,12 +145,12 @@ void ImproperHarmonicKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -324,8 +325,8 @@ void ImproperHarmonicKokkos::coeff(int narg, char **arg) k_chi.h_view[i] = chi[i]; } - k_k.template modify(); - k_chi.template modify(); + k_k.modify_host(); + k_chi.modify_host(); } /* ---------------------------------------------------------------------- @@ -343,8 +344,8 @@ void ImproperHarmonicKokkos::read_restart(FILE *fp) k_chi.h_view[i] = chi[i]; } - k_k.template modify(); - k_chi.template modify(); + k_k.modify_host(); + k_chi.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/improper_harmonic_kokkos.h b/src/KOKKOS/improper_harmonic_kokkos.h index 8bd206aaf0..ad31447383 100644 --- a/src/KOKKOS/improper_harmonic_kokkos.h +++ b/src/KOKKOS/improper_harmonic_kokkos.h @@ -60,17 +60,17 @@ class ImproperHarmonicKokkos : public ImproperHarmonic { const F_FLOAT &vb2x, const F_FLOAT &vb2y, const F_FLOAT &vb2z, const F_FLOAT &vb3x, const F_FLOAT &vb3y, const F_FLOAT &vb3z) const; + typedef typename KKDevice::value KKDeviceType; + Kokkos::DualView k_eatom; + Kokkos::DualView k_vatom; + protected: class NeighborKokkos *neighborKK; - typedef typename KKDevice::value KKDeviceType; typename AT::t_x_array_randomread x; typename Kokkos::View > f; typename AT::t_int_2d improperlist; - - Kokkos::DualView k_eatom; - Kokkos::DualView k_vatom; Kokkos::View > d_eatom; Kokkos::View > d_vatom; From 6a8e7b4d707d9e0c7b82c6e027e2a5d59543161e Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Thu, 27 Jun 2024 22:56:12 -0600 Subject: [PATCH 129/385] update variables, templates, kk types --- src/KOKKOS/angle_charmm_kokkos.cpp | 21 +-- src/KOKKOS/angle_charmm_kokkos.h | 9 +- src/KOKKOS/angle_class2_kokkos.cpp | 65 ++++----- src/KOKKOS/angle_class2_kokkos.h | 8 +- src/KOKKOS/angle_cosine_kokkos.cpp | 9 +- src/KOKKOS/angle_cosine_kokkos.h | 7 +- src/KOKKOS/dihedral_charmm_kokkos.cpp | 45 +++---- src/KOKKOS/dihedral_charmm_kokkos.h | 7 +- src/KOKKOS/dihedral_charmmfsw_kokkos.cpp | 45 +++---- src/KOKKOS/dihedral_charmmfsw_kokkos.h | 8 +- src/KOKKOS/dihedral_class2_kokkos.cpp | 161 ++++++++++++----------- src/KOKKOS/dihedral_class2_kokkos.h | 6 +- src/KOKKOS/dihedral_opls_kokkos.cpp | 25 ++-- src/KOKKOS/dihedral_opls_kokkos.h | 7 +- src/KOKKOS/improper_class2_kokkos.cpp | 53 ++++---- src/KOKKOS/improper_class2_kokkos.h | 6 +- 16 files changed, 245 insertions(+), 237 deletions(-) diff --git a/src/KOKKOS/angle_charmm_kokkos.cpp b/src/KOKKOS/angle_charmm_kokkos.cpp index 666002686c..22d2b924dd 100644 --- a/src/KOKKOS/angle_charmm_kokkos.cpp +++ b/src/KOKKOS/angle_charmm_kokkos.cpp @@ -38,6 +38,7 @@ static constexpr double SMALL = 0.001; template AngleCharmmKokkos::AngleCharmmKokkos(LAMMPS *lmp) : AngleCharmm(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -125,12 +126,12 @@ void AngleCharmmKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -284,10 +285,10 @@ void AngleCharmmKokkos::coeff(int narg, char **arg) k_r_ub.h_view[i] = r_ub[i]; } - k_k.template modify(); - k_theta0.template modify(); - k_k_ub.template modify(); - k_r_ub.template modify(); + k_k.modify_host(); + k_theta0.modify_host(); + k_k_ub.modify_host(); + k_r_ub.modify_host(); k_k.template sync(); k_theta0.template sync(); @@ -322,10 +323,10 @@ void AngleCharmmKokkos::read_restart(FILE *fp) k_r_ub.h_view[i] = r_ub[i]; } - k_k.template modify(); - k_theta0.template modify(); - k_k_ub.template modify(); - k_r_ub.template modify(); + k_k.modify_host(); + k_theta0.modify_host(); + k_k_ub.modify_host(); + k_r_ub.modify_host(); k_k.template sync(); k_theta0.template sync(); diff --git a/src/KOKKOS/angle_charmm_kokkos.h b/src/KOKKOS/angle_charmm_kokkos.h index 197f9160a0..2bb06725f9 100644 --- a/src/KOKKOS/angle_charmm_kokkos.h +++ b/src/KOKKOS/angle_charmm_kokkos.h @@ -58,19 +58,18 @@ class AngleCharmmKokkos : public AngleCharmm { const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const; + using KKDeviceType = typename KKDevice::value; + Kokkos::DualView k_eatom; + Kokkos::DualView k_vatom; + protected: class NeighborKokkos *neighborKK; typedef ArrayTypes AT; typename AT::t_x_array_randomread x; - - using KKDeviceType = typename KKDevice::value; typename Kokkos::View > f; typename AT::t_int_2d anglelist; - - Kokkos::DualView k_eatom; - Kokkos::DualView k_vatom; Kokkos::View> d_eatom; Kokkos::View> d_vatom; diff --git a/src/KOKKOS/angle_class2_kokkos.cpp b/src/KOKKOS/angle_class2_kokkos.cpp index e831ae2283..e9d4797e71 100644 --- a/src/KOKKOS/angle_class2_kokkos.cpp +++ b/src/KOKKOS/angle_class2_kokkos.cpp @@ -38,6 +38,7 @@ static constexpr double SMALL = 0.001; template AngleClass2Kokkos::AngleClass2Kokkos(LAMMPS *lmp) : AngleClass2(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -141,12 +142,12 @@ void AngleClass2Kokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -386,21 +387,21 @@ void AngleClass2Kokkos::coeff(int narg, char **arg) k_theta0.h_view[i] = theta0[i]; } - k_k2.template modify(); - k_k3.template modify(); - k_k4.template modify(); - k_bb_k.template modify(); - k_bb_r1.template modify(); - k_bb_r2.template modify(); - k_ba_k1.template modify(); - k_ba_k2.template modify(); - k_ba_r1.template modify(); - k_ba_r2.template modify(); - k_setflag.template modify(); - k_setflag_a.template modify(); - k_setflag_bb.template modify(); - k_setflag_ba.template modify(); - k_theta0.template modify(); + k_k2.modify_host(); + k_k3.modify_host(); + k_k4.modify_host(); + k_bb_k.modify_host(); + k_bb_r1.modify_host(); + k_bb_r2.modify_host(); + k_ba_k1.modify_host(); + k_ba_k2.modify_host(); + k_ba_r1.modify_host(); + k_ba_r2.modify_host(); + k_setflag.modify_host(); + k_setflag_a.modify_host(); + k_setflag_bb.modify_host(); + k_setflag_ba.modify_host(); + k_theta0.modify_host(); } /* ---------------------------------------------------------------------- @@ -465,21 +466,21 @@ void AngleClass2Kokkos::read_restart(FILE *fp) k_theta0.h_view[i] = theta0[i]; } - k_k2.template modify(); - k_k3.template modify(); - k_k4.template modify(); - k_bb_k.template modify(); - k_bb_r1.template modify(); - k_bb_r2.template modify(); - k_ba_k1.template modify(); - k_ba_k2.template modify(); - k_ba_r1.template modify(); - k_ba_r2.template modify(); - k_setflag.template modify(); - k_setflag_a.template modify(); - k_setflag_bb.template modify(); - k_setflag_ba.template modify(); - k_theta0.template modify(); + k_k2.modify_host(); + k_k3.modify_host(); + k_k4.modify_host(); + k_bb_k.modify_host(); + k_bb_r1.modify_host(); + k_bb_r2.modify_host(); + k_ba_k1.modify_host(); + k_ba_k2.modify_host(); + k_ba_r1.modify_host(); + k_ba_r2.modify_host(); + k_setflag.modify_host(); + k_setflag_a.modify_host(); + k_setflag_bb.modify_host(); + k_setflag_ba.modify_host(); + k_theta0.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_class2_kokkos.h b/src/KOKKOS/angle_class2_kokkos.h index 81bed169bc..7ef9e9b652 100644 --- a/src/KOKKOS/angle_class2_kokkos.h +++ b/src/KOKKOS/angle_class2_kokkos.h @@ -36,8 +36,8 @@ class AngleClass2Kokkos : public AngleClass2 { public: typedef DeviceType device_type; - typedef ArrayTypes AT; typedef EV_FLOAT value_type; + typedef ArrayTypes AT; AngleClass2Kokkos(class LAMMPS *); ~AngleClass2Kokkos() override; @@ -60,6 +60,9 @@ class AngleClass2Kokkos : public AngleClass2 { const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const; + typename AT::tdual_efloat_1d k_eatom; + typename AT::tdual_virial_array k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -67,9 +70,6 @@ class AngleClass2Kokkos : public AngleClass2 { typename AT::t_x_array_randomread x; typename AT::t_f_array f; typename AT::t_int_2d anglelist; - - typename AT::tdual_efloat_1d k_eatom; - typename AT::tdual_virial_array k_vatom; typename AT::t_efloat_1d d_eatom; typename AT::t_virial_array d_vatom; diff --git a/src/KOKKOS/angle_cosine_kokkos.cpp b/src/KOKKOS/angle_cosine_kokkos.cpp index 768dfd43ca..5d61213df8 100644 --- a/src/KOKKOS/angle_cosine_kokkos.cpp +++ b/src/KOKKOS/angle_cosine_kokkos.cpp @@ -36,6 +36,7 @@ using namespace MathConst; template AngleCosineKokkos::AngleCosineKokkos(LAMMPS *lmp) : AngleCosine(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -124,12 +125,12 @@ void AngleCosineKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -254,7 +255,7 @@ void AngleCosineKokkos::coeff(int narg, char **arg) for (int i = 1; i <= n; i++) k_k.h_view[i] = k[i]; - k_k.template modify(); + k_k.modify_host(); } /* ---------------------------------------------------------------------- @@ -270,7 +271,7 @@ void AngleCosineKokkos::read_restart(FILE *fp) for (int i = 1; i <= n; i++) k_k.h_view[i] = k[i]; - k_k.template modify(); + k_k.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_cosine_kokkos.h b/src/KOKKOS/angle_cosine_kokkos.h index 33b80f5a5f..3cfa5a73df 100644 --- a/src/KOKKOS/angle_cosine_kokkos.h +++ b/src/KOKKOS/angle_cosine_kokkos.h @@ -37,6 +37,7 @@ class AngleCosineKokkos : public AngleCosine { public: typedef DeviceType device_type; typedef EV_FLOAT value_type; + typedef ArrayTypes AT; AngleCosineKokkos(class LAMMPS *); ~AngleCosineKokkos() override; @@ -59,6 +60,9 @@ class AngleCosineKokkos : public AngleCosine { const F_FLOAT &delx1, const F_FLOAT &dely1, const F_FLOAT &delz1, const F_FLOAT &delx2, const F_FLOAT &dely2, const F_FLOAT &delz2) const; + typename AT::tdual_efloat_1d k_eatom; + typename AT::tdual_virial_array k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -66,9 +70,6 @@ class AngleCosineKokkos : public AngleCosine { typename ArrayTypes::t_x_array_randomread x; typename ArrayTypes::t_f_array f; typename ArrayTypes::t_int_2d anglelist; - - typename ArrayTypes::tdual_efloat_1d k_eatom; - typename ArrayTypes::tdual_virial_array k_vatom; typename ArrayTypes::t_efloat_1d d_eatom; typename ArrayTypes::t_virial_array d_vatom; diff --git a/src/KOKKOS/dihedral_charmm_kokkos.cpp b/src/KOKKOS/dihedral_charmm_kokkos.cpp index b385ec7f01..a8939770df 100644 --- a/src/KOKKOS/dihedral_charmm_kokkos.cpp +++ b/src/KOKKOS/dihedral_charmm_kokkos.cpp @@ -40,6 +40,7 @@ static constexpr double TOLERANCE = 0.05; template DihedralCharmmKokkos::DihedralCharmmKokkos(LAMMPS *lmp) : DihedralCharmm(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -115,7 +116,7 @@ void DihedralCharmmKokkos::compute(int eflag_in, int vflag_in) qqrd2e = force->qqrd2e; h_warning_flag() = 0; - k_warning_flag.template modify(); + k_warning_flag.modify_host(); k_warning_flag.template sync(); copymode = 1; @@ -141,7 +142,7 @@ void DihedralCharmmKokkos::compute(int eflag_in, int vflag_in) // error check k_warning_flag.template modify(); - k_warning_flag.template sync(); + k_warning_flag.sync_host(); if (h_warning_flag()) error->warning(FLERR,"Dihedral problem"); @@ -174,20 +175,20 @@ void DihedralCharmmKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); k_eatom_pair.template modify(); - k_eatom_pair.template sync(); + k_eatom_pair.sync_host(); for (int i = 0; i < n; i++) force->pair->eatom[i] += k_eatom_pair.h_view(i); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); k_vatom_pair.template modify(); - k_vatom_pair.template sync(); + k_vatom_pair.sync_host(); for (int i = 0; i < n; i++) { force->pair->vatom[i][0] += k_vatom_pair.h_view(i,0); force->pair->vatom[i][1] += k_vatom_pair.h_view(i,1); @@ -454,12 +455,12 @@ void DihedralCharmmKokkos::coeff(int narg, char **arg) k_weight.h_view[i] = weight[i]; } - k_k.template modify(); - k_multiplicity.template modify(); - k_shift.template modify(); - k_cos_shift.template modify(); - k_sin_shift.template modify(); - k_weight.template modify(); + k_k.modify_host(); + k_multiplicity.modify_host(); + k_shift.modify_host(); + k_cos_shift.modify_host(); + k_sin_shift.modify_host(); + k_weight.modify_host(); k_k.template sync(); k_multiplicity.template sync(); @@ -502,10 +503,10 @@ void DihedralCharmmKokkos::init_style() } } - k_lj14_1.template modify(); - k_lj14_2.template modify(); - k_lj14_3.template modify(); - k_lj14_4.template modify(); + k_lj14_1.modify_host(); + k_lj14_2.modify_host(); + k_lj14_3.modify_host(); + k_lj14_4.modify_host(); k_lj14_1.template sync(); k_lj14_2.template sync(); @@ -547,12 +548,12 @@ void DihedralCharmmKokkos::read_restart(FILE *fp) k_weight.h_view[i] = weight[i]; } - k_k.template modify(); - k_multiplicity.template modify(); - k_shift.template modify(); - k_cos_shift.template modify(); - k_sin_shift.template modify(); - k_weight.template modify(); + k_k.modify_host(); + k_multiplicity.modify_host(); + k_shift.modify_host(); + k_cos_shift.modify_host(); + k_sin_shift.modify_host(); + k_weight.modify_host(); k_k.template sync(); k_multiplicity.template sync(); diff --git a/src/KOKKOS/dihedral_charmm_kokkos.h b/src/KOKKOS/dihedral_charmm_kokkos.h index dea251473b..74510ed515 100644 --- a/src/KOKKOS/dihedral_charmm_kokkos.h +++ b/src/KOKKOS/dihedral_charmm_kokkos.h @@ -104,6 +104,10 @@ class DihedralCharmmKokkos : public DihedralCharmm { const F_FLOAT &evdwl, const F_FLOAT &ecoul, const F_FLOAT &fpair, const F_FLOAT &delx, const F_FLOAT &dely, const F_FLOAT &delz) const; + typedef typename KKDevice::value KKDeviceType; + Kokkos::DualView k_eatom; + Kokkos::DualView k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -114,9 +118,6 @@ class DihedralCharmmKokkos : public DihedralCharmm { typename AT::t_f_array f; typename AT::t_int_2d dihedrallist; - typedef typename KKDevice::value KKDeviceType; - Kokkos::DualView k_eatom; - Kokkos::DualView k_vatom; Kokkos::View > d_eatom; Kokkos::View > d_vatom; diff --git a/src/KOKKOS/dihedral_charmmfsw_kokkos.cpp b/src/KOKKOS/dihedral_charmmfsw_kokkos.cpp index aeb9b022a7..3414a02ec4 100644 --- a/src/KOKKOS/dihedral_charmmfsw_kokkos.cpp +++ b/src/KOKKOS/dihedral_charmmfsw_kokkos.cpp @@ -47,6 +47,7 @@ static constexpr double TOLERANCE = 0.05; template DihedralCharmmfswKokkos::DihedralCharmmfswKokkos(LAMMPS *lmp) : DihedralCharmmfsw(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -122,7 +123,7 @@ void DihedralCharmmfswKokkos::compute(int eflag_in, int vflag_in) qqrd2e = force->qqrd2e; h_warning_flag() = 0; - k_warning_flag.template modify(); + k_warning_flag.modify_host(); k_warning_flag.template sync(); copymode = 1; @@ -148,7 +149,7 @@ void DihedralCharmmfswKokkos::compute(int eflag_in, int vflag_in) // error check k_warning_flag.template modify(); - k_warning_flag.template sync(); + k_warning_flag.sync_host(); if (h_warning_flag()) error->warning(FLERR,"Dihedral problem"); @@ -181,20 +182,20 @@ void DihedralCharmmfswKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); k_eatom_pair.template modify(); - k_eatom_pair.template sync(); + k_eatom_pair.sync_host(); for (int i = 0; i < n; i++) force->pair->eatom[i] += k_eatom_pair.h_view(i); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); k_vatom_pair.template modify(); - k_vatom_pair.template sync(); + k_vatom_pair.sync_host(); for (int i = 0; i < n; i++) { force->pair->vatom[i][0] += k_vatom_pair.h_view(i,0); force->pair->vatom[i][1] += k_vatom_pair.h_view(i,1); @@ -471,12 +472,12 @@ void DihedralCharmmfswKokkos::coeff(int narg, char **arg) k_weight.h_view[i] = weight[i]; } - k_k.template modify(); - k_multiplicity.template modify(); - k_shift.template modify(); - k_cos_shift.template modify(); - k_sin_shift.template modify(); - k_weight.template modify(); + k_k.modify_host(); + k_multiplicity.modify_host(); + k_shift.modify_host(); + k_cos_shift.modify_host(); + k_sin_shift.modify_host(); + k_weight.modify_host(); k_k.template sync(); k_multiplicity.template sync(); @@ -519,10 +520,10 @@ void DihedralCharmmfswKokkos::init_style() } } - k_lj14_1.template modify(); - k_lj14_2.template modify(); - k_lj14_3.template modify(); - k_lj14_4.template modify(); + k_lj14_1.modify_host(); + k_lj14_2.modify_host(); + k_lj14_3.modify_host(); + k_lj14_4.modify_host(); k_lj14_1.template sync(); k_lj14_2.template sync(); @@ -564,12 +565,12 @@ void DihedralCharmmfswKokkos::read_restart(FILE *fp) k_weight.h_view[i] = weight[i]; } - k_k.template modify(); - k_multiplicity.template modify(); - k_shift.template modify(); - k_cos_shift.template modify(); - k_sin_shift.template modify(); - k_weight.template modify(); + k_k.modify_host(); + k_multiplicity.modify_host(); + k_shift.modify_host(); + k_cos_shift.modify_host(); + k_sin_shift.modify_host(); + k_weight.modify_host(); k_k.template sync(); k_multiplicity.template sync(); diff --git a/src/KOKKOS/dihedral_charmmfsw_kokkos.h b/src/KOKKOS/dihedral_charmmfsw_kokkos.h index b1c65ae477..845d2192d7 100644 --- a/src/KOKKOS/dihedral_charmmfsw_kokkos.h +++ b/src/KOKKOS/dihedral_charmmfsw_kokkos.h @@ -67,6 +67,10 @@ class DihedralCharmmfswKokkos : public DihedralCharmmfsw { const F_FLOAT &evdwl, const F_FLOAT &ecoul, const F_FLOAT &fpair, const F_FLOAT &delx, const F_FLOAT &dely, const F_FLOAT &delz) const; + typedef typename KKDevice::value KKDeviceType; + Kokkos::DualView k_eatom; + Kokkos::DualView k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -76,10 +80,6 @@ class DihedralCharmmfswKokkos : public DihedralCharmmfsw { typename AT::t_ffloat_1d_randomread q; typename AT::t_f_array f; typename AT::t_int_2d dihedrallist; - - typedef typename KKDevice::value KKDeviceType; - Kokkos::DualView k_eatom; - Kokkos::DualView k_vatom; Kokkos::View > d_eatom; Kokkos::View > d_vatom; diff --git a/src/KOKKOS/dihedral_class2_kokkos.cpp b/src/KOKKOS/dihedral_class2_kokkos.cpp index 204a6d0d1a..83c03d856a 100644 --- a/src/KOKKOS/dihedral_class2_kokkos.cpp +++ b/src/KOKKOS/dihedral_class2_kokkos.cpp @@ -38,6 +38,7 @@ static constexpr double SMALL = 0.001; template DihedralClass2Kokkos::DihedralClass2Kokkos(LAMMPS *lmp) : DihedralClass2(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -137,7 +138,7 @@ void DihedralClass2Kokkos::compute(int eflag_in, int vflag_in) newton_bond = force->newton_bond; h_warning_flag() = 0; - k_warning_flag.template modify(); + k_warning_flag.modify_host(); k_warning_flag.template sync(); copymode = 1; @@ -163,7 +164,7 @@ void DihedralClass2Kokkos::compute(int eflag_in, int vflag_in) // error check k_warning_flag.template modify(); - k_warning_flag.template sync(); + k_warning_flag.sync_host(); if (h_warning_flag()) error->warning(FLERR,"Dihedral problem"); @@ -179,12 +180,12 @@ void DihedralClass2Kokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -786,44 +787,44 @@ void DihedralClass2Kokkos::coeff(int narg, char **arg) k_setflag_bb13t.h_view[i] = setflag_bb13t[i]; } - k_k1.template modify(); - k_k2.template modify(); - k_k3.template modify(); - k_phi1.template modify(); - k_phi2.template modify(); - k_phi3.template modify(); - k_mbt_f1.template modify(); - k_mbt_f2.template modify(); - k_mbt_f3.template modify(); - k_mbt_r0.template modify(); - k_ebt_f1_1.template modify(); - k_ebt_f2_1.template modify(); - k_ebt_f3_1.template modify(); - k_ebt_r0_1.template modify(); - k_ebt_f1_2.template modify(); - k_ebt_f2_2.template modify(); - k_ebt_f3_2.template modify(); - k_ebt_r0_2.template modify(); - k_at_f1_1.template modify(); - k_at_f2_1.template modify(); - k_at_f3_1.template modify(); - k_at_f1_2.template modify(); - k_at_f2_2.template modify(); - k_at_f3_2.template modify(); - k_at_theta0_1.template modify(); - k_at_theta0_2.template modify(); - k_aat_k.template modify(); - k_aat_theta0_1.template modify(); - k_aat_theta0_2.template modify(); - k_bb13t_k.template modify(); - k_bb13t_r10.template modify(); - k_bb13t_r30.template modify(); - k_setflag_d.template modify(); - k_setflag_mbt.template modify(); - k_setflag_ebt.template modify(); - k_setflag_at.template modify(); - k_setflag_aat.template modify(); - k_setflag_bb13t.template modify(); + k_k1.modify_host(); + k_k2.modify_host(); + k_k3.modify_host(); + k_phi1.modify_host(); + k_phi2.modify_host(); + k_phi3.modify_host(); + k_mbt_f1.modify_host(); + k_mbt_f2.modify_host(); + k_mbt_f3.modify_host(); + k_mbt_r0.modify_host(); + k_ebt_f1_1.modify_host(); + k_ebt_f2_1.modify_host(); + k_ebt_f3_1.modify_host(); + k_ebt_r0_1.modify_host(); + k_ebt_f1_2.modify_host(); + k_ebt_f2_2.modify_host(); + k_ebt_f3_2.modify_host(); + k_ebt_r0_2.modify_host(); + k_at_f1_1.modify_host(); + k_at_f2_1.modify_host(); + k_at_f3_1.modify_host(); + k_at_f1_2.modify_host(); + k_at_f2_2.modify_host(); + k_at_f3_2.modify_host(); + k_at_theta0_1.modify_host(); + k_at_theta0_2.modify_host(); + k_aat_k.modify_host(); + k_aat_theta0_1.modify_host(); + k_aat_theta0_2.modify_host(); + k_bb13t_k.modify_host(); + k_bb13t_r10.modify_host(); + k_bb13t_r30.modify_host(); + k_setflag_d.modify_host(); + k_setflag_mbt.modify_host(); + k_setflag_ebt.modify_host(); + k_setflag_at.modify_host(); + k_setflag_aat.modify_host(); + k_setflag_bb13t.modify_host(); } @@ -956,44 +957,44 @@ void DihedralClass2Kokkos::read_restart(FILE *fp) k_setflag_bb13t.h_view[i] = setflag_bb13t[i]; } - k_k1.template modify(); - k_k2.template modify(); - k_k3.template modify(); - k_phi1.template modify(); - k_phi2.template modify(); - k_phi3.template modify(); - k_mbt_f1.template modify(); - k_mbt_f2.template modify(); - k_mbt_f3.template modify(); - k_mbt_r0.template modify(); - k_ebt_f1_1.template modify(); - k_ebt_f2_1.template modify(); - k_ebt_f3_1.template modify(); - k_ebt_r0_1.template modify(); - k_ebt_f1_2.template modify(); - k_ebt_f2_2.template modify(); - k_ebt_f3_2.template modify(); - k_ebt_r0_2.template modify(); - k_at_f1_1.template modify(); - k_at_f2_1.template modify(); - k_at_f3_1.template modify(); - k_at_f1_2.template modify(); - k_at_f2_2.template modify(); - k_at_f3_2.template modify(); - k_at_theta0_1.template modify(); - k_at_theta0_2.template modify(); - k_aat_k.template modify(); - k_aat_theta0_1.template modify(); - k_aat_theta0_2.template modify(); - k_bb13t_k.template modify(); - k_bb13t_r10.template modify(); - k_bb13t_r30.template modify(); - k_setflag_d.template modify(); - k_setflag_mbt.template modify(); - k_setflag_ebt.template modify(); - k_setflag_at.template modify(); - k_setflag_aat.template modify(); - k_setflag_bb13t.template modify(); + k_k1.modify_host(); + k_k2.modify_host(); + k_k3.modify_host(); + k_phi1.modify_host(); + k_phi2.modify_host(); + k_phi3.modify_host(); + k_mbt_f1.modify_host(); + k_mbt_f2.modify_host(); + k_mbt_f3.modify_host(); + k_mbt_r0.modify_host(); + k_ebt_f1_1.modify_host(); + k_ebt_f2_1.modify_host(); + k_ebt_f3_1.modify_host(); + k_ebt_r0_1.modify_host(); + k_ebt_f1_2.modify_host(); + k_ebt_f2_2.modify_host(); + k_ebt_f3_2.modify_host(); + k_ebt_r0_2.modify_host(); + k_at_f1_1.modify_host(); + k_at_f2_1.modify_host(); + k_at_f3_1.modify_host(); + k_at_f1_2.modify_host(); + k_at_f2_2.modify_host(); + k_at_f3_2.modify_host(); + k_at_theta0_1.modify_host(); + k_at_theta0_2.modify_host(); + k_aat_k.modify_host(); + k_aat_theta0_1.modify_host(); + k_aat_theta0_2.modify_host(); + k_bb13t_k.modify_host(); + k_bb13t_r10.modify_host(); + k_bb13t_r30.modify_host(); + k_setflag_d.modify_host(); + k_setflag_mbt.modify_host(); + k_setflag_ebt.modify_host(); + k_setflag_at.modify_host(); + k_setflag_aat.modify_host(); + k_setflag_bb13t.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/dihedral_class2_kokkos.h b/src/KOKKOS/dihedral_class2_kokkos.h index 6e1dceb0cf..ddc79d21d9 100644 --- a/src/KOKKOS/dihedral_class2_kokkos.h +++ b/src/KOKKOS/dihedral_class2_kokkos.h @@ -60,6 +60,9 @@ class DihedralClass2Kokkos : public DihedralClass2 { const F_FLOAT &vb2x, const F_FLOAT &vb2y, const F_FLOAT &vb2z, const F_FLOAT &vb3x, const F_FLOAT &vb3y, const F_FLOAT &vb3z) const; + DAT::tdual_efloat_1d k_eatom; + DAT::tdual_virial_array k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -67,9 +70,6 @@ class DihedralClass2Kokkos : public DihedralClass2 { typename AT::t_x_array_randomread x; typename AT::t_f_array f; typename AT::t_int_2d dihedrallist; - - DAT::tdual_efloat_1d k_eatom; - DAT::tdual_virial_array k_vatom; typename AT::t_efloat_1d d_eatom; typename AT::t_virial_array d_vatom; diff --git a/src/KOKKOS/dihedral_opls_kokkos.cpp b/src/KOKKOS/dihedral_opls_kokkos.cpp index ce7502b25a..b45437b781 100644 --- a/src/KOKKOS/dihedral_opls_kokkos.cpp +++ b/src/KOKKOS/dihedral_opls_kokkos.cpp @@ -39,6 +39,7 @@ static constexpr double SMALLER = 0.00001; template DihedralOPLSKokkos::DihedralOPLSKokkos(LAMMPS *lmp) : DihedralOPLS(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -100,7 +101,7 @@ void DihedralOPLSKokkos::compute(int eflag_in, int vflag_in) newton_bond = force->newton_bond; h_warning_flag() = 0; - k_warning_flag.template modify(); + k_warning_flag.modify_host(); k_warning_flag.template sync(); copymode = 1; @@ -126,7 +127,7 @@ void DihedralOPLSKokkos::compute(int eflag_in, int vflag_in) // error check k_warning_flag.template modify(); - k_warning_flag.template sync(); + k_warning_flag.sync_host(); if (h_warning_flag()) error->warning(FLERR,"Dihedral problem"); @@ -142,12 +143,12 @@ void DihedralOPLSKokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -372,10 +373,10 @@ void DihedralOPLSKokkos::coeff(int narg, char **arg) k_k4.h_view[i] = k4[i]; } - k_k1.template modify(); - k_k2.template modify(); - k_k3.template modify(); - k_k4.template modify(); + k_k1.modify_host(); + k_k2.modify_host(); + k_k3.modify_host(); + k_k4.modify_host(); } /* ---------------------------------------------------------------------- @@ -395,10 +396,10 @@ void DihedralOPLSKokkos::read_restart(FILE *fp) k_k4.h_view[i] = k4[i]; } - k_k1.template modify(); - k_k2.template modify(); - k_k3.template modify(); - k_k4.template modify(); + k_k1.modify_host(); + k_k2.modify_host(); + k_k3.modify_host(); + k_k4.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/dihedral_opls_kokkos.h b/src/KOKKOS/dihedral_opls_kokkos.h index 886f4abcae..20c5083ad9 100644 --- a/src/KOKKOS/dihedral_opls_kokkos.h +++ b/src/KOKKOS/dihedral_opls_kokkos.h @@ -60,16 +60,15 @@ class DihedralOPLSKokkos : public DihedralOPLS { const F_FLOAT &vb2x, const F_FLOAT &vb2y, const F_FLOAT &vb2z, const F_FLOAT &vb3x, const F_FLOAT &vb3y, const F_FLOAT &vb3z) const; + DAT::tdual_efloat_1d k_eatom; + DAT::tdual_virial_array k_vatom; + protected: class NeighborKokkos *neighborKK; - typename AT::t_x_array_randomread x; typename AT::t_f_array f; typename AT::t_int_2d dihedrallist; - - DAT::tdual_efloat_1d k_eatom; - DAT::tdual_virial_array k_vatom; typename ArrayTypes::t_efloat_1d d_eatom; typename ArrayTypes::t_virial_array d_vatom; diff --git a/src/KOKKOS/improper_class2_kokkos.cpp b/src/KOKKOS/improper_class2_kokkos.cpp index 862ba2a52f..1aee9d2144 100644 --- a/src/KOKKOS/improper_class2_kokkos.cpp +++ b/src/KOKKOS/improper_class2_kokkos.cpp @@ -34,6 +34,7 @@ static constexpr double SMALL = 0.001; template ImproperClass2Kokkos::ImproperClass2Kokkos(LAMMPS *lmp) : ImproperClass2(lmp) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; @@ -110,7 +111,7 @@ void ImproperClass2Kokkos::compute(int eflag_in, int vflag_in) newton_bond = force->newton_bond; h_warning_flag() = 0; - k_warning_flag.template modify(); + k_warning_flag.modify_host(); k_warning_flag.template sync(); copymode = 1; @@ -139,7 +140,7 @@ void ImproperClass2Kokkos::compute(int eflag_in, int vflag_in) // error check k_warning_flag.template modify(); - k_warning_flag.template sync(); + k_warning_flag.sync_host(); if (h_warning_flag()) error->warning(FLERR,"Improper problem"); @@ -171,12 +172,12 @@ void ImproperClass2Kokkos::compute(int eflag_in, int vflag_in) if (eflag_atom) { k_eatom.template modify(); - k_eatom.template sync(); + k_eatom.sync_host(); } if (vflag_atom) { k_vatom.template modify(); - k_vatom.template sync(); + k_vatom.sync_host(); } copymode = 0; @@ -918,17 +919,17 @@ void ImproperClass2Kokkos::coeff(int narg, char **arg) k_setflag_aa.h_view[i] = setflag_aa[i]; } - k_k0.template modify(); - k_chi0.template modify(); - k_aa_k1.template modify(); - k_aa_k2.template modify(); - k_aa_k3.template modify(); - k_aa_theta0_1.template modify(); - k_aa_theta0_2.template modify(); - k_aa_theta0_3 .template modify(); - k_setflag.template modify(); - k_setflag_i.template modify(); - k_setflag_aa.template modify(); + k_k0.modify_host(); + k_chi0.modify_host(); + k_aa_k1.modify_host(); + k_aa_k2.modify_host(); + k_aa_k3.modify_host(); + k_aa_theta0_1.modify_host(); + k_aa_theta0_2.modify_host(); + k_aa_theta0_3 .modify_host(); + k_setflag.modify_host(); + k_setflag_i.modify_host(); + k_setflag_aa.modify_host(); } /* ---------------------------------------------------------------------- @@ -979,17 +980,17 @@ void ImproperClass2Kokkos::read_restart(FILE *fp) k_setflag_aa.h_view[i] = setflag_aa[i]; } - k_k0.template modify(); - k_chi0.template modify(); - k_aa_k1.template modify(); - k_aa_k2.template modify(); - k_aa_k3.template modify(); - k_aa_theta0_1.template modify(); - k_aa_theta0_2.template modify(); - k_aa_theta0_3 .template modify(); - k_setflag.template modify(); - k_setflag_i.template modify(); - k_setflag_aa.template modify(); + k_k0.modify_host(); + k_chi0.modify_host(); + k_aa_k1.modify_host(); + k_aa_k2.modify_host(); + k_aa_k3.modify_host(); + k_aa_theta0_1.modify_host(); + k_aa_theta0_2.modify_host(); + k_aa_theta0_3 .modify_host(); + k_setflag.modify_host(); + k_setflag_i.modify_host(); + k_setflag_aa.modify_host(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/improper_class2_kokkos.h b/src/KOKKOS/improper_class2_kokkos.h index da939b69b0..7a55c8a5f8 100644 --- a/src/KOKKOS/improper_class2_kokkos.h +++ b/src/KOKKOS/improper_class2_kokkos.h @@ -71,6 +71,9 @@ class ImproperClass2Kokkos : public ImproperClass2 { const F_FLOAT &vb2x, const F_FLOAT &vb2y, const F_FLOAT &vb2z, const F_FLOAT &vb3x, const F_FLOAT &vb3y, const F_FLOAT &vb3z) const; + DAT::tdual_efloat_1d k_eatom; + DAT::tdual_virial_array k_vatom; + protected: class NeighborKokkos *neighborKK; @@ -78,9 +81,6 @@ class ImproperClass2Kokkos : public ImproperClass2 { typename AT::t_x_array_randomread x; typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d improperlist; - - DAT::tdual_efloat_1d k_eatom; - DAT::tdual_virial_array k_vatom; typename AT::t_efloat_1d d_eatom; typename AT::t_virial_array d_vatom; From a8c7ebf47d4dea62eb547b0cf5025f362221ff89 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jun 2024 14:17:20 -0400 Subject: [PATCH 130/385] must use the "roots" communicator only on world->me == 0 Thanks to @joshuakempfert. See issue #4210 --- src/REPLICA/neb.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/REPLICA/neb.cpp b/src/REPLICA/neb.cpp index d9144a9489..4023f2c0b3 100644 --- a/src/REPLICA/neb.cpp +++ b/src/REPLICA/neb.cpp @@ -198,7 +198,7 @@ void NEB::run() if (me == 0) color = 0; else - color = 1; + color = MPI_UNDEFINED; MPI_Comm_split(uworld, color, 0, &roots); auto fixes = modify->get_fix_by_style("^neb$"); @@ -608,17 +608,20 @@ void NEB::open(char *file) void NEB::print_status() { double fnorm2 = sqrt(update->minimize->fnorm_sqr()); - double fmaxreplica; - MPI_Allreduce(&fnorm2, &fmaxreplica, 1, MPI_DOUBLE, MPI_MAX, roots); double fnorminf = update->minimize->fnorm_inf(); - double fmaxatom; - MPI_Allreduce(&fnorminf, &fmaxatom, 1, MPI_DOUBLE, MPI_MAX, roots); + double fmaxreplica = 0.0; + double fmaxatom = 0.0; - if (print_mode == VERBOSE) { - freplica = new double[nreplica]; - MPI_Allgather(&fnorm2, 1, MPI_DOUBLE, &freplica[0], 1, MPI_DOUBLE, roots); - fmaxatomInRepl = new double[nreplica]; - MPI_Allgather(&fnorminf, 1, MPI_DOUBLE, &fmaxatomInRepl[0], 1, MPI_DOUBLE, roots); + if (me == 0) { + MPI_Allreduce(&fnorm2, &fmaxreplica, 1, MPI_DOUBLE, MPI_MAX, roots); + MPI_Allreduce(&fnorminf, &fmaxatom, 1, MPI_DOUBLE, MPI_MAX, roots); + + if (print_mode == VERBOSE) { + freplica = new double[nreplica]; + MPI_Allgather(&fnorm2, 1, MPI_DOUBLE, &freplica[0], 1, MPI_DOUBLE, roots); + fmaxatomInRepl = new double[nreplica]; + MPI_Allgather(&fnorminf, 1, MPI_DOUBLE, &fmaxatomInRepl[0], 1, MPI_DOUBLE, roots); + } } double one[7]; @@ -703,7 +706,7 @@ void NEB::print_status() fflush(universe->ulogfile); } } - if (print_mode == VERBOSE) { + if ((me == 0) && (print_mode == VERBOSE)) { delete[] freplica; delete[] fmaxatomInRepl; } From 8397738978dd22e33209b4b3b99726292f98c535 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jun 2024 18:32:12 -0400 Subject: [PATCH 131/385] add explanation about integrating new styles into packages --- doc/src/Developer_write_pair.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/src/Developer_write_pair.rst b/doc/src/Developer_write_pair.rst index d70f8ec50b..c286b9e1dd 100644 --- a/doc/src/Developer_write_pair.rst +++ b/doc/src/Developer_write_pair.rst @@ -50,6 +50,30 @@ We are looking at the following cases: - `Case 3: a potential requiring communication`_ - `Case 4: potentials without a compute() function`_ +Package and build system considerations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In general, new pair styles should be added to the :ref:`EXTRA-PAIR +package ` unless they are an accelerated pair style and +then they should be added to the corresponding accelerator package +(:ref:`GPU `, :ref:`INTEL `, :ref:`KOKKOS +`, :ref:`OPENMP `, :ref:`OPT `). If +you feel that your contribution should be added to a different package, +please consult with the LAMMPS developers first. + +The contributed code needs to support the :doc:`traditional GNU make +build process ` **and** the :doc:`CMake build process +`. For the GNU make process and if the package has an +``Install.sh`` file, most likely that file needs to be updated to +correctly copy the sources when installing the package and properly +delete them when uninstalling. This is particularly important when +added a new pair style that is a derived class from an existing pair +style in a package, so that its installation depends on the the +installation status of the package of the derived class. For the CMake +process, it is sometimes necessary to make changes to the package +specific CMake scripting in ``cmake/Modules/Packages``. + + ---- Case 1: a pairwise additive model From 1326592f237b86730b9988f7ba1dde5733979c12 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 28 Jun 2024 17:07:23 -0600 Subject: [PATCH 132/385] Proofing RHEO package --- doc/src/Commands_fix.rst | 1 + doc/src/Howto_rheo.rst | 38 +- doc/src/atom_style.rst | 2 +- doc/src/bond_rheo_shell.rst | 47 +- doc/src/bond_style.rst | 1 + doc/src/compute_rheo_property_atom.rst | 43 +- doc/src/fix.rst | 6 +- doc/src/fix_add_heat.rst | 36 +- doc/src/fix_rheo.rst | 74 +- doc/src/fix_rheo_oxidation.rst | 21 +- doc/src/fix_rheo_pressure.rst | 14 +- doc/src/fix_rheo_thermal.rst | 20 +- doc/src/fix_rheo_viscosity.rst | 12 +- doc/src/pair_rheo.rst | 36 +- doc/src/pair_rheo_solid.rst | 6 +- doc/src/pair_style.rst | 2 + examples/rheo/balloon/in.rheo.balloon | 2 +- .../rheo/balloon/log.17Apr2024.balloon.g++.4 | 382 ++++ .../rheo/dam-break/log.17Apr2024.dam.g++.4 | 1694 +++++++++++++++++ examples/rheo/ice-cubes/in.rheo.ice.cubes | 3 +- .../rheo/ice-cubes/log.17Apr2024.ice.g++.4 | 379 ++++ examples/rheo/oxidation/in.rheo.oxidation | 3 +- .../oxidation/log.17Apr2024.oxidation.g++.4 | 488 +++++ examples/rheo/poiseuille/in.rheo.poiseuille | 2 +- .../poiseuille/log.17Apr2024.poiseuille.g++.4 | 288 +++ .../log.17Apr2024.taylor.green.g++.4 | 224 +++ src/BPM/bond_bpm_spring.cpp | 2 - src/BPM/compute_nbond_atom.cpp | 2 +- src/BPM/fix_update_special_bonds.cpp | 2 +- src/RHEO/bond_rheo_shell.cpp | 13 +- src/RHEO/compute_rheo_kernel.cpp | 184 +- src/RHEO/compute_rheo_kernel.h | 2 +- src/RHEO/compute_rheo_surface.cpp | 4 +- src/RHEO/fix_rheo.cpp | 47 +- src/RHEO/fix_rheo.h | 2 +- src/RHEO/fix_rheo_oxidation.cpp | 6 +- src/RHEO/fix_rheo_thermal.cpp | 23 +- src/RHEO/fix_rheo_viscosity.cpp | 1 + src/RHEO/pair_rheo.cpp | 36 +- src/RHEO/pair_rheo.h | 4 +- 40 files changed, 3797 insertions(+), 355 deletions(-) create mode 100644 examples/rheo/balloon/log.17Apr2024.balloon.g++.4 create mode 100644 examples/rheo/dam-break/log.17Apr2024.dam.g++.4 create mode 100644 examples/rheo/ice-cubes/log.17Apr2024.ice.g++.4 create mode 100644 examples/rheo/oxidation/log.17Apr2024.oxidation.g++.4 create mode 100644 examples/rheo/poiseuille/log.17Apr2024.poiseuille.g++.4 create mode 100644 examples/rheo/taylor-green/log.17Apr2024.taylor.green.g++.4 diff --git a/doc/src/Commands_fix.rst b/doc/src/Commands_fix.rst index f2771f0c50..4350a98b31 100644 --- a/doc/src/Commands_fix.rst +++ b/doc/src/Commands_fix.rst @@ -28,6 +28,7 @@ OPT. * :doc:`adapt ` * :doc:`adapt/fep ` * :doc:`addforce ` + * :doc:`add/heat ` * :doc:`addtorque ` * :doc:`alchemy ` * :doc:`amoeba/bitorsion ` diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index 9d70bf074f..4c0f069d92 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -2,8 +2,9 @@ Reproducing hydrodynamics and elastic objects (RHEO) ==================================================== The RHEO package is a hybrid implementation of smoothed particle -hydrodynamics (SPH) for fluid flow, coupled to the :doc:`BPM package ` to model -solid elements. RHEO combines these methods to enable mesh-free modeling of multiphase material systems. The SPH solver supports many advanced options +hydrodynamics (SPH) for fluid flow, coupled to the :doc:`BPM package ` +to model solid elements. RHEO combines these methods to enable mesh-free modeling +of multiphase material systems. The SPH solver supports many advanced options including reproducing kernels, particle shifting, free surface identification, and solid surface reconstruction. To model fluid-solid systems, the status of particles can dynamically change between a fluid and solid state, e.g. during @@ -29,9 +30,10 @@ of reproducing kernels). In conjunction to fix rheo, one must specify an instance of :doc:`fix rheo/pressure ` and :doc:`fix rheo/viscosity ` to define a pressure equation of state and viscosity model, respectively. Optionally, one can model -a heat equation with :doc:`fix rheo/thermal`, which also allows the user -to specify equations for a particle's thermal conductivity, specific heat, -latent heat, and melting temperature. The ordering of these fixes in an an input script matters. Fix rheo must be defined prior to all +a heat equation with :doc:`fix rheo/thermal `, which also +allows the user to specify equations for a particle's thermal conductivity, +specific heat, latent heat, and melting temperature. The ordering of these +fixes in an an input script matters. Fix rheo must be defined prior to all other RHEO fixes. Typically, RHEO requires atom style rheo. In addition to typical atom @@ -45,9 +47,9 @@ affect particles. Instead, one should use the *sph/e* attribute. The status variable uses bitmasking to track various properties of a particle such as its current state of matter (fluid or solid) and its location relative to a surface. Some of these properties (and others) can be accessed using -:doc:`compute rheo/property/atom `. The *status* attribute -in :doc:`the set command ` only allows control over the first bit which sets -the state of matter, 0 is fluid and 1 is solid. +:doc:`compute rheo/property/atom `. The *status* +attribute in :doc:`the set command ` only allows control over the first bit +which sets the state of matter, 0 is fluid and 1 is solid. Fluid interactions, including pressure forces, viscous forces, and heat exchange, are calculated using :doc:`pair rheo `. Unlike typical pair styles, @@ -59,18 +61,18 @@ hydrodynamic forces are only calculated if a fluid particle is involved. To model elastic objects, there are currently two mechanisms in RHEO, one designed for bulk solid bodies and the other for thin shells. Both mechanisms rely on -introducing bonded forces between particles and therefore require a hybrid of atom style bond and rheo -(or rheo/thermal). +introducing bonded forces between particles and therefore require a hybrid of atom +style bond and rheo (or rheo/thermal). To create an elastic solid body, one has to (a) change the status of constituent particles to solid (e.g. with the :doc:`set ` command), (b) create bpm bonds between the particles (see the :doc:`bpm howto ` page for more details), and (c) use :doc:`pair rheo/solid ` to apply repulsive contact forces between distinct solid bodies. Akin to pair rheo, -looks at a particles fluid/solid status to determine whether to apply forces. -However, unlike pair rheo, pair rheo/solid does obey special bond settings such -that contact forces do not have to be calculated between two bonded solid particles -in the same elastic body. +pair rheo/solid considers a particles fluid/solid phase to determine whether to +apply forces. However, unlike pair rheo, pair rheo/solid does obey special bond +settings such that contact forces do not have to be calculated between two bonded +solid particles in the same elastic body. In systems with thermal evolution, fix rheo/thermal can optionally set a melting/solidification temperature allowing particles to dynamically swap their @@ -79,9 +81,9 @@ critical temperature, respectively. Using the *react* option, one can specify a bond length and a bond type. Then, when solidifying, particles will search their local neighbors and automatically create bonds with any neighboring solid particles in range. For BPM bond styles, bonds will then use the immediate position of the two -particles to calculate a reference state. When melting, particles will then delete -any bonds of the specified type when reverting to a fluid state. Special bonds are -updated as bonds are created/broken. +particles to calculate a reference state. When melting, particles will delete any +bonds of the specified type when reverting to a fluid state. Special bonds are updated +as bonds are created/broken. The other option for elastic objects is an elastic shell that is nominally much thinner than a particle diameter, e.g. a oxide skin which gradually forms over time @@ -106,7 +108,7 @@ criteria for creating/deleting a bond or altering force calculations). .. _howto_rheo_palermo: -**(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. +**(Palermo)** Palermo, Wolf, Clemmer, O'Connor, in preparation. .. _howto_rheo_clemmer: diff --git a/doc/src/atom_style.rst b/doc/src/atom_style.rst index 0a3cb642be..2e6a6e1cbe 100644 --- a/doc/src/atom_style.rst +++ b/doc/src/atom_style.rst @@ -194,7 +194,7 @@ the Additional Information section below. - :ref:`RHEO ` - solid and fluid RHEO particles * - *rheo/thermal* - - *atomic* + rho, status, temperature + - *atomic* + rho, status, energy, temperature - :ref:`RHEO ` - RHEO particles with temperature * - *sph* diff --git a/doc/src/bond_rheo_shell.rst b/doc/src/bond_rheo_shell.rst index 3b5cfa6a49..439f88ec8e 100644 --- a/doc/src/bond_rheo_shell.rst +++ b/doc/src/bond_rheo_shell.rst @@ -44,12 +44,11 @@ The *rheo/shell* bond style is designed to work with :doc:`fix rheo/oxidation ` which creates candidate bonds between eligible surface or near-surface particles. When a bond is first created, it computes no forces and starts a timer. Forces are -not computed until the timer reaches the specified bond formation time -and the bond is fully enabled. If the two particles move outside of the -maximum bond distance or move into the bulk before the timer reaches -the formation time, the bond automatically deletes itself. Not that -this deletion does not generate any broken bond data saved to a -*store/local* fix. +not computed until the timer reaches the specified bond formation time, +*t/form*, and the bond is enabled and applies forces. If the two particles +move outside of the maximum bond distance or move into the bulk before +the timer reaches *t/form*, the bond automatically deletes itself. This +deletion is not recorded as a broken bond in the optional *store/local* fix. Before bonds are enabled, they are still treated as regular bonds by all other parts of LAMMPS. This means they are written to data files @@ -60,17 +59,17 @@ To only count enabled bonds, use the *nbond/shell* attribute in When enabled, the bond then computes forces based on deviations from the initial reference state of the two atoms much like a BPM style bond (as further discussed in the :doc:`BPM howto page `). -The reference state is stored by each bond when it is first enabled -the setup of a run. Data is then preserved across run commands and is -written to :doc:`binary restart files ` such that restarting -the system will not reset the reference state of a bond or the timer. +The reference state is stored by each bond when it is first enabled. +Data is then preserved across run commands and is written to +:doc:`binary restart files ` such that restarting the system +will not reset the reference state of a bond or the timer. This bond style is based on a model described in -:ref:`(Clemmer) `. The force has a magnitude of +:ref:`(Clemmer) `. The force has a magnitude of .. math:: - F = 2 k (r - r_0) + \frac{2 * k}{r_0^2 \epsilon_c^2} (r - r_0)^3 + F = 2 k (r - r_0) + \frac{2 k}{r_0^2 \epsilon_c^2} (r - r_0)^3 where :math:`k` is a stiffness, :math:`r` is the current distance and :math:`r_0` is the initial distance between the two particles, and @@ -78,17 +77,15 @@ and :math:`r_0` is the initial distance between the two particles, and is done by setting the bond type to 0 such that forces are no longer computed. -An additional damping force is applied to the bonded -particles. This forces is proportional to the difference in the -normal velocity of particles using a similar construction as -dissipative particle dynamics :ref:`(Groot) `: +A damping force proportional to the difference in the normal velocity +of particles is also applied to bonded particles: .. math:: F_D = - \gamma w (\hat{r} \bullet \vec{v}) where :math:`\gamma` is the damping strength, :math:`\hat{r}` is the -radial normal vector, and :math:`\vec{v}` is the velocity difference +displacement normal vector, and :math:`\vec{v}` is the velocity difference between the two particles. The following coefficients must be defined for each bond type via the @@ -103,7 +100,7 @@ the data file or restart files read by the :doc:`read_data Unlike other BPM-style bonds, this bond style does not update special bond settings when bonds are created or deleted. This bond style also does not enforce specific :doc:`special_bonds ` settings. -This behavior is purposeful such :doc:`RHEO pair forces ` +This behavior is purposeful such :doc:`RHEO pair ` forces and heat flows are still calculated. If the *store/local* keyword is used, an internal fix will track bonds that @@ -162,10 +159,10 @@ the specified attribute. The single() function of this bond style returns 0.0 for the energy of a bonded interaction, since energy is not conserved in these -dissipative potentials. The single() function also calculates an -extra bond quantity, the initial distance :math:`r_0`. This -extra quantity can be accessed by the -:doc:`compute bond/local ` command as *b1*\ . +dissipative potentials. The single() function also calculates two +extra bond quantities, the initial distance :math:`r_0` and a time. +These extra quantities can be accessed by the +:doc:`compute bond/local ` command as *b1* and *b2*\ . Restrictions """""""""""" @@ -186,10 +183,6 @@ NA ---------- -.. _howto_rheo_clemmer: +.. _rheo_clemmer: **(Clemmer)** Clemmer, Pierce, O'Connor, Nevins, Jones, Lechman, Tencer, Appl. Math. Model., 130, 310-326 (2024). - -.. _Groot4: - -**(Groot)** Groot and Warren, J Chem Phys, 107, 4423-35 (1997). diff --git a/doc/src/bond_style.rst b/doc/src/bond_style.rst index 95f463e695..da56fe7fbb 100644 --- a/doc/src/bond_style.rst +++ b/doc/src/bond_style.rst @@ -105,6 +105,7 @@ accelerated styles exist. * :doc:`oxdna2/fene ` - same as oxdna but used with different pair styles * :doc:`oxrna2/fene ` - modified FENE bond suitable for RNA modeling * :doc:`quartic ` - breakable quartic bond +* :doc:`rheo/shell ` - shell bond for oxidation modeling in RHEO * :doc:`special ` - enable special bond exclusions for 1-5 pairs and beyond * :doc:`table ` - tabulated by bond length diff --git a/doc/src/compute_rheo_property_atom.rst b/doc/src/compute_rheo_property_atom.rst index 861fd04688..f34b2225f5 100644 --- a/doc/src/compute_rheo_property_atom.rst +++ b/doc/src/compute_rheo_property_atom.rst @@ -1,7 +1,7 @@ .. index:: compute rheo/property/atom compute rheo/property/atom command -============================= +================================== Syntax """""" @@ -17,11 +17,10 @@ Syntax .. parsed-literal:: possible attributes = phase, surface, surface/r, - surface/divr, surface/n/:math:`\alpha`, coordination, - shift/v/:math:`\alpha`, energy, temperature, heatflow, + surface/divr, surface/n/a, coordination, + shift/v/a, energy, temperature, heatflow, conductivity, cv, viscosity, pressure, rho, - grad/v/:math:`\alpha \beta`, stress/v/:math:`\alpha \beta`, - stress/t/:math:`\alpha \beta`, nbond/shell + grad/v/ab, stress/v/ab, stress/t/ab, nbond/shell .. parsed-literal:: @@ -29,9 +28,9 @@ Syntax *surface* = atom surface status *surface/r* = atom distance from the surface *surface/divr* = divergence of position at atom position - *surface/n/:math:`\alpha`* = surface normal vector + *surface/n/a* = a-component of surface normal vector *coordination* = coordination number - *shift/v/:math:`\alpha`* = atom shifting velocity + *shift/v/a* = a-component of atom shifting velocity *energy* = atom energy *temperature* = atom temperature *heatflow* = atom heat flow @@ -40,9 +39,9 @@ Syntax *viscosity* = atom viscosity *pressure* = atom pressure *rho* = atom density - *grad/v/:math:`\alpha \beta`* = atom velocity gradient - *stress/v/:math:`\alpha \beta`* = atom viscous stress - *stress/t/:math:`\alpha \beta`* = atom total stress (pressure and viscous) + *grad/v/ab* = ab-component of atom velocity gradient tensor + *stress/v/ab* = ab-component of atom viscous stress tensor + *stress/t/ab* = ab-component of atom total stress tensor (pressure and viscous) *nbond/shell* = number of oxide bonds Examples @@ -68,12 +67,12 @@ computes as inputs. See for example, the :doc:`fix ave/chunk `, and :doc:`atom-style variable ` commands. -For vector attributes, e.g. *shift/v/:math:`\alpha`*, one must specify +For vector attributes, e.g. *shift/v/*:math:`\alpha`, one must specify :math:`\alpha` as the *x*, *y*, or *z* component, e.g. *shift/v/x*. Alternatively, a wild card \* will include all components, *x* and *y* in 2D or *x*, *y*, and *z* in 3D. -For tensor attributes, e.g. *grad/v/:math:`\alpha \beta`*, one must specify +For tensor attributes, e.g. *grad/v/*:math:`\alpha \beta`, one must specify both :math:`\alpha` and :math:`\beta` as *x*, *y*, or *z*, e.g. *grad/v/xy*. Alternatively, a wild card \* will include all components. In 2D, this includes *xx*, *xy*, *yx*, and *yy*. In 3D, this includes *xx*, *xy*, *xz*, @@ -93,11 +92,11 @@ the *interface/reconstruct* option of :doc:`fix rheo `. Bulk particles have a value of 0, surface particles have a value of 1, and splash particles have a value of 2. The *surface/r* property is the distance from the surface, up to the kernel cutoff length. Surface particles -have a value of 0. The *surface/n* properties are the components of the -surface normal vector. +have a value of 0. The *surface/n/*:math:`\alpha` properties are the +components of the surface normal vector. -The *shift/v/:math:`\alpha`* properties are the components of the shifting velocity -produced by the *shift* option of :doc:`fix rheo `. +The *shift/v/*:math:`\alpha` properties are the components of the shifting +velocity produced by the *shift* option of :doc:`fix rheo `. The *nbond/shell* property is the number of shell bonds that have been activated from :doc:`bond style rheo/shell `. @@ -110,13 +109,13 @@ Output info """"""""""" This compute calculates a per-atom vector or per-atom array depending -on the number of input values. If a single input is specified, a -per-atom vector is produced. If two or more inputs are specified, a +on the number of input values. Generally, if a single input is specified, +a per-atom vector is produced. If two or more inputs are specified, a per-atom array is produced where the number of columns = the number of -inputs. If a wild card \* is used for a vector or tensor, then the number -of inputs is considered to be incremented by the dimensiod or dimension -squared, respectively. The vector or array can be accessed by any command -that uses per-atom values from a compute as input. See the +inputs. However, if a wild card \* is used for a vector or tensor, then +the number of inputs is considered to be incremented by the dimension or +the dimension squared, respectively. The vector or array can be accessed +by any command that uses per-atom values from a compute as input. See the :doc:`Howto output ` page for an overview of LAMMPS output options. diff --git a/doc/src/fix.rst b/doc/src/fix.rst index 42f7bcff6b..4919c226fd 100644 --- a/doc/src/fix.rst +++ b/doc/src/fix.rst @@ -193,6 +193,7 @@ accelerated styles exist. * :doc:`adapt ` - change a simulation parameter over time * :doc:`adapt/fep ` - enhanced version of fix adapt * :doc:`addforce ` - add a force to each atom +* :doc:`add/heat ` - add a heat flux to each atom * :doc:`addtorque ` - add a torque to a group of atoms * :doc:`alchemy ` - perform an "alchemical transformation" between two partitions * :doc:`amoeba/bitorsion ` - torsion/torsion terms in AMOEBA force field @@ -371,8 +372,9 @@ accelerated styles exist. * :doc:`restrain ` - constrain a bond, angle, dihedral * :doc:`rheo ` - integrator for the RHEO package * :doc:`rheo/thermal ` - thermal integrator for the RHEO package -* :doc:`rheo/pressure ` - pressure derivation for the RHEO package -* :doc:`rheo/viscosity ` - viscosity derivation for the RHEO package +* :doc:`rheo/oxidation ` - create oxidation bonds for the RHEO package +* :doc:`rheo/pressure ` - pressure calculation for the RHEO package +* :doc:`rheo/viscosity ` - viscosity calculation for the RHEO package * :doc:`rhok ` - add bias potential for long-range ordered systems * :doc:`rigid ` - constrain one or more clusters of atoms to move as a rigid body with NVE integration * :doc:`rigid/meso ` - constrain clusters of mesoscopic SPH/SDPD particles to move as a rigid body diff --git a/doc/src/fix_add_heat.rst b/doc/src/fix_add_heat.rst index 2a2d855927..5b67bd4e15 100644 --- a/doc/src/fix_add_heat.rst +++ b/doc/src/fix_add_heat.rst @@ -16,14 +16,14 @@ Syntax .. parsed-literal:: - *constant* args = rate - rate = rate of heat flow (energy/time units) - *linear* args = t_target k - t_target = target temperature (temperature units) - k = prefactor (energy/(time*temperature) units) - *quartic* args = t_target k - t_target = target temperature (temperature units) - k = prefactor (energy/(time*temperature^4) units) + *constant* args = *rate* + *rate* = rate of heat flow (energy/time units) + *linear* args = :math:`T_{target}` *k* + :math:`T_{target}` = target temperature (temperature units) + *k* = prefactor (energy/(time*temperature) units) + *quartic* args = :math:`T_{target}` *k* + :math:`T_{target}` = target temperature (temperature units) + *k* = prefactor (energy/(time*temperature^4) units) * zero or more keyword/value pairs may be appended to args * keyword = *overwrite* @@ -45,7 +45,9 @@ Examples Description """"""""""" -This fix adds heat to particles every timestep. +This fix adds heat to particles with the temperature attribute every timestep. +Note that this is an internal temperature of a particle intended for use with +non-atomistic models like the discrete element method. For the *constant* style, heat is added at the specified rate. For the *linear* style, heat is added at a rate of :math:`k (T_{target} - T)` where :math:`k` is the @@ -62,22 +64,22 @@ determine the rate of heat added. Equal-style variables can specify formulas with various mathematical functions and include :doc:`thermo_style ` command -keywords for the simulation box parameters, time step, and elapsed time. -Thus, it is easy to specify time-dependent heating. +keywords for the simulation box parameters, time step, and elapsed time +to specify time-dependent heating. Atom-style variables can specify the same formulas as equal-style variables but can also include per-atom values, such as atom -coordinates. Thus, it is easy to specify a spatially-dependent heating -field with optional time-dependence as well. +coordinates to specify spatially-dependent heating. -If the *overwrite* keyword is set to *yes*, this fix will effectively set -the total heat flow on a particle, overwriting contributions from pair -styles or other fixes. +If the *overwrite* keyword is set to *yes*, this fix will set the total +heat flow on a particle every timestep, overwriting contributions from pair +styles or other fixes. If *overwrite* is *no*, this fix will add heat on +top of other contributions. ---------- Restart, fix_modify, output, run start/stop, minimize info -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index 978691db41..d69b52d751 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -1,7 +1,7 @@ .. index:: fix rheo fix rheo command -=============== +================ Syntax """""" @@ -38,8 +38,8 @@ Examples .. code-block:: LAMMPS - fix 1 all rheo 1.0 quintic thermal density 0.1 speed/sound 10.0 - fix 1 all rheo 1.0 RK1 shift surface/detection coordination 40 + fix 1 all rheo 3.0 quintic 0 thermal density 0.1 0.1 speed/sound 10.0 1.0 + fix 1 all rheo 3.0 RK1 10 shift surface/detection coordination 40 Description """"""""""" @@ -48,14 +48,15 @@ Description Perform time integration for RHEO particles, updating positions, velocities, and densities. For a detailed breakdown of the integration timestep and -numerical details, see :ref:`(Palermo) `. For an +numerical details, see :ref:`(Palermo) `. For an overview of other features available in the RHEO package, see :doc:`the RHEO howto `. The type of kernel is specified using *kstyle* and the cutoff is *cut*. Four kernels are currently available. The *quintic* kernel is a standard quintic spline function commonly used in SPH. The other options, *RK0*, *RK1*, and -*RK2*, are zeroth, first, and second order reproducing. To generate a reproducing kernel, a particle must have sufficient neighbors inside the +*RK2*, are zeroth, first, and second order reproducing. To generate a +reproducing kernel, a particle must have sufficient neighbors inside the kernel cutoff distance (a coordination number) to accurately calculate moments. This threshold is set by *zmin*. If reproducing kernels are requested but a particle has fewer neighbors, then it will revert to a @@ -81,28 +82,27 @@ surfaces. A modified form of Fickian particle shifting can be enabled with the *shift* keyword. This effectively shifts particle positions to generate a -more uniform spatial distribution. Shifting currently does consider the +more uniform spatial distribution. Shifting currently does not consider the type of a particle and therefore may be inappropriate in systems consisting -of multiple materials. +of multiple fluid phases. In systems with free surfaces, the *surface/detection* keyword can be used to classify the location of particles as being within the bulk fluid, on a free surface, or isolated from other particles in a splash or droplet. -Shifting is then disabled in the direction away from the free surface to -prevent it from diffusing particles away from the bulk fluid. Surface -detection can also be used to control surface-nucleated effects like -oxidation when used in combination with -:doc:`fix rheo/oxidation `. Surface detection is not +Shifting is then disabled in the normal direction away from the free surface +to prevent particles from difusing away. Surface detection can also be used +to control surface-nucleated effects like oxidation when used in combination +with :doc:`fix rheo/oxidation `. Surface detection is not performed on solid bodies. The *surface/detection* keyword takes three arguments: *sdstyle*, *limit*, -and *limi/splash*. The first, *sdstyle*, specifies whether surface particles +and *limit/splash*. The first, *sdstyle*, specifies whether surface particles are identified using a coordination number (*coordination*) or the divergence of the local particle positions (*divergence*). The threshold value for a surface particle for either of these criteria is set by the numerical value of *limit*. Additionally, if a particle's coordination number is too low, i.e. if it has separated off from the bulk in a droplet, it is not possible -to define surfaces and a particle is classified as a splash. The coordination +to define surfaces and the particle is classified as a splash. The coordination threshold for this classification is set by the numerical value of *limit/splash*. @@ -112,23 +112,23 @@ a kernel summation of the masses of neighboring particles by specifying the *rho keyword. The *self/mass* keyword modifies the behavior of the density summation in *rho/sum*. -Typically, the density :math:`\rho` of a particle is calculated as the sum +Typically, the density :math:`\rho` of a particle is calculated as the sum over neighbors .. math:: - \rho_i = \Sum_{j} W_{ij} M_j + \rho_i = \sum_{j} W_{ij} M_j -where the summation is over neighbors, :math:`W_{ij}` is the kernel, and :math:`M_j` -is the mass of particle :math:`j`. The *self/mass* keyword augments this expression -by replacing :math:`M_j` with :math:`M_i`. This may be useful in simulations of -multiple fluid phases with large differences in density, :ref:`(Hu) `. +where :math:`W_{ij}` is the kernel, and :math:`M_j` is the mass of particle :math:`j`. +The *self/mass* keyword augments this expression by replacing :math:`M_j` with +:math:`M_i`. This may be useful in simulations of multiple fluid phases with large +differences in density, :ref:`(Hu) `. -The *density* keyword is used to specify the equilbrium density of each of the N -particle types. It must be followed by N numerical values specifying each -type's equilibrium density *rho0*. +The *density* keyword is used to specify the equilibrium density of each of the N +particle types. It must be followed by N numerical values specifying each type's +equilibrium density *rho0*. The *speed/sound* keyword is used to specify the speed of sound of each of the -N particle types. It must be followed by N numerical values specifying each -type's speed of sound *cs*. +N particle types. It must be followed by N numerical values specifying each type's +speed of sound *cs*. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -144,18 +144,16 @@ the :doc:`run ` command. This fix is not invoked during Restrictions """""""""""" -This fix must be used with atom style rheo or rheo/thermal. -This fix must be used in conjuction with -:doc:`fix rheo/pressure `. and -:doc:`fix rheo/viscosity `, If the *thermal* -setting is used, there must also be an instance of -:doc:`fix rheo/thermal `. The fix group must be -set to all. Only one instance of fix rheo may be defined and it -must be defined prior to all other RHEO fixes. +This fix must be used with atom style rheo or rheo/thermal. This fix must +be used in conjuction with :doc:`fix rheo/pressure `. +and :doc:`fix rheo/viscosity `. If the *thermal* setting +is used, there must also be an instance of +:doc:`fix rheo/thermal `. The fix group must be set to all. +Only one instance of fix rheo may be defined and it must be defined prior +to all other RHEO fixes in the input script. -This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the -:doc:`Build package ` page for more info. +This fix is part of the RHEO package. It is only enabled if LAMMPS was built +with that package. See the :doc:`Build package ` page for more info. Related commands """""""""""""""" @@ -173,9 +171,9 @@ Default ---------- -.. _howto_rheo_palermo: +.. _rheo_palermo: -**(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. +**(Palermo)** Palermo, Wolf, Clemmer, O'Connor, in preparation. .. _fix_rheo_hu: diff --git a/doc/src/fix_rheo_oxidation.rst b/doc/src/fix_rheo_oxidation.rst index 3043291c60..ba3ead3f1f 100644 --- a/doc/src/fix_rheo_oxidation.rst +++ b/doc/src/fix_rheo_oxidation.rst @@ -36,21 +36,21 @@ for use with bond style :doc:`bond rheo/shell `. Every timestep, particles check neighbors within a distance of *cut*. This distance must be smaller than the kernel length defined in :doc:`fix rheo `. Bonds of type *btype* are created between -pairs of particles that satisfy one of two conditions. First, if both -particles are on the fluid surface, or within a distance of *rsurf* -from the surface. Secondly, if one particle is on the fluid surface -and the other bond is solid. This process is further described in -:ref:`(Clemmer) `. +a fluid particle and either a fluid or solid neighbor. The fluid particles +must also be on the fluid surface, or within a distance of *rsurf* from +the surface. This process is further described in +:ref:`(Clemmer) `. If used in conjunction with solid bodies, such as those generated by the *react* option of :doc:`fix rheo/thermal `, -it is recommended that one uses a :doc:`hybrid bond style ` +it is recommended to use a :doc:`hybrid bond style ` with different bond types for solid and oxide bonds. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +No information about this fix is written to :doc:`binary restart files `. +None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various :doc:`output commands `. No parameter of this fix can be used with the *start/stop* keywords of @@ -59,11 +59,12 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" -This fix must be used with an bond style :doc:`rheo/shell ` +This fix must be used with the bond style :doc:`rheo/shell ` and :doc:`fix rheo ` with surface detection enabled. This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +LAMMPS was built with that package. See the :doc:`Build package ` +page for more info. Related commands """""""""""""""" @@ -79,6 +80,6 @@ none ---------- -.. _howto_rheo_clemmer: +.. _howto_rheo_clemmer2: **(Clemmer)** Clemmer, Pierce, O'Connor, Nevins, Jones, Lechman, Tencer, Appl. Math. Model., 130, 310-326 (2024). diff --git a/doc/src/fix_rheo_pressure.rst b/doc/src/fix_rheo_pressure.rst index f2a994da88..e01aebf90f 100644 --- a/doc/src/fix_rheo_pressure.rst +++ b/doc/src/fix_rheo_pressure.rst @@ -1,7 +1,7 @@ .. index:: fix rheo/pressure fix rheo/pressure command -=============== +========================= Syntax """""" @@ -20,7 +20,7 @@ Syntax *linear* args = none *taitwater* args = none - *cubic* args = cubic term prefactor :math:`A_3` (pressure/density\^2) + *cubic* args = cubic prefactor :math:`A_3` (pressure/density\^2) Examples """""""" @@ -36,8 +36,8 @@ Description .. versionadded:: TBD This fix defines a pressure equation of state for RHEO particles. One can -define different equations of state for different atom types, but an -equation must be specified for every atom type. +define different equations of state for different atom types. An equation +must be specified for every atom type. One first defines the atom *types*. A wild-card asterisk can be used in place of or in conjunction with the *types* argument to set the coefficients for @@ -74,7 +74,8 @@ Style *taitwater* is Tait's equation of state: Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +No information about this fix is written to :doc:`binary restart files `. +None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various :doc:`output commands `. No parameter of this fix can be used with the *start/stop* keywords of @@ -89,7 +90,8 @@ conjuction with :doc:`fix rheo `. The fix group must be set to all. Only one instance of fix rheo/pressure can be defined. This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +LAMMPS was built with that package. See the :doc:`Build package ` +page for more info. Related commands """""""""""""""" diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index 1ceb1259c0..e116325091 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -1,7 +1,7 @@ .. index:: fix rheo/thermal fix rheo/thermal command -=============== +======================== Syntax """""" @@ -50,16 +50,16 @@ Description .. versionadded:: TBD -This fix performs time integration of temperature evolution for atom style -rheo/thermal. In addition, it defines multiple thermal properties of -particles and handles melting/solidification, if applicable. For more details -on phase transitions in RHEO, see :doc:`the RHEO howto `. +This fix performs time integration of temperature for atom style rheo/thermal. +In addition, it defines multiple thermal properties of particles and handles +melting/solidification, if applicable. For more details on phase transitions +in RHEO, see :doc:`the RHEO howto `. Note that the temperature of a particle is always derived from the energy. This implies the *temperature* attribute of :doc:`the set command ` does not affect particles. Instead, one should use the *sph/e* attribute. -For each atom type, one can define attributes for the *conductivity*, +For each atom type, one can define expressions for the *conductivity*, *specific/heat*, *latent/heat*, and critical temperature (*Tfreeze*). The conductivity and specific heat must be defined for all atom types. The latent heat and critical temperature are optional. However, a @@ -88,13 +88,14 @@ types that have a defined value of *Tfreeze*. When a fluid particle's temperature drops below *Tfreeze*, bonds of type *btype* are created between nearby solid particles within a distance of *cut*. The particle's status also swaps to a solid state. When a solid particle's temperature rises above -*Tfreeze*, all bonds of type *btype* are broken and the particle's tatus swaps +*Tfreeze*, all bonds of type *btype* are broken and the particle's status swaps to a fluid state. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options +No information about this fix is written to :doc:`binary restart files `. +None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various :doc:`output commands `. No parameter of this fix can be used with the *start/stop* keywords of @@ -110,7 +111,8 @@ must be used in conjuction with :doc:`fix rheo ` with the instance of fix rheo/pressure can be defined. This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +LAMMPS was built with that package. See the :doc:`Build package ` +page for more info. Related commands """""""""""""""" diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst index 8175178787..912de584c2 100644 --- a/doc/src/fix_rheo_viscosity.rst +++ b/doc/src/fix_rheo_viscosity.rst @@ -1,7 +1,7 @@ .. index:: fix rheo/viscosity fix rheo/viscosity command -=============== +========================== Syntax """""" @@ -63,16 +63,16 @@ for the stress :math:`\tau` \tau = \left(\frac{\tau_0}{\dot{\gamma}} + K \dot{\gamma}^{n - 1}\right) \dot{\gamma}, \tau \ge \tau_0 -where :math:`\dot{\gamma}` is the strain rate and :math:`tau_0` is the critical +where :math:`\dot{\gamma}` is the strain rate and :math:`\tau_0` is the critical yield stress, below which :math:`\dot{\gamma} = 0.0`. To avoid divergences, this expression is regularized by defining a critical strain rate *gd0*. If the local strain rate on a particle falls below this limit, a constant viscosity of *eta* is assigned. This implies a value of .. math:: - \tau_0 = \eta * \dot{\gamma}_0 - K \dot{\gamma}_0^N + \tau_0 = \eta \dot{\gamma}_0 - K \dot{\gamma}_0^N -as further discussed in :ref:`(Palermo) `. +as further discussed in :ref:`(Palermo) `. Restart, fix_modify, output, run start/stop, minimize info @@ -112,6 +112,6 @@ none ---------- -.. _howto_rheo_palermo: +.. _rheo_palermo2: -**(Palermo)** Palermo, Clemmer, Wolf, O'Connor, in preparation. +**(Palermo)** Palermo, Wolf, Clemmer, O'Connor, in preparation. diff --git a/doc/src/pair_rheo.rst b/doc/src/pair_rheo.rst index a530444f36..993ec3cee3 100644 --- a/doc/src/pair_rheo.rst +++ b/doc/src/pair_rheo.rst @@ -1,7 +1,7 @@ .. index:: pair_style rheo pair_style rheo command -========================= +======================= Syntax """""" @@ -25,7 +25,7 @@ Examples .. code-block:: LAMMPS - pair_style rheo 1.0 quintic rho/damp 1.0 artificial/visc 2.0 + pair_style rheo 3.0 rho/damp 1.0 artificial/visc 2.0 pair_coeff * * Description @@ -41,22 +41,23 @@ heat exchanged between particles. The *artificial/viscosity* keyword is used to specify the magnitude :math:`\zeta` of an optional artificial viscosity contribution to forces. This factor can help stabilize simulations by smoothing out small length -scale variations in velocity fields. Artificial viscous forces are only -exchanged by fluid particles unless interfaces are not reconstructed in -fix rheo, in which fluid particles will also exchange artificial viscous -forces with solid particles to improve stability. +scale variations in velocity fields. Artificial viscous forces typically +are only exchanged by fluid particles. However, if interfaces are not +reconstructed in fix rheo, fluid particles will also exchange artificial +viscous forces with solid particles to improve stability. The *rho/damp* keyword is used to specify the magnitude :math:`\xi` of an optional pairwise damping term between the density of particles. This factor can help stabilize simulations by smoothing out small length -scale variations in density fields. +scale variations in density fields. However, in systems that develop +a density gradient in equilibrium (e.g. in a hydrostatic column underlying +gravity), this option may be inappropriate. If particles have different viscosities or conductivities, the *harmonic/means* keyword changes how they are averaged before calculating pairwise forces or heat exchanges. By default, an arithmetic averaged is -used, however, a harmonic mean may improve stability in multiphase systems -with large disparities in viscosities. This keyword has no effect on -results if viscosities and conductivities are constant. +used, however, a harmonic mean may improve stability in systems with multiple +fluid phases with large disparities in viscosities. No coefficients are defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples @@ -70,16 +71,20 @@ Mixing, shift, table, tail correction, restart, rRESPA info This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and -pair_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. +Thus, you need to re-specify the pair_style and pair_coeff commands in an input +script that reads a restart file. -This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*, *middle*, *outer* keywords. +This style can only be used via the *pair* keyword of the +:doc:`run_style respa ` command. It does not support the *inner*, +*middle*, *outer* keywords. Restrictions """""""""""" This fix is part of the RHEO package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +LAMMPS was built with that package. See the +:doc:`Build package ` page for more info. Related commands """""""""""""""" @@ -93,4 +98,5 @@ Related commands Default """"""" -Density damping and artificial viscous forces are not calculated. Arithmetic means are used for mixing particle properties. +Density damping and artificial viscous forces are not calculated. +Arithmetic means are used for mixing particle properties. diff --git a/doc/src/pair_rheo_solid.rst b/doc/src/pair_rheo_solid.rst index 4bac9b726f..0b1ed47fb8 100644 --- a/doc/src/pair_rheo_solid.rst +++ b/doc/src/pair_rheo_solid.rst @@ -1,7 +1,7 @@ .. index:: pair_style rheo/solid pair_style rheo/solid command -========================= +============================= Syntax """""" @@ -44,7 +44,7 @@ normal velocity of particles F_D = - \gamma w (\hat{r} \bullet \vec{v}) where :math:`\gamma` is the damping strength, :math:`\hat{r}` is the -radial normal vector, :math:`\vec{v}` is the velocity difference +displacement normal vector, :math:`\vec{v}` is the velocity difference between the two particles, and :math:`w` is a smoothing factor. This smoothing factor is constructed such that damping forces go to zero as particles come out of contact to avoid discontinuities. It is @@ -95,7 +95,7 @@ This pair style can only be used via the *pair* keyword of the Restrictions """""""""""" -This pair style is part of the BPM package. It is only enabled if +This pair style is part of the RHEO package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. diff --git a/doc/src/pair_style.rst b/doc/src/pair_style.rst index 75157d6127..1cb85ff739 100644 --- a/doc/src/pair_style.rst +++ b/doc/src/pair_style.rst @@ -337,6 +337,8 @@ accelerated styles exist. * :doc:`reaxff ` - ReaxFF potential * :doc:`rebo ` - Second generation REBO potential of Brenner * :doc:`rebomos ` - REBOMoS potential for MoS2 +* :doc:`rheo ` - fluid interactions in RHEO package +* :doc:`rheo/solid ` - solid interactions in RHEO package * :doc:`resquared ` - Everaers RE-Squared ellipsoidal potential * :doc:`saip/metal ` - Interlayer potential for hetero-junctions formed with hexagonal 2D materials and metal surfaces * :doc:`sdpd/taitwater/isothermal ` - Smoothed dissipative particle dynamics for water at isothermal conditions diff --git a/examples/rheo/balloon/in.rheo.balloon b/examples/rheo/balloon/in.rheo.balloon index c82fa39df3..24e400f40f 100644 --- a/examples/rheo/balloon/in.rheo.balloon +++ b/examples/rheo/balloon/in.rheo.balloon @@ -71,5 +71,5 @@ compute nbond all nbond/atom thermo 200 thermo_style custom step time ke press atoms -dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_nbond c_rho +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_nbond c_rho run 30000 diff --git a/examples/rheo/balloon/log.17Apr2024.balloon.g++.4 b/examples/rheo/balloon/log.17Apr2024.balloon.g++.4 new file mode 100644 index 0000000000..28fcc4b590 --- /dev/null +++ b/examples/rheo/balloon/log.17Apr2024.balloon.g++.4 @@ -0,0 +1,382 @@ +LAMMPS (17 Apr 2024 - Development - patch_5May2020-18508-g3c0eaf6870-modified) +# ------ 2D water balloon ------ # + +dimension 2 +units lj +atom_style hybrid rheo bond +boundary m m p +comm_modify vel yes +newton off + +region box block -40 40 0 80 -0.01 0.01 units box +create_box 1 box bond/types 1 extra/bond/per/atom 15 extra/special/per/atom 50 +Created orthogonal box = (-40 0 -0.01) to (40 80 0.01) + 2 by 2 by 1 MPI processor grid + +region fluid sphere -10 40 0 30 units box side in +lattice hex 1.0 +Lattice spacing in x,y,z = 1.0745699 1.8612097 1.0745699 +create_atoms 1 region fluid +Created 2830 atoms + using lattice units in orthogonal box = (-40 0 -0.01) to (40 80 0.01) + create_atoms CPU = 0.001 seconds + +region shell sphere -10 40 0 27 units box side out +group shell region shell +544 atoms in group shell + +set group shell rheo/status 1 +Setting atom values ... + 544 settings made for rheo/status +set group all vx 0.005 vy -0.04 +Setting atom values ... + 2830 settings made for vx + 2830 settings made for vy + +# ------ Model parameters ------# + +variable cut equal 3.0 +variable n equal 1.0 +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable mp equal 1/${n} +variable mp equal 1/1 +variable zeta equal 0.05 +variable kappa equal 0.01*${rho0}/${mp} +variable kappa equal 0.01*1/${mp} +variable kappa equal 0.01*1/1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable dt_max equal 0.1*3/${cs}/3 +variable dt_max equal 0.1*3/1/3 +variable eta equal 0.05 +variable Cv equal 1.0 +variable L equal 1.0 +variable Tf equal 1.0 + +mass * ${mp} +mass * 1 +timestep 0.1 + +pair_style hybrid/overlay rheo ${cut} artificial/visc ${zeta} rheo/solid +pair_style hybrid/overlay rheo 3 artificial/visc ${zeta} rheo/solid +pair_style hybrid/overlay rheo 3 artificial/visc 0.05 rheo/solid +pair_coeff * * rheo +pair_coeff * * rheo/solid 1.0 1.0 1.0 + +special_bonds lj 0.0 1.0 1.0 coul 0.0 1.0 1.0 +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 1 1 + special bond factors coul: 0 1 1 + 0 = max # of 1-2 neighbors + 101 = max # of special neighbors + special bonds CPU = 0.000 seconds +create_bonds many shell shell 1 0 1.5 +Generated 0 of 0 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 3.3 + ghost atom cutoff = 3.3 + binsize = 1.65, bins = 49 49 1 + 3 neighbor lists, perpetual/occasional/extra = 2 1 0 + (1) command create_bonds, occasional + attributes: full, newton off + pair build: full/bin + stencil: full/bin/2d + bin: standard + (2) pair rheo, perpetual + attributes: half, newton off + pair build: half/bin/newtoff + stencil: full/bin/2d + bin: standard + (3) pair rheo/solid, perpetual, trim from (2) + attributes: half, newton off, cut 1.3 + pair build: trim + stencil: none + bin: none +Added 1263 bonds, new total = 1263 +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 1 1 + special bond factors coul: 0 1 1 + 6 = max # of 1-2 neighbors + 101 = max # of special neighbors + special bonds CPU = 0.000 seconds +special_bonds lj 0.0 1.0 1.0 coul 1.0 1.0 1.0 + +bond_style bpm/spring +bond_coeff 1 1.0 1.0 1.0 + +# A lower critical strain allows the balloon to pop +#bond_coeff 1 1.0 0.05 1.0 + +# ------ Drop balloon ------# + +fix 1 all rheo ${cut} quintic 0 shift surface/detection coordination 22 8 +fix 1 all rheo 3 quintic 0 shift surface/detection coordination 22 8 +fix 2 all rheo/viscosity * constant ${eta} +fix 2 all rheo/viscosity * constant 0.05 +fix 3 all rheo/pressure * linear +fix 4 all wall/harmonic ylo EDGE 2.0 1.0 1.0 +fix 5 all enforce2d + +compute rho all rheo/property/atom rho +compute phase all rheo/property/atom phase +compute nbond all nbond/atom + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press atoms + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_nbond c_rho +run 30000 + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Your simulation uses code contributions which should be cited: + +- BPM bond style: doi:10.1039/D3SM01373A + +@Article{Clemmer2024, + author = {Clemmer, Joel T. and Monti, Joseph M. and Lechman, Jeremy B.}, + title = {A soft departure from jamming: the compaction of deformable + granular matter under high pressures}, + journal = {Soft Matter}, + year = 2024, + volume = 20, + number = 8, + pages = {1702--1718} +} + +- @article{PalermoInPrep, + journal = {in prep}, + title = {RHEO: A Hybrid Mesh-Free Model Framework for Dynamic Multi-Phase Flows}, + year = {2024}, + author = {Eric T. Palermo and Ki T. Wolf and Joel T. Clemmer and Thomas C. O'Connor}, +} + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Generated 0 of 0 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 3.3 + ghost atom cutoff = 3.3 + binsize = 1.65, bins = 49 49 1 + 6 neighbor lists, perpetual/occasional/extra = 6 0 0 + (1) pair rheo, perpetual, half/full from (3) + attributes: half, newton off + pair build: halffull/newtoff + stencil: none + bin: none + (2) pair rheo/solid, perpetual, trim from (1) + attributes: half, newton off, cut 1.3 + pair build: trim + stencil: none + bin: none + (3) compute RHEO/KERNEL, perpetual + attributes: full, newton off + pair build: full/bin + stencil: full/bin/2d + bin: standard + (4) compute RHEO/GRAD, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (5) compute RHEO/VSHIFT, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (6) compute RHEO/SURFACE, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none +Per MPI rank memory allocation (min/avg/max) = 17.63 | 17.64 | 17.65 Mbytes + Step Time KinEng Press Atoms + 0 0 0.0008125 0.00035927734 2830 + 200 20 0.0008125 0.00035927734 2830 + 400 40 0.0008125 0.00035927734 2830 + 600 60 0.0008125 0.00035927734 2830 + 800 80 0.0008125 0.00035927734 2830 + 1000 100 0.0008125 0.00035927734 2830 + 1200 120 0.0008125 0.00035927734 2830 + 1400 140 0.0008125 0.00035927734 2830 + 1600 160 0.0008125 0.00035927734 2830 + 1800 180 0.0008125 0.00035927734 2830 + 2000 200 0.0008125 0.00035927734 2830 + 2200 220 0.0008125 0.00035927734 2830 + 2400 240 0.00079033569 0.00043037861 2830 + 2600 260 0.0007549229 0.00045188383 2830 + 2800 280 0.00072808836 0.00031695003 2830 + 3000 300 0.0007017958 1.6121754e-05 2830 + 3200 320 0.00067479047 -0.00015725514 2830 + 3400 340 0.00064762254 -0.00023361314 2830 + 3600 360 0.00061960255 -0.00033837679 2830 + 3800 380 0.0005857206 -0.00051770716 2830 + 4000 400 0.00055061733 -0.00070309251 2830 + 4200 420 0.00051884719 -0.0008247795 2830 + 4400 440 0.00049022236 -0.00099918413 2830 + 4600 460 0.00046060011 -0.0010923159 2830 + 4800 480 0.00042900173 -0.0011524571 2830 + 5000 500 0.00039751503 -0.0012586358 2830 + 5200 520 0.00036620054 -0.0013973543 2830 + 5400 540 0.00033130023 -0.0015185231 2830 + 5600 560 0.00030565892 -0.0016159836 2830 + 5800 580 0.00028209836 -0.0016925198 2830 + 6000 600 0.00024695044 -0.0017796892 2830 + 6200 620 0.00021190635 -0.0018706272 2830 + 6400 640 0.0001947093 -0.0019146643 2830 + 6600 660 0.00018903936 -0.0019146199 2830 + 6800 680 0.00017753371 -0.0019390155 2830 + 7000 700 0.00015170593 -0.0020247472 2830 + 7200 720 0.00011509692 -0.0021222209 2830 + 7400 740 7.9861785e-05 -0.0022033181 2830 + 7600 760 6.1350463e-05 -0.0022511971 2830 + 7800 780 6.5269523e-05 -0.0022222806 2830 + 8000 800 8.5709569e-05 -0.0021089664 2830 + 8200 820 0.00011746348 -0.0019351493 2830 + 8400 840 0.00015698134 -0.0017079928 2830 + 8600 860 0.00019758065 -0.0014618965 2830 + 8800 880 0.00023338199 -0.0012365832 2830 + 9000 900 0.00026282353 -0.0010348527 2830 + 9200 920 0.00028604776 -0.00085287884 2830 + 9400 940 0.00030388767 -0.000681122 2830 + 9600 960 0.000317589 -0.00052203521 2830 + 9800 980 0.00032716728 -0.00037501187 2830 + 10000 1000 0.00033270692 -0.00025576132 2830 + 10200 1020 0.00033485986 -0.00016554207 2830 + 10400 1040 0.00033476763 -9.8525417e-05 2830 + 10600 1060 0.00033351922 -5.1166347e-05 2830 + 10800 1080 0.00033161645 -2.0773965e-05 2830 + 11000 1100 0.00032913022 2.2384421e-07 2830 + 11200 1120 0.00032618376 1.2304773e-05 2830 + 11400 1140 0.00032310409 1.3725982e-05 2830 + 11600 1160 0.0003202128 9.0431945e-06 2830 + 11800 1180 0.00031760386 -5.3537879e-07 2830 + 12000 1200 0.00031518884 -1.331708e-05 2830 + 12200 1220 0.00031283958 -3.0838612e-05 2830 + 12400 1240 0.0003104901 -5.0038548e-05 2830 + 12600 1260 0.00030811597 -6.9699925e-05 2830 + 12800 1280 0.00030555782 -8.9972287e-05 2830 + 13000 1300 0.00030256671 -0.00011712941 2830 + 13200 1320 0.00029907961 -0.00015495826 2830 + 13400 1340 0.00029504656 -0.00020292633 2830 + 13600 1360 0.0002905184 -0.00024892421 2830 + 13800 1380 0.00028564542 -0.000295085 2830 + 14000 1400 0.00028073246 -0.00034571956 2830 + 14200 1420 0.00027611457 -0.00039341977 2830 + 14400 1440 0.00027217382 -0.0004281012 2830 + 14600 1460 0.00026919129 -0.00045342545 2830 + 14800 1480 0.00026727674 -0.00047323419 2830 + 15000 1500 0.0002663482 -0.00048423944 2830 + 15200 1520 0.00026616663 -0.0004816085 2830 + 15400 1540 0.00026634862 -0.00047573486 2830 + 15600 1560 0.0002664314 -0.00046803192 2830 + 15800 1580 0.00026603348 -0.00045753668 2830 + 16000 1600 0.00026511015 -0.00044676105 2830 + 16200 1620 0.00026373403 -0.00044075794 2830 + 16400 1640 0.00026217342 -0.00043684036 2830 + 16600 1660 0.0002607038 -0.00042774771 2830 + 16800 1680 0.00025951097 -0.00041603026 2830 + 17000 1700 0.00025869088 -0.00040302996 2830 + 17200 1720 0.00025825588 -0.00038415247 2830 + 17400 1740 0.00025818373 -0.00035742127 2830 + 17600 1760 0.00025843381 -0.00032854722 2830 + 17800 1780 0.00025897836 -0.00029821183 2830 + 18000 1800 0.00025981472 -0.00026108907 2830 + 18200 1820 0.00026095775 -0.00021731058 2830 + 18400 1840 0.00026239688 -0.00017030825 2830 + 18600 1860 0.00026404432 -0.00011868778 2830 + 18800 1880 0.00026574247 -5.9556286e-05 2830 + 19000 1900 0.00026729563 2.3014881e-06 2830 + 19200 1920 0.00026852418 6.2100169e-05 2830 + 19400 1940 0.00026929086 0.00012090325 2830 + 19600 1960 0.0002695407 0.00017904223 2830 + 19800 1980 0.00026929677 0.00023112254 2830 + 20000 2000 0.00026863577 0.0002756697 2830 + 20200 2020 0.00026765699 0.0003158399 2830 + 20400 2040 0.00026646841 0.00035200747 2830 + 20600 2060 0.00026516938 0.00038018442 2830 + 20800 2080 0.00026383495 0.00040179111 2830 + 21000 2100 0.00026252489 0.00042030921 2830 + 21200 2120 0.00026128616 0.00043466976 2830 + 21400 2140 0.00026014896 0.00044221445 2830 + 21600 2160 0.00025912325 0.00044531883 2830 + 21800 2180 0.00025821515 0.00044661709 2830 + 22000 2200 0.00025742576 0.00044409089 2830 + 22200 2220 0.00025674938 0.00043634999 2830 + 22400 2240 0.00025617111 0.00042630344 2830 + 22600 2260 0.0002556791 0.00041561603 2830 + 22800 2280 0.00025525963 0.00040166735 2830 + 23000 2300 0.00025489538 0.00038430419 2830 + 23200 2320 0.00025456861 0.0003669402 2830 + 23400 2340 0.00025426747 0.00034972373 2830 + 23600 2360 0.00025398353 0.0003302242 2830 + 23800 2380 0.00025370842 0.00030993088 2830 + 24000 2400 0.00025344084 0.00029143258 2830 + 24200 2420 0.00025318683 0.00027421708 2830 + 24400 2440 0.0002529591 0.00025603123 2830 + 24600 2460 0.0002527713 0.00023950245 2830 + 24800 2480 0.00025264228 0.00022644812 2830 + 25000 2500 0.00025259021 0.00021540748 2830 + 25200 2520 0.00025262892 0.00020544201 2830 + 25400 2540 0.00025276229 0.00019845807 2830 + 25600 2560 0.0002529876 0.00019449958 2830 + 25800 2580 0.00025329374 0.00019082606 2830 + 26000 2600 0.00025366066 0.00018700064 2830 + 26200 2620 0.00025406164 0.00018426061 2830 + 26400 2640 0.00025446737 0.00018098339 2830 + 26600 2660 0.00025484714 0.00017471869 2830 + 26800 2680 0.00025516604 0.00016565557 2830 + 27000 2700 0.00025538911 0.00015493626 2830 + 27200 2720 0.00025548177 0.00014075592 2830 + 27400 2740 0.00025541168 0.00012205573 2830 + 27600 2760 0.00025514889 0.00010039772 2830 + 27800 2780 0.00025467547 7.7069215e-05 2830 + 28000 2800 0.0002539915 5.1158042e-05 2830 + 28200 2820 0.00025312083 2.3468384e-05 2830 + 28400 2840 0.00025211323 -3.2184465e-06 2830 + 28600 2860 0.00025104366 -2.7726301e-05 2830 + 28800 2880 0.00025000263 -5.0202987e-05 2830 + 29000 2900 0.00024907814 -6.9244776e-05 2830 + 29200 2920 0.00024833815 -8.2874516e-05 2830 + 29400 2940 0.0002478155 -9.1854992e-05 2830 + 29600 2960 0.00024750313 -9.766055e-05 2830 + 29800 2980 0.00024735538 -9.9681291e-05 2830 + 30000 3000 0.00024730191 -9.818759e-05 2830 +Loop time of 177.982 on 4 procs for 30000 steps with 2830 atoms + +Performance: 1456330.235 tau/day, 168.557 timesteps/s, 477.016 katom-step/s +99.7% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 22.913 | 27.061 | 34.594 | 87.2 | 15.20 +Bond | 0.22386 | 0.26159 | 0.30792 | 6.0 | 0.15 +Neigh | 0.84412 | 0.84509 | 0.8462 | 0.1 | 0.47 +Comm | 0.50015 | 0.55579 | 0.60346 | 5.2 | 0.31 +Output | 0.65854 | 0.69412 | 0.72473 | 2.8 | 0.39 +Modify | 133.13 | 136 | 137.38 | 14.5 | 76.41 +Other | | 12.57 | | | 7.06 + +Nlocal: 707.5 ave 1576 max 53 min +Histogram: 2 0 0 0 0 0 1 0 0 1 +Nghost: 164.75 ave 239 max 94 min +Histogram: 1 0 1 0 0 0 0 1 0 1 +Neighs: 12307.8 ave 27380 max 983 min +Histogram: 2 0 0 0 0 0 1 0 0 1 +FullNghs: 23517 ave 53040 max 1502 min +Histogram: 2 0 0 0 0 0 1 0 0 1 + +Total # of neighbors = 94068 +Ave neighs/atom = 33.239576 +Ave special neighs/atom = 0.89257951 +Neighbor list builds = 783 +Dangerous builds = 0 +Total wall time: 0:02:58 diff --git a/examples/rheo/dam-break/log.17Apr2024.dam.g++.4 b/examples/rheo/dam-break/log.17Apr2024.dam.g++.4 new file mode 100644 index 0000000000..6388d9e478 --- /dev/null +++ b/examples/rheo/dam-break/log.17Apr2024.dam.g++.4 @@ -0,0 +1,1694 @@ +LAMMPS (17 Apr 2024 - Development - patch_5May2020-18508-g3c0eaf6870-modified) +# ------ 2D dam break ------ # + +dimension 2 +units lj +atom_style rheo +boundary f s p +comm_modify vel yes +newton off + +# ------ Create simulation box ------ # + +variable n equal 1.0 +variable cut equal 2.2 +variable dx equal 3.0 + +region box block -1 150 -1 80 -0.1 0.1 units box +create_box 2 box +Created orthogonal box = (-1 -1 -0.1) to (150 80 0.1) + 2 by 2 by 1 MPI processor grid +lattice hex ${n} +lattice hex 1 +Lattice spacing in x,y,z = 1.0745699 1.8612097 1.0745699 + +region fluid block $(xlo+v_dx+1.0) $(xlo+40.0) $(ylo+v_dx+1.0) $(yhi-20.0) EDGE EDGE units box +region fluid block 3 $(xlo+40.0) $(ylo+v_dx+1.0) $(yhi-20.0) EDGE EDGE units box +region fluid block 3 39 $(ylo+v_dx+1.0) $(yhi-20.0) EDGE EDGE units box +region fluid block 3 39 2.991900000000000226 $(yhi-20.0) EDGE EDGE units box +region fluid block 3 39 2.991900000000000226 60.008099999999998886 EDGE EDGE units box +region walls1 block $(xlo+v_dx) $(xhi-v_dx) $(ylo+v_dx) $(yhi-v_dx) EDGE EDGE side out units box +region walls1 block 2 $(xhi-v_dx) $(ylo+v_dx) $(yhi-v_dx) EDGE EDGE side out units box +region walls1 block 2 147 $(ylo+v_dx) $(yhi-v_dx) EDGE EDGE side out units box +region walls1 block 2 147 1.9919000000000000039 $(yhi-v_dx) EDGE EDGE side out units box +region walls1 block 2 147 1.9919000000000000039 77.008099999999998886 EDGE EDGE side out units box +region walls2 block EDGE EDGE EDGE $(yhi-v_dx) EDGE EDGE side in units box +region walls2 block EDGE EDGE EDGE 77.008099999999998886 EDGE EDGE side in units box +region walls intersect 2 walls1 walls2 + +create_atoms 1 region fluid +Created 2044 atoms + using lattice units in orthogonal box = (-1 -1.0081 -0.1) to (150 80.0081 0.1) + create_atoms CPU = 0.001 seconds +create_atoms 2 region walls +Created 1002 atoms + using lattice units in orthogonal box = (-1 -1.0081 -0.1) to (150 80.0081 0.1) + create_atoms CPU = 0.000 seconds + +group fluid type 1 +2044 atoms in group fluid +group rig type 2 +1002 atoms in group rig + +# ------ Model parameters ------ # + +variable rho0 equal 1.0 +variable mp equal ${rho0}/${n} +variable mp equal 1/${n} +variable mp equal 1/1 +variable cs equal 1.0 +variable zeta equal 0.1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable dt_max equal 0.1*2.2/${cs}/3 +variable dt_max equal 0.1*2.2/1/3 +variable eta equal 0.1 +variable Dr equal 0.1 + +mass 1 ${mp} +mass 1 1 +mass 2 $(2*v_mp) +mass 2 2 +set group all rheo/rho ${rho0} +set group all rheo/rho 1 +Setting atom values ... + 3046 settings made for rheo/rho + +set group all rheo/status 0 +Setting atom values ... + 3046 settings made for rheo/status +set group rig rheo/status 1 +Setting atom values ... + 1002 settings made for rheo/status + +timestep ${dt_max} +timestep 0.0733333333333333 + +pair_style rheo ${cut} artificial/visc ${zeta} #rho/damp ${Dr} +pair_style rheo 2.2 artificial/visc ${zeta} +pair_style rheo 2.2 artificial/visc 0.1 +pair_coeff * * + +# ------ Fixes & computes ------ # + +fix 1 all rheo ${cut} quintic 10 surface/detection coordination 22 8 rho/sum +fix 1 all rheo 2.2 quintic 10 surface/detection coordination 22 8 rho/sum +fix 2 all rheo/viscosity * constant ${eta} +fix 2 all rheo/viscosity * constant 0.1 +fix 3 all rheo/pressure * linear +fix 4 all gravity 1e-3 vector 0 -1 0 +fix 5 rig setforce 0.0 0.0 0.0 +fix 6 all enforce2d + +compute rho all rheo/property/atom rho +compute p all rheo/property/atom pressure +compute surf all rheo/property/atom surface +compute sn all rheo/property/atom surface/n/x surface/n/y + +# ------ Output & Run ------ # + +thermo 20 +thermo_style custom step time ke press + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho c_surf c_p c_sn[*] + +run 30000 + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Your simulation uses code contributions which should be cited: + +- @article{PalermoInPrep, + journal = {in prep}, + title = {RHEO: A Hybrid Mesh-Free Model Framework for Dynamic Multi-Phase Flows}, + year = {2024}, + author = {Eric T. Palermo and Ki T. Wolf and Joel T. Clemmer and Thomas C. O'Connor}, +} + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Generated 0 of 1 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 2.5 + ghost atom cutoff = 2.5 + binsize = 1.25, bins = 121 65 1 + 5 neighbor lists, perpetual/occasional/extra = 5 0 0 + (1) pair rheo, perpetual, half/full from (2) + attributes: half, newton off + pair build: halffull/newtoff + stencil: none + bin: none + (2) compute RHEO/KERNEL, perpetual + attributes: full, newton off + pair build: full/bin/atomonly + stencil: full/bin/2d + bin: standard + (3) compute RHEO/GRAD, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (4) compute RHEO/RHO/SUM, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (5) compute RHEO/SURFACE, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none +Per MPI rank memory allocation (min/avg/max) = 5.707 | 5.721 | 5.736 Mbytes + Step Time KinEng Press + 0 0 0 -8.9662357e-06 + 20 1.4666667 0.00034058796 8.9684994e-05 + 40 2.9333333 6.9365611e-05 2.3675864e-05 + 60 4.4 6.1074185e-05 1.6680783e-05 + 80 5.8666667 5.0534793e-05 1.2623473e-05 + 100 7.3333333 4.1073516e-05 1.1708742e-05 + 120 8.8 4.9303871e-05 1.3714304e-05 + 140 10.266667 5.1669035e-05 1.3579535e-05 + 160 11.733333 6.0107096e-05 1.606084e-05 + 180 13.2 6.9154593e-05 1.8429091e-05 + 200 14.666667 8.0009963e-05 2.0757671e-05 + 220 16.133333 9.1883493e-05 2.3542955e-05 + 240 17.6 0.00010524584 2.6786532e-05 + 260 19.066667 0.00011982479 3.0390295e-05 + 280 20.533333 0.00013474016 3.4766566e-05 + 300 22 0.00015081777 4.0596983e-05 + 320 23.466667 0.00016922091 4.7811202e-05 + 340 24.933333 0.00018746472 5.436563e-05 + 360 26.4 0.00020594739 5.8634772e-05 + 380 27.866667 0.00022673738 6.0759081e-05 + 400 29.333333 0.00024754656 6.1922882e-05 + 420 30.8 0.00026882061 6.4956859e-05 + 440 32.266667 0.00029203 7.2311959e-05 + 460 33.733333 0.00031627032 8.1297842e-05 + 480 35.2 0.00034113307 8.9913587e-05 + 500 36.666667 0.00036599396 9.7909338e-05 + 520 38.133333 0.00039120212 0.0001055925 + 540 39.6 0.00041728537 0.00011265914 + 560 41.066667 0.00044402713 0.00011842088 + 580 42.533333 0.00047160578 0.00012321574 + 600 44 0.00050005372 0.00012842455 + 620 45.466667 0.00052908365 0.00013533445 + 640 46.933333 0.00055833314 0.00014412684 + 660 48.4 0.00058760766 0.00015385416 + 680 49.866667 0.00061704537 0.00016323184 + 700 51.333333 0.00064676026 0.0001720558 + 720 52.8 0.00067674239 0.00018065137 + 740 54.266667 0.00070699735 0.00018906348 + 760 55.733333 0.00073745009 0.00019856234 + 780 57.2 0.00076805806 0.00020874484 + 800 58.666667 0.00079892632 0.00021905295 + 820 60.133333 0.00083019385 0.00022890532 + 840 61.6 0.00086204047 0.00023806257 + 860 63.066667 0.00089463638 0.00024675987 + 880 64.533333 0.0009280011 0.00025519683 + 900 66 0.00096201218 0.00026350368 + 920 67.466667 0.00099657113 0.00027166253 + 940 68.933333 0.0010317502 0.00027992975 + 960 70.4 0.0010676863 0.00028790134 + 980 71.866667 0.0011043796 0.00029680468 + 1000 73.333333 0.0011417187 0.00030600061 + 1020 74.8 0.001179618 0.00031551941 + 1040 76.266667 0.0012180222 0.00032540799 + 1060 77.733333 0.0012568886 0.00033557079 + 1080 79.2 0.0012962727 0.00034616068 + 1100 80.666667 0.0013363417 0.00035717164 + 1120 82.133333 0.0013772784 0.00036920892 + 1140 83.6 0.0014192183 0.00038068516 + 1160 85.066667 0.0014621933 0.00039223594 + 1180 86.533333 0.0015061045 0.00040532576 + 1200 88 0.001550789 0.00041895976 + 1220 89.466667 0.0015961278 0.00043309673 + 1240 90.933333 0.0016420919 0.0004476234 + 1260 92.4 0.001688693 0.00046248791 + 1280 93.866667 0.0017358804 0.00047764479 + 1300 95.333333 0.0017834857 0.0004929783 + 1320 96.8 0.0018313096 0.00050814477 + 1340 98.266667 0.0018793086 0.00052401678 + 1360 99.733333 0.0019277217 0.00053716885 + 1380 101.2 0.0019769204 0.00055180327 + 1400 102.66667 0.0020270711 0.0005656469 + 1420 104.13333 0.0020779701 0.00057917022 + 1440 105.6 0.0021293579 0.00059160854 + 1460 107.06667 0.0021813213 0.00060392999 + 1480 108.53333 0.0022341025 0.00061636071 + 1500 110 0.00228757 0.00062924749 + 1520 111.46667 0.0023412951 0.00064266414 + 1540 112.93333 0.0023952355 0.0006565177 + 1560 114.4 0.0024498098 0.00067063291 + 1580 115.86667 0.0025051272 0.00068509378 + 1600 117.33333 0.0025608522 0.00069926059 + 1620 118.8 0.0026168714 0.000713059 + 1640 120.26667 0.0026733349 0.00072675496 + 1660 121.73333 0.0027302055 0.00074010812 + 1680 123.2 0.0027874761 0.00075390199 + 1700 124.66667 0.0028453711 0.00076786487 + 1720 126.13333 0.0029038156 0.0007820191 + 1740 127.6 0.0029624061 0.00079619745 + 1760 129.06667 0.0030211707 0.00081053823 + 1780 130.53333 0.0030802801 0.00082493927 + 1800 132 0.0031393313 0.00083943639 + 1820 133.46667 0.0031981476 0.00085389118 + 1840 134.93333 0.0032572803 0.00086793469 + 1860 136.4 0.0033167316 0.00088219559 + 1880 137.86667 0.0033757606 0.00089612646 + 1900 139.33333 0.0034343394 0.00090982709 + 1920 140.8 0.0034930349 0.00092382861 + 1940 142.26667 0.0035518482 0.00093805745 + 1960 143.73333 0.0036105788 0.00095257985 + 1980 145.2 0.0036693157 0.00096734041 + 2000 146.66667 0.0037279206 0.00098228262 + 2020 148.13333 0.0037863272 0.00099753272 + 2040 149.6 0.0038448977 0.0010129675 + 2060 151.06667 0.0039035631 0.0010289263 + 2080 152.53333 0.0039618021 0.001044226 + 2100 154 0.0040196981 0.001059823 + 2120 155.46667 0.0040776598 0.0010754207 + 2140 156.93333 0.0041356267 0.0010912489 + 2160 158.4 0.0041933707 0.0011068916 + 2180 159.86667 0.0042506844 0.001122462 + 2200 161.33333 0.0043076551 0.0011378276 + 2220 162.8 0.004364899 0.0011531367 + 2240 164.26667 0.0044223607 0.0011685928 + 2260 165.73333 0.0044790909 0.001183629 + 2280 167.2 0.0045350513 0.0011983147 + 2300 168.66667 0.0045910698 0.0012128941 + 2320 170.13333 0.0046473036 0.0012274902 + 2340 171.6 0.0047034572 0.0012420483 + 2360 173.06667 0.0047594904 0.001256434 + 2380 174.53333 0.0048154857 0.0012710526 + 2400 176 0.0048713579 0.0012854643 + 2420 177.46667 0.0049268461 0.0012999539 + 2440 178.93333 0.0049821065 0.0013141319 + 2460 180.4 0.0050376352 0.0013286044 + 2480 181.86667 0.0050932684 0.0013428647 + 2500 183.33333 0.0051487541 0.0013573039 + 2520 184.8 0.0052041856 0.001371655 + 2540 186.26667 0.005259265 0.0013858701 + 2560 187.73333 0.0053140412 0.0014000303 + 2580 189.2 0.0053687577 0.0014142597 + 2600 190.66667 0.0054226172 0.0014281564 + 2620 192.13333 0.0054756639 0.0014420369 + 2640 193.6 0.0055290419 0.0014559949 + 2660 195.06667 0.0055821088 0.0014698039 + 2680 196.53333 0.0056340694 0.0014837338 + 2700 198 0.0056859198 0.0014973779 + 2720 199.46667 0.0057376404 0.0015110075 + 2740 200.93333 0.0057882397 0.0015247587 + 2760 202.4 0.0058380714 0.0015376559 + 2780 203.86667 0.0058874524 0.0015511804 + 2800 205.33333 0.0059360376 0.0015643594 + 2820 206.8 0.0059840503 0.0015776406 + 2840 208.26667 0.0060315172 0.0015904895 + 2860 209.73333 0.0060778724 0.0016030297 + 2880 211.2 0.0061232681 0.0016153868 + 2900 212.66667 0.0061684129 0.0016276456 + 2920 214.13333 0.0062133058 0.0016395859 + 2940 215.6 0.0062576324 0.0016507189 + 2960 217.06667 0.0063013566 0.0016623583 + 2980 218.53333 0.0063443506 0.0016735007 + 3000 220 0.0063871542 0.001684583 + 3020 221.46667 0.006430519 0.001697154 + 3040 222.93333 0.0064740424 0.0017087524 + 3060 224.4 0.0065176616 0.0017189916 + 3080 225.86667 0.0065615555 0.0017301805 + 3100 227.33333 0.006605039 0.0017410152 + 3120 228.8 0.0066482973 0.0017517164 + 3140 230.26667 0.0066915406 0.0017619713 + 3160 231.73333 0.0067344437 0.0017722386 + 3180 233.2 0.006777227 0.0017824734 + 3200 234.66667 0.006819344 0.0017926386 + 3220 236.13333 0.0068607536 0.0018023968 + 3240 237.6 0.0069026957 0.0018127097 + 3260 239.06667 0.0069450313 0.0018236711 + 3280 240.53333 0.0069865151 0.0018341375 + 3300 242 0.0070275294 0.0018448641 + 3320 243.46667 0.0070688646 0.0018561596 + 3340 244.93333 0.0071092014 0.0018662927 + 3360 246.4 0.0071487936 0.0018770385 + 3380 247.86667 0.0071890814 0.001886802 + 3400 249.33333 0.0072281891 0.0018972625 + 3420 250.8 0.0072657267 0.0019062877 + 3440 252.26667 0.0073033651 0.0019160172 + 3460 253.73333 0.0073406213 0.0019254146 + 3480 255.2 0.0073773312 0.0019343899 + 3500 256.66667 0.0074135814 0.0019431867 + 3520 258.13333 0.0074488904 0.0019521168 + 3540 259.6 0.0074841693 0.0019611895 + 3560 261.06667 0.0075194817 0.0019697561 + 3580 262.53333 0.0075540131 0.0019782744 + 3600 264 0.0075880612 0.0019869585 + 3620 265.46667 0.0076217162 0.0019954264 + 3640 266.93333 0.0076541332 0.0020048511 + 3660 268.4 0.0076854774 0.0020121513 + 3680 269.86667 0.0077170032 0.002020407 + 3700 271.33333 0.0077479535 0.002028555 + 3720 272.8 0.0077778112 0.002035829 + 3740 274.26667 0.0078075791 0.0020445579 + 3760 275.73333 0.0078373125 0.002051243 + 3780 277.2 0.0078671935 0.0020596139 + 3800 278.66667 0.0078966016 0.0020667611 + 3820 280.13333 0.0079259829 0.0020737998 + 3840 281.6 0.0079561144 0.0020823896 + 3860 283.06667 0.0079856022 0.0020898018 + 3880 284.53333 0.0080155451 0.0020975877 + 3900 286 0.008045725 0.0021058637 + 3920 287.46667 0.00807515 0.0021132131 + 3940 288.93333 0.0081055524 0.0021220937 + 3960 290.4 0.0081357323 0.0021293745 + 3980 291.86667 0.0081660373 0.0021372148 + 4000 293.33333 0.0081969984 0.0021452255 + 4020 294.8 0.0082267987 0.0021525847 + 4040 296.26667 0.0082567948 0.0021608073 + 4060 297.73333 0.0082871434 0.0021682544 + 4080 299.2 0.0083173455 0.0021769568 + 4100 300.66667 0.0083480923 0.0021843095 + 4120 302.13333 0.008377833 0.0021919136 + 4140 303.6 0.0084065176 0.0022000503 + 4160 305.06667 0.0084359624 0.0022072124 + 4180 306.53333 0.0084657862 0.0022153288 + 4200 308 0.008494679 0.0022227735 + 4220 309.46667 0.008523307 0.002229996 + 4240 310.93333 0.008553561 0.0022382672 + 4260 312.4 0.0085842107 0.0022462238 + 4280 313.86667 0.0086124223 0.0022536478 + 4300 315.33333 0.0086404396 0.0022608951 + 4320 316.8 0.0086693991 0.0022683957 + 4340 318.26667 0.0086973954 0.0022764575 + 4360 319.73333 0.0087253957 0.0022829952 + 4380 321.2 0.0087529268 0.0022901779 + 4400 322.66667 0.0087798869 0.0022970351 + 4420 324.13333 0.0088070731 0.0023035923 + 4440 325.6 0.0088336854 0.0023108163 + 4460 327.06667 0.00886034 0.002317611 + 4480 328.53333 0.008886686 0.0023244292 + 4500 330 0.0089126796 0.0023323098 + 4520 331.46667 0.0089380439 0.002338006 + 4540 332.93333 0.0089625802 0.0023439698 + 4560 334.4 0.0089876608 0.0023508279 + 4580 335.86667 0.0090119764 0.0023567519 + 4600 337.33333 0.0090358053 0.0023630419 + 4620 338.8 0.0090597056 0.0023696207 + 4640 340.26667 0.0090827564 0.0023757413 + 4660 341.73333 0.0091057102 0.0023825055 + 4680 343.2 0.0091280804 0.0023880185 + 4700 344.66667 0.0091501664 0.0023938041 + 4720 346.13333 0.0091724992 0.0024006288 + 4740 347.6 0.0091940571 0.0024066505 + 4760 349.06667 0.0092145857 0.0024118199 + 4780 350.53333 0.0092353995 0.0024187452 + 4800 352 0.0092558703 0.0024235776 + 4820 353.46667 0.009275219 0.0024285703 + 4840 354.93333 0.0092944603 0.0024339815 + 4860 356.4 0.0093126366 0.0024385746 + 4880 357.86667 0.0093312838 0.0024434876 + 4900 359.33333 0.0093497163 0.0024488983 + 4920 360.8 0.009365989 0.0024527436 + 4940 362.26667 0.0093829249 0.0024572285 + 4960 363.73333 0.0093999951 0.0024620002 + 4980 365.2 0.0094162511 0.0024654432 + 5000 366.66667 0.009432966 0.0024696871 + 5020 368.13333 0.0094491728 0.0024752768 + 5040 369.6 0.0094654395 0.0024791774 + 5060 371.06667 0.0094822028 0.0024833783 + 5080 372.53333 0.0094987002 0.0024876159 + 5100 374 0.0095154669 0.0024916919 + 5120 375.46667 0.0095317268 0.0024971427 + 5140 376.93333 0.0095488298 0.0025012162 + 5160 378.4 0.0095659696 0.0025049341 + 5180 379.86667 0.0095824397 0.0025092752 + 5200 381.33333 0.0096000959 0.0025131409 + 5220 382.8 0.0096178056 0.0025171802 + 5240 384.26667 0.0096358075 0.0025217474 + 5260 385.73333 0.0096536841 0.0025259115 + 5280 387.2 0.0096720374 0.0025307756 + 5300 388.66667 0.0096903176 0.0025371145 + 5320 390.13333 0.0097081278 0.002540216 + 5340 391.6 0.0097268941 0.0025456853 + 5360 393.06667 0.009745217 0.0025499166 + 5380 394.53333 0.0097634815 0.0025546822 + 5400 396 0.0097813844 0.0025591351 + 5420 397.46667 0.0097989874 0.0025645654 + 5440 398.93333 0.0098165651 0.0025681155 + 5460 400.4 0.0098343876 0.0025724122 + 5480 401.86667 0.0098522329 0.0025783873 + 5500 403.33333 0.0098691009 0.0025818597 + 5520 404.8 0.0098860184 0.0025857495 + 5540 406.26667 0.0099028987 0.002590578 + 5560 407.73333 0.0099197309 0.0025942164 + 5580 409.2 0.0099359956 0.0025983095 + 5600 410.66667 0.0099524424 0.0026024035 + 5620 412.13333 0.0099690162 0.0026067584 + 5640 413.6 0.0099843964 0.002611251 + 5660 415.06667 0.010000092 0.0026151565 + 5680 416.53333 0.010015971 0.0026189738 + 5700 418 0.01003088 0.0026226851 + 5720 419.46667 0.010046448 0.0026266212 + 5740 420.93333 0.010061779 0.0026305773 + 5760 422.4 0.010077085 0.002634556 + 5780 423.86667 0.010092596 0.0026403454 + 5800 425.33333 0.010107214 0.0026431069 + 5820 426.8 0.010122323 0.0026467806 + 5840 428.26667 0.010136615 0.0026505801 + 5860 429.73333 0.0101514 0.0026545146 + 5880 431.2 0.010165938 0.0026575254 + 5900 432.66667 0.010180061 0.0026611852 + 5920 434.13333 0.010193978 0.0026651517 + 5940 435.6 0.010207399 0.0026700025 + 5960 437.06667 0.010221274 0.0026724013 + 5980 438.53333 0.0102342 0.002675843 + 6000 440 0.010246851 0.0026796139 + 6020 441.46667 0.010259615 0.0026826456 + 6040 442.93333 0.010271994 0.0026856149 + 6060 444.4 0.010284566 0.0026891263 + 6080 445.86667 0.01029697 0.0026934663 + 6100 447.33333 0.010297087 0.0026929648 + 6120 448.8 0.01026953 0.0026859415 + 6140 450.26667 0.010241322 0.0026788232 + 6160 451.73333 0.010201572 0.0026685955 + 6180 453.2 0.010167529 0.0026596809 + 6200 454.66667 0.010140751 0.0026523585 + 6220 456.13333 0.010096077 0.002641072 + 6240 457.6 0.010043217 0.0026282922 + 6260 459.06667 0.0099830892 0.0026127228 + 6280 460.53333 0.0099406642 0.0026021682 + 6300 462 0.0099151275 0.002595732 + 6320 463.46667 0.0098900642 0.0025891145 + 6340 464.93333 0.0098560891 0.0025805017 + 6360 466.4 0.0098293518 0.0025741231 + 6380 467.86667 0.0098089665 0.0025692332 + 6400 469.33333 0.0097886264 0.0025633005 + 6420 470.8 0.0097672621 0.0025580882 + 6440 472.26667 0.0097438543 0.0025530359 + 6460 473.73333 0.0097156792 0.0025441423 + 6480 475.2 0.0096824023 0.0025359007 + 6500 476.66667 0.0096556854 0.0025282404 + 6520 478.13333 0.0096245146 0.0025200185 + 6540 479.6 0.0095942888 0.0025112709 + 6560 481.06667 0.0095630005 0.0025029005 + 6580 482.53333 0.0095307546 0.0024945223 + 6600 484 0.0094979676 0.0024851442 + 6620 485.46667 0.0094678543 0.0024768078 + 6640 486.93333 0.009440454 0.0024694763 + 6660 488.4 0.0094144007 0.0024632333 + 6680 489.86667 0.0093906089 0.0024562358 + 6700 491.33333 0.0093653494 0.0024490631 + 6720 492.8 0.0093388466 0.0024421324 + 6740 494.26667 0.0093068273 0.0024334756 + 6760 495.73333 0.0092747153 0.0024247141 + 6780 497.2 0.0092468798 0.0024172005 + 6800 498.66667 0.0092160816 0.002409021 + 6820 500.13333 0.0091844109 0.0024010176 + 6840 501.6 0.0091543943 0.0023931861 + 6860 503.06667 0.0091225364 0.00238459 + 6880 504.53333 0.009091163 0.0023764251 + 6900 506 0.0090620145 0.0023688628 + 6920 507.46667 0.0090327696 0.0023610683 + 6940 508.93333 0.0090043995 0.0023537352 + 6960 510.4 0.0089749557 0.0023459457 + 6980 511.86667 0.0089447271 0.0023385936 + 7000 513.33333 0.0089161633 0.0023311311 + 7020 514.8 0.008888379 0.002323798 + 7040 516.26667 0.0088597051 0.0023162749 + 7060 517.73333 0.0088314196 0.0023094901 + 7080 519.2 0.0088032697 0.0023017143 + 7100 520.66667 0.0087764174 0.0022945937 + 7120 522.13333 0.0087493465 0.0022878231 + 7140 523.6 0.0087208106 0.0022805679 + 7160 525.06667 0.0086901023 0.0022726678 + 7180 526.53333 0.0086602781 0.0022649995 + 7200 528 0.0086338883 0.0022581858 + 7220 529.46667 0.0086086121 0.002252324 + 7240 530.93333 0.0085801758 0.0022441934 + 7260 532.4 0.0085495659 0.0022361561 + 7280 533.86667 0.0085199727 0.0022288965 + 7300 535.33333 0.0084891254 0.0022216958 + 7320 536.8 0.0084557275 0.0022130525 + 7340 538.26667 0.0084218841 0.002203592 + 7360 539.73333 0.0083899168 0.0021958184 + 7380 541.2 0.0083585487 0.002188024 + 7400 542.66667 0.0083279264 0.0021795695 + 7420 544.13333 0.0082956611 0.0021711337 + 7440 545.6 0.0082600396 0.0021620937 + 7460 547.06667 0.008222435 0.0021524246 + 7480 548.53333 0.0081847492 0.0021422603 + 7500 550 0.0081480769 0.0021324926 + 7520 551.46667 0.0081129495 0.0021237168 + 7540 552.93333 0.0080794573 0.0021154414 + 7560 554.4 0.0080465003 0.0021057182 + 7580 555.86667 0.0080134857 0.0020967731 + 7600 557.33333 0.0079807769 0.0020882759 + 7620 558.8 0.007949081 0.0020799016 + 7640 560.26667 0.0079178914 0.0020720038 + 7660 561.73333 0.0078871135 0.0020650346 + 7680 563.2 0.007856599 0.0020563039 + 7700 564.66667 0.0078260839 0.002048286 + 7720 566.13333 0.007796051 0.0020402506 + 7740 567.6 0.0077667325 0.0020324247 + 7760 569.06667 0.0077368975 0.0020242564 + 7780 570.53333 0.0077063146 0.002016025 + 7800 572 0.0076756813 0.0020076974 + 7820 573.46667 0.0076444658 0.0019992537 + 7840 574.93333 0.0076122527 0.0019912246 + 7860 576.4 0.00757938 0.0019824601 + 7880 577.86667 0.0075457657 0.0019739889 + 7900 579.33333 0.0075114496 0.0019644524 + 7920 580.8 0.0074775871 0.0019556077 + 7940 582.26667 0.0074449114 0.0019470595 + 7960 583.73333 0.0074125826 0.0019386798 + 7980 585.2 0.0073795946 0.0019298994 + 8000 586.66667 0.0073460046 0.0019208737 + 8020 588.13333 0.0073122744 0.0019120703 + 8040 589.6 0.0072783913 0.0019033047 + 8060 591.06667 0.0072440775 0.0018943414 + 8080 592.53333 0.0072092735 0.0018852102 + 8100 594 0.0071736521 0.0018758623 + 8120 595.46667 0.0071373132 0.0018664102 + 8140 596.93333 0.0071013244 0.0018569886 + 8160 598.4 0.0070657891 0.0018477343 + 8180 599.86667 0.0070299646 0.0018383955 + 8200 601.33333 0.0069940522 0.001829006 + 8220 602.8 0.0069586108 0.0018197189 + 8240 604.26667 0.0069231457 0.0018112586 + 8260 605.73333 0.0068871373 0.0018016096 + 8280 607.2 0.0068512951 0.0017928173 + 8300 608.66667 0.006816413 0.0017834399 + 8320 610.13333 0.0067820205 0.0017745017 + 8340 611.6 0.0067473828 0.0017654991 + 8360 613.06667 0.0067124905 0.0017569034 + 8380 614.53333 0.0066773905 0.0017474775 + 8400 616 0.0066417638 0.0017387333 + 8420 617.46667 0.0066057074 0.0017293058 + 8440 618.93333 0.0065700041 0.0017200093 + 8460 620.4 0.0065351174 0.0017110662 + 8480 621.86667 0.0065006001 0.0017017664 + 8500 623.33333 0.0064659553 0.0016926237 + 8520 624.8 0.0064314284 0.0016834464 + 8540 626.26667 0.0063972759 0.0016730222 + 8560 627.73333 0.006363104 0.0016535358 + 8580 629.2 0.0063283374 0.0016341308 + 8600 630.66667 0.0062929939 0.0016145833 + 8620 632.13333 0.0062575534 0.0015952196 + 8640 633.6 0.0062223967 0.0015767924 + 8660 635.06667 0.0061876077 0.0015584021 + 8680 636.53333 0.0061531388 0.0015432462 + 8700 638 0.0061189895 0.0015255547 + 8720 639.46667 0.0060849843 0.0015087078 + 8740 640.93333 0.0060508603 0.0014912511 + 8760 642.4 0.0060166368 0.0014741414 + 8780 643.86667 0.0059825217 0.0014570326 + 8800 645.33333 0.0059487275 0.0014404208 + 8820 646.8 0.005915195 0.001427214 + 8840 648.26667 0.0058815506 0.0014108717 + 8860 649.73333 0.0058475012 0.001394823 + 8880 651.2 0.005813175 0.0013791763 + 8900 652.66667 0.0057788055 0.0013635495 + 8920 654.13333 0.0057442301 0.0013485291 + 8940 655.6 0.0057092563 0.0013329993 + 8960 657.06667 0.0056742445 0.0013200488 + 8980 658.53333 0.0056395856 0.0013052312 + 9000 660 0.005604919 0.0012908181 + 9020 661.46667 0.0055697452 0.001276258 + 9040 662.93333 0.0055345006 0.0012617179 + 9060 664.4 0.0054999699 0.0012488732 + 9080 665.86667 0.0054658705 0.0012342743 + 9100 667.33333 0.0054312056 0.0012219265 + 9120 668.8 0.0053958845 0.0012069595 + 9140 670.26667 0.0053607107 0.0011946481 + 9160 671.73333 0.0053258562 0.0011805403 + 9180 673.2 0.005290634 0.0011685879 + 9200 674.66667 0.0052548527 0.0011548258 + 9220 676.13333 0.0052191394 0.0011431756 + 9240 677.6 0.0051838155 0.0011292222 + 9260 679.06667 0.0051486178 0.0011177695 + 9280 680.53333 0.0051136287 0.0011043218 + 9300 682 0.0050793517 0.001093456 + 9320 683.46667 0.0050458249 0.00108072 + 9340 684.93333 0.0050124909 0.0010699656 + 9360 686.4 0.0049790841 0.0010577503 + 9380 687.86667 0.0049458438 0.0010471846 + 9400 689.33333 0.0049128193 0.0010353066 + 9420 690.8 0.0048796878 0.0010250736 + 9440 692.26667 0.0048463678 0.0010133357 + 9460 693.73333 0.0048130621 0.0010034192 + 9480 695.2 0.0047797612 0.00099181501 + 9500 696.66667 0.0047463058 0.00098192704 + 9520 698.13333 0.0047129773 0.00097114316 + 9540 699.6 0.0046802695 0.0009614797 + 9560 701.06667 0.0046481303 0.00095001935 + 9580 702.53333 0.0046159995 0.00094018625 + 9600 704 0.0045836057 0.00093048866 + 9620 705.46667 0.0045513113 0.00092093431 + 9640 706.93333 0.0045195288 0.00091163732 + 9660 708.4 0.0044881214 0.00090108788 + 9680 709.86667 0.0044565522 0.00089178586 + 9700 711.33333 0.0044245471 0.00088289706 + 9720 712.8 0.0043923571 0.00087366447 + 9740 714.26667 0.0043603446 0.00086340815 + 9760 715.73333 0.0043285042 0.00085450195 + 9780 717.2 0.0042965444 0.00084545827 + 9800 718.66667 0.0042643896 0.00083689129 + 9820 720.13333 0.0042323768 0.00082818681 + 9840 721.6 0.0042008631 0.00081834996 + 9860 723.06667 0.0041697784 0.00081001308 + 9880 724.53333 0.0041387393 0.00080132405 + 9900 726 0.0041075523 0.00079289302 + 9920 727.46667 0.0040764684 0.00078371229 + 9940 728.93333 0.004045842 0.00077617702 + 9960 730.4 0.0040156553 0.00076786882 + 9980 731.86667 0.0039855818 0.00075942893 + 10000 733.33333 0.0039554481 0.0007511838 + 10020 734.8 0.0039255002 0.00074338609 + 10040 736.26667 0.0038961167 0.0007357845 + 10060 737.73333 0.0038673423 0.00072863577 + 10080 739.2 0.0038388258 0.00072101271 + 10100 740.66667 0.0038101889 0.00071325927 + 10120 742.13333 0.0037813579 0.00070577634 + 10140 743.6 0.0037524894 0.00069840857 + 10160 745.06667 0.0037236699 0.0006912217 + 10180 746.53333 0.0036948382 0.00068398999 + 10200 748 0.0036659574 0.0006765938 + 10220 749.46667 0.003637161 0.00066944812 + 10240 750.93333 0.0036086524 0.00066246958 + 10260 752.4 0.0035804876 0.00065555896 + 10280 753.86667 0.0035525249 0.00064877214 + 10300 755.33333 0.003524549 0.00064262835 + 10320 756.8 0.0034964925 0.0006359586 + 10340 758.26667 0.0034685139 0.00062899447 + 10360 759.73333 0.0034408225 0.00062253344 + 10380 761.2 0.0034134787 0.00061569541 + 10400 762.66667 0.0033863357 0.00061002091 + 10420 764.13333 0.0033591874 0.00060376799 + 10440 765.6 0.0033319865 0.00059696082 + 10460 767.06667 0.0033049023 0.00059041399 + 10480 768.53333 0.0032781346 0.00058417754 + 10500 770 0.0032516844 0.0005781413 + 10520 771.46667 0.0032253297 0.00057280542 + 10540 772.93333 0.0031988384 0.00056654214 + 10560 774.4 0.0031722162 0.00056022576 + 10580 775.86667 0.0031457039 0.0005547685 + 10600 777.33333 0.0031195399 0.00054891424 + 10620 778.8 0.003093753 0.00054282948 + 10640 780.26667 0.0030681782 0.0005378126 + 10660 781.73333 0.0030426412 0.00053187104 + 10680 783.2 0.0030171127 0.00052598426 + 10700 784.66667 0.0029917103 0.00052087104 + 10720 786.13333 0.0029665734 0.00051521228 + 10740 787.6 0.0029417486 0.00050965329 + 10760 789.06667 0.0029171964 0.000504914 + 10780 790.53333 0.0028928685 0.00049932491 + 10800 792 0.0028687686 0.00049451045 + 10820 793.46667 0.0028449566 0.00048905426 + 10840 794.93333 0.0028215175 0.00048442583 + 10860 796.4 0.0027985141 0.00047942674 + 10880 797.86667 0.0027759233 0.00047495434 + 10900 799.33333 0.0027536322 0.00046989793 + 10920 800.8 0.0027315039 0.00046490714 + 10940 802.26667 0.0027094846 0.00046064051 + 10960 803.73333 0.0026876651 0.00045602046 + 10980 805.2 0.002666198 0.00045168389 + 11000 806.66667 0.0026451664 0.00044707481 + 11020 808.13333 0.0026244819 0.00044301025 + 11040 809.6 0.0026039186 0.00043882304 + 11060 811.06667 0.0025833111 0.00043484293 + 11080 812.53333 0.0025627062 0.0004302122 + 11100 814 0.0025423309 0.00042635689 + 11120 815.46667 0.0025223953 0.00042237706 + 11140 816.93333 0.002502881 0.00041811928 + 11160 818.4 0.002483558 0.00041427004 + 11180 819.86667 0.0024642 0.00041016131 + 11200 821.33333 0.002444785 0.00040680079 + 11220 822.8 0.0024255271 0.00040255216 + 11240 824.26667 0.0024066719 0.0003989581 + 11260 825.73333 0.0023882699 0.00039531616 + 11280 827.2 0.0023701608 0.00039149232 + 11300 828.66667 0.0023521641 0.00038812202 + 11320 830.13333 0.0023342875 0.00038432826 + 11340 831.6 0.0023167154 0.00038122373 + 11360 833.06667 0.0022996036 0.00037780451 + 11380 834.53333 0.0022829198 0.00037461979 + 11400 836 0.0022664799 0.00037151931 + 11420 837.46667 0.0022501566 0.00036807932 + 11440 838.93333 0.0022340312 0.00036508287 + 11460 840.4 0.0022183033 0.00036190422 + 11480 841.86667 0.0022030817 0.00035916212 + 11500 843.33333 0.0021882572 0.00035628429 + 11520 844.8 0.0021735959 0.00035351859 + 11540 846.26667 0.0021589553 0.00035088484 + 11560 847.73333 0.002144383 0.00034780033 + 11580 849.2 0.0021300334 0.00034517904 + 11600 850.66667 0.0021160134 0.00034238069 + 11620 852.13333 0.0021022646 0.00034000514 + 11640 853.6 0.0020886207 0.00033719824 + 11660 855.06667 0.0020749807 0.00033475998 + 11680 856.53333 0.0020613877 0.0003323936 + 11700 858 0.002047954 0.0003295216 + 11720 859.46667 0.0020347589 0.00032713228 + 11740 860.93333 0.0020218117 0.00032474079 + 11760 862.4 0.0020091095 0.00032239213 + 11780 863.86667 0.0019966993 0.00031989799 + 11800 865.33333 0.0019846286 0.00031771663 + 11820 866.8 0.0019728573 0.0003157215 + 11840 868.26667 0.0019612776 0.00031355627 + 11860 869.73333 0.0019498221 0.00031127816 + 11880 871.2 0.0019385448 0.00030917103 + 11900 872.66667 0.0019275959 0.00030717234 + 11920 874.13333 0.0019170876 0.00030529115 + 11940 875.6 0.0019069791 0.00030345863 + 11960 877.06667 0.0018971139 0.00030170128 + 11980 878.53333 0.0018873555 0.0003001492 + 12000 880 0.0018776861 0.000298125 + 12020 881.46667 0.0018681863 0.0002963477 + 12040 882.93333 0.0018589294 0.00029463961 + 12060 884.4 0.0018499098 0.00029287916 + 12080 885.86667 0.0018410776 0.00029127697 + 12100 887.33333 0.0018324309 0.00028984289 + 12120 888.8 0.0018240594 0.00028840492 + 12140 890.26667 0.0018160961 0.00028702304 + 12160 891.73333 0.0018086145 0.00028549007 + 12180 893.2 0.0018015575 0.00028402955 + 12200 894.66667 0.0017947657 0.00028282399 + 12220 896.13333 0.0017880903 0.00028154717 + 12240 897.6 0.0017814942 0.00028017139 + 12260 899.06667 0.0017750529 0.00027900454 + 12280 900.53333 0.0017688698 0.00027808648 + 12300 902 0.0017629899 0.00027685309 + 12320 903.46667 0.0017573722 0.00027580637 + 12340 904.93333 0.0017519364 0.00027485838 + 12360 906.4 0.0017466397 0.00027394007 + 12380 907.86667 0.001741517 0.00027291856 + 12400 909.33333 0.0017366544 0.00027203238 + 12420 910.8 0.0017321325 0.00027110163 + 12440 912.26667 0.0017279827 0.00027027898 + 12460 913.73333 0.0017241867 0.00026956597 + 12480 915.2 0.0017207028 0.00026893832 + 12500 916.66667 0.0017174942 0.0002684279 + 12520 918.13333 0.0017145473 0.00026791943 + 12540 919.6 0.0017118647 0.00026744382 + 12560 921.06667 0.0017094489 0.00026685887 + 12580 922.53333 0.0017072871 0.00026638424 + 12600 924 0.0017053649 0.00026597657 + 12620 925.46667 0.0017036738 0.00026563478 + 12640 926.93333 0.0017022202 0.00026540665 + 12660 928.4 0.0017010329 0.00026520386 + 12680 929.86667 0.0017001522 0.00026507626 + 12700 931.33333 0.0016995942 0.00026477717 + 12720 932.8 0.0016993235 0.0002646703 + 12740 934.26667 0.0016992705 0.00026461169 + 12760 935.73333 0.0016993774 0.00026456725 + 12780 937.2 0.0016996306 0.00026455988 + 12800 938.66667 0.001700059 0.0002646213 + 12820 940.13333 0.0017007039 0.00026482076 + 12840 941.6 0.0017015791 0.00026487824 + 12860 943.06667 0.0017026482 0.00026493272 + 12880 944.53333 0.0017038391 0.00026510172 + 12900 946 0.0017050887 0.00026529547 + 12920 947.46667 0.0017063854 0.00026551572 + 12940 948.93333 0.001707774 0.00026599737 + 12960 950.4 0.0017093344 0.00026611126 + 12980 951.86667 0.0017111446 0.00026624827 + 13000 953.33333 0.0017132414 0.00026655284 + 13020 954.8 0.0017156029 0.00026692012 + 13040 956.26667 0.0017181728 0.00026731624 + 13060 957.73333 0.001720904 0.00026783066 + 13080 959.2 0.0017237902 0.00026836703 + 13100 960.66667 0.0017268644 0.0002689476 + 13120 962.13333 0.0017301659 0.0002694946 + 13140 963.6 0.0017336967 0.00026985524 + 13160 965.06667 0.0017374153 0.00027047141 + 13180 966.53333 0.0017412627 0.00027116583 + 13200 968 0.0017451982 0.00027186788 + 13220 969.46667 0.0017492157 0.00027241441 + 13240 970.93333 0.0017533345 0.00027303315 + 13260 972.4 0.001757579 0.00027374363 + 13280 973.86667 0.0017619627 0.00027451986 + 13300 975.33333 0.0017664863 0.00027525007 + 13320 976.8 0.0017711394 0.00027591661 + 13340 978.26667 0.0017759051 0.00027671531 + 13360 979.73333 0.0017807725 0.00027754179 + 13380 981.2 0.0017857381 0.00027848699 + 13400 982.66667 0.0017907994 0.00027931598 + 13420 984.13333 0.0017959473 0.00028027815 + 13440 985.6 0.0018011601 0.00028113792 + 13460 987.06667 0.0018064143 0.00028211623 + 13480 988.53333 0.0018117101 0.00028327908 + 13500 990 0.0018170864 0.00028409026 + 13520 991.46667 0.0018225918 0.00028501376 + 13540 992.93333 0.0018282476 0.00028596031 + 13560 994.4 0.0018340585 0.00028716447 + 13580 995.86667 0.0018400197 0.00028805463 + 13600 997.33333 0.0018461017 0.00028921664 + 13620 998.8 0.0018522484 0.00029037184 + 13640 1000.2667 0.0018583764 0.00029143019 + 13660 1001.7333 0.001864373 0.00029269198 + 13680 1003.2 0.0018701272 0.0002936223 + 13700 1004.6667 0.001875598 0.00029471055 + 13720 1006.1333 0.0018808354 0.00029567952 + 13740 1007.6 0.0018859376 0.00029685882 + 13760 1009.0667 0.0018910107 0.00029796198 + 13780 1010.5333 0.0018961401 0.00029897911 + 13800 1012 0.0019013893 0.0002998773 + 13820 1013.4667 0.0019068286 0.00030092291 + 13840 1014.9333 0.0019125242 0.00030190868 + 13860 1016.4 0.0019185061 0.00030309941 + 13880 1017.8667 0.001924749 0.00030441051 + 13900 1019.3333 0.0019311778 0.00030560739 + 13920 1020.8 0.001937711 0.00030711748 + 13940 1022.2667 0.0019442933 0.00030842988 + 13960 1023.7333 0.0019508956 0.00030970219 + 13980 1025.2 0.0019575153 0.00031088886 + 14000 1026.6667 0.0019641693 0.00031199334 + 14020 1028.1333 0.0019708823 0.00031333167 + 14040 1029.6 0.0019776662 0.0003147189 + 14060 1031.0667 0.0019845097 0.0003161484 + 14080 1032.5333 0.0019913915 0.00031776661 + 14100 1034 0.0019983071 0.00031912667 + 14120 1035.4667 0.0020052807 0.00032037968 + 14140 1036.9333 0.0020123438 0.00032176152 + 14160 1038.4 0.002019523 0.00032328697 + 14180 1039.8667 0.0020268687 0.00032480224 + 14200 1041.3333 0.0020344454 0.0003263506 + 14220 1042.8 0.0020422702 0.00032803708 + 14240 1044.2667 0.0020503074 0.00032950555 + 14260 1045.7333 0.0020584954 0.00033107602 + 14280 1047.2 0.0020667453 0.00033272838 + 14300 1048.6667 0.0020749518 0.00033440292 + 14320 1050.1333 0.0020830298 0.00033616301 + 14340 1051.6 0.0020909561 0.00033777436 + 14360 1053.0667 0.002098763 0.00033939304 + 14380 1054.5333 0.0021064571 0.00034108867 + 14400 1056 0.0021139812 0.00034279091 + 14420 1057.4667 0.0021212743 0.00034442447 + 14440 1058.9333 0.0021283312 0.00034608006 + 14460 1060.4 0.0021351913 0.00034766535 + 14480 1061.8667 0.0021418558 0.00034931633 + 14500 1063.3333 0.0021482781 0.00035065187 + 14520 1064.8 0.0021544661 0.00035206483 + 14540 1066.2667 0.0021605274 0.00035349517 + 14560 1067.7333 0.0021666138 0.00035497387 + 14580 1069.2 0.002172775 0.00035650749 + 14600 1070.6667 0.0021789434 0.00035816361 + 14620 1072.1333 0.0021850567 0.00035981347 + 14640 1073.6 0.0021911017 0.00036119002 + 14660 1075.0667 0.0021970459 0.00036263527 + 14680 1076.5333 0.002202891 0.00036408979 + 14700 1078 0.0022086678 0.00036558706 + 14720 1079.4667 0.0022143659 0.00036708363 + 14740 1080.9333 0.0022200095 0.00036872316 + 14760 1082.4 0.0022256795 0.00037031852 + 14780 1083.8667 0.0022314598 0.00037172104 + 14800 1085.3333 0.0022373988 0.00037326473 + 14820 1086.8 0.0022435042 0.00037481567 + 14840 1088.2667 0.0022497418 0.0003767171 + 14860 1089.7333 0.0022560684 0.00037860978 + 14880 1091.2 0.002262451 0.00038015024 + 14900 1092.6667 0.0022688473 0.00038171512 + 14920 1094.1333 0.0022751666 0.00038333305 + 14940 1095.6 0.0022812118 0.00038546448 + 14960 1097.0667 0.0022867513 0.00038693328 + 14980 1098.5333 0.0022917745 0.00038844788 + 15000 1100 0.002296287 0.00038988563 + 15020 1101.4667 0.0022999653 0.00039138878 + 15040 1102.9333 0.0023028622 0.00039244167 + 15060 1104.4 0.002305798 0.00039349216 + 15080 1105.8667 0.0023089263 0.00039463979 + 15100 1107.3333 0.0023120599 0.00039582741 + 15120 1108.8 0.0023154124 0.00039746408 + 15140 1110.2667 0.0023192069 0.00039877981 + 15160 1111.7333 0.0023234403 0.00040024924 + 15180 1113.2 0.0023275332 0.00040194985 + 15200 1114.6667 0.0023309379 0.00040319063 + 15220 1116.1333 0.0023333104 0.0004046024 + 15240 1117.6 0.0023350271 0.00040564766 + 15260 1119.0667 0.0023370916 0.00040733425 + 15280 1120.5333 0.0023395929 0.00040838933 + 15300 1122 0.0023424998 0.00040987095 + 15320 1123.4667 0.0023453536 0.00041107287 + 15340 1124.9333 0.0023473165 0.00041242318 + 15360 1126.4 0.0023477134 0.00041322951 + 15380 1127.8667 0.0023491753 0.0004146031 + 15400 1129.3333 0.0023509302 0.00041566144 + 15420 1130.8 0.0023529326 0.00041714975 + 15440 1132.2667 0.0023554779 0.00041837505 + 15460 1133.7333 0.0023580661 0.00042017965 + 15480 1135.2 0.0023607312 0.0004213224 + 15500 1136.6667 0.0023635957 0.00042300666 + 15520 1138.1333 0.0023666602 0.00042436098 + 15540 1139.6 0.0023691001 0.0004260457 + 15560 1141.0667 0.0023700594 0.00042714685 + 15580 1142.5333 0.0023705741 0.00042853206 + 15600 1144 0.0023711825 0.00042951675 + 15620 1145.4667 0.002371987 0.00043109076 + 15640 1146.9333 0.0023732281 0.00043221551 + 15660 1148.4 0.0023749382 0.00043370865 + 15680 1149.8667 0.0023770404 0.00043490458 + 15700 1151.3333 0.0023793818 0.0004365297 + 15720 1152.8 0.0023816701 0.00043819097 + 15740 1154.2667 0.0023836808 0.00043980236 + 15760 1155.7333 0.0023856065 0.00044146758 + 15780 1157.2 0.0023876705 0.0004433163 + 15800 1158.6667 0.0023898905 0.00044465376 + 15820 1160.1333 0.0023918799 0.00044645614 + 15840 1161.6 0.0023914238 0.00044759356 + 15860 1163.0667 0.0023885514 0.00044839265 + 15880 1164.5333 0.0023867062 0.00044939387 + 15900 1166 0.0023853424 0.00045041476 + 15920 1167.4667 0.0023837839 0.00045152066 + 15940 1168.9333 0.0023823865 0.00045222801 + 15960 1170.4 0.0023800327 0.00045327302 + 15980 1171.8667 0.0023735917 0.00045357981 + 16000 1173.3333 0.0023643861 0.00045337685 + 16020 1174.8 0.0023565577 0.00045352436 + 16040 1176.2667 0.0023484436 0.00045344895 + 16060 1177.7333 0.0023408376 0.00045346696 + 16080 1179.2 0.0023326737 0.00045286966 + 16100 1180.6667 0.0023236531 0.00045261832 + 16120 1182.1333 0.0023169178 0.00045293394 + 16140 1183.6 0.0023111828 0.00045311831 + 16160 1185.0667 0.0023064172 0.00045378709 + 16180 1186.5333 0.002302184 0.00045455946 + 16200 1188 0.0022983621 0.00045539262 + 16220 1189.4667 0.0022953512 0.00045591645 + 16240 1190.9333 0.0022929801 0.00045712856 + 16260 1192.4 0.0022909009 0.00045847159 + 16280 1193.8667 0.0022885525 0.00045961196 + 16300 1195.3333 0.0022855688 0.00046061347 + 16320 1196.8 0.002282828 0.00046188788 + 16340 1198.2667 0.0022802183 0.00046302244 + 16360 1199.7333 0.0022773774 0.00046375719 + 16380 1201.2 0.0022731903 0.00046492183 + 16400 1202.6667 0.0022645201 0.00046516447 + 16420 1204.1333 0.0022568251 0.00046542882 + 16440 1205.6 0.0022422695 0.00046437586 + 16460 1207.0667 0.0022155713 0.00046051887 + 16480 1208.5333 0.0022035759 0.00046001297 + 16500 1210 0.002190894 0.00045893493 + 16520 1211.4667 0.0021802322 0.00045942457 + 16540 1212.9333 0.0021704133 0.000459471 + 16560 1214.4 0.0021615234 0.00045918488 + 16580 1215.8667 0.0021529915 0.00045936006 + 16600 1217.3333 0.0021451373 0.00045959338 + 16620 1218.8 0.0021383906 0.0004600505 + 16640 1220.2667 0.0021325315 0.00046005064 + 16660 1221.7333 0.0021277429 0.00046108228 + 16680 1223.2 0.0021237755 0.00046243368 + 16700 1224.6667 0.0021203172 0.00046394738 + 16720 1226.1333 0.0021172137 0.00046532716 + 16740 1227.6 0.0021142084 0.00046719106 + 16760 1229.0667 0.0021110689 0.00046854799 + 16780 1230.5333 0.0021077864 0.00046991776 + 16800 1232 0.0021045002 0.00047183286 + 16820 1233.4667 0.0021013226 0.00047317989 + 16840 1234.9333 0.002098386 0.0004747552 + 16860 1236.4 0.0020957505 0.00047738008 + 16880 1237.8667 0.0020931882 0.0004792455 + 16900 1239.3333 0.0020905705 0.00048104549 + 16920 1240.8 0.0020878895 0.00048403265 + 16940 1242.2667 0.0020853857 0.00048573735 + 16960 1243.7333 0.0020831358 0.00048728108 + 16980 1245.2 0.0020808323 0.00048952128 + 17000 1246.6667 0.0020784817 0.00049099168 + 17020 1248.1333 0.0020761732 0.00049278614 + 17040 1249.6 0.0020739063 0.00049556886 + 17060 1251.0667 0.0020717239 0.00049826766 + 17080 1252.5333 0.0020697361 0.00050040771 + 17100 1254 0.0020679208 0.00050266159 + 17120 1255.4667 0.0020661569 0.00050465637 + 17140 1256.9333 0.0020645102 0.00050644859 + 17160 1258.4 0.002063175 0.00050945115 + 17180 1259.8667 0.0020620744 0.00051135072 + 17200 1261.3333 0.0020578831 0.00051271416 + 17220 1262.8 0.002036801 0.00051070868 + 17240 1264.2667 0.0020246474 0.0005105671 + 17260 1265.7333 0.0020154083 0.00051056266 + 17280 1267.2 0.0020081398 0.00051203914 + 17300 1268.6667 0.0020033592 0.00051368703 + 17320 1270.1333 0.0019993325 0.00051565203 + 17340 1271.6 0.0019965177 0.00051918806 + 17360 1273.0667 0.0019938276 0.000522221 + 17380 1274.5333 0.0019914867 0.00052433401 + 17400 1276 0.0019892544 0.0005278718 + 17420 1277.4667 0.0019871107 0.00052787286 + 17440 1278.9333 0.0019850499 0.00052722809 + 17460 1280.4 0.0019830428 0.0005263569 + 17480 1281.8667 0.0019811987 0.00052588328 + 17500 1283.3333 0.0019795831 0.00052534586 + 17520 1284.8 0.0019781827 0.00052537295 + 17540 1286.2667 0.0019770664 0.00052509105 + 17560 1287.7333 0.0019762397 0.00052445472 + 17580 1289.2 0.0019755625 0.0005240242 + 17600 1290.6667 0.001974964 0.00052397078 + 17620 1292.1333 0.0019744966 0.00052447005 + 17640 1293.6 0.0019741078 0.00052446447 + 17660 1295.0667 0.0019735916 0.0005241986 + 17680 1296.5333 0.001972809 0.00052362297 + 17700 1298 0.0019718021 0.00052322362 + 17720 1299.4667 0.0019707205 0.00052316488 + 17740 1300.9333 0.0019696972 0.00052280952 + 17760 1302.4 0.0019687912 0.00052267588 + 17780 1303.8667 0.0019679901 0.00052231283 + 17800 1305.3333 0.0019672622 0.00052253006 + 17820 1306.8 0.0019665862 0.00052301876 + 17840 1308.2667 0.0019659299 0.00052301364 + 17860 1309.7333 0.00196528 0.0005229424 + 17880 1311.2 0.0019646495 0.00052264866 + 17900 1312.6667 0.0019640476 0.00052292066 + 17920 1314.1333 0.0019634587 0.0005229915 + 17940 1315.6 0.0019628594 0.00052284877 + 17960 1317.0667 0.0019622352 0.00052292872 + 17980 1318.5333 0.0019612399 0.00052337341 + 18000 1320 0.0019519628 0.00052094399 + 18020 1321.4667 0.0019343509 0.00051533063 + 18040 1322.9333 0.0019199585 0.00051174103 + 18060 1324.4 0.001905945 0.00050822167 + 18080 1325.8667 0.0018954044 0.00050571386 + 18100 1327.3333 0.0018867099 0.0005045138 + 18120 1328.8 0.0018790423 0.00050281498 + 18140 1330.2667 0.0018724677 0.00050092806 + 18160 1331.7333 0.0018669293 0.00049977801 + 18180 1333.2 0.0018621946 0.0004988236 + 18200 1334.6667 0.0018581668 0.00049860903 + 18220 1336.1333 0.0018546088 0.00049734989 + 18240 1337.6 0.001851507 0.00049612125 + 18260 1339.0667 0.0018488437 0.00049539768 + 18280 1340.5333 0.0018464974 0.00049462331 + 18300 1342 0.0018441554 0.00049419987 + 18320 1343.4667 0.0018418357 0.00049359519 + 18340 1344.9333 0.0018400699 0.00049361929 + 18360 1346.4 0.0018391163 0.0004934397 + 18380 1347.8667 0.0018386451 0.00049401695 + 18400 1349.3333 0.0018382434 0.00049404913 + 18420 1350.8 0.0018377762 0.00049284789 + 18440 1352.2667 0.0018373163 0.00049253988 + 18460 1353.7333 0.0018368769 0.00049170154 + 18480 1355.2 0.00183642 0.00049134218 + 18500 1356.6667 0.0018359651 0.00049049622 + 18520 1358.1333 0.0018355476 0.00049018604 + 18540 1359.6 0.0018351502 0.00049009857 + 18560 1361.0667 0.0018347415 0.00049034975 + 18580 1362.5333 0.0018343456 0.00048962734 + 18600 1364 0.0018340032 0.00048910267 + 18620 1365.4667 0.0018337131 0.000489678 + 18640 1366.9333 0.0018334434 0.00048942363 + 18660 1368.4 0.0018331908 0.00048883791 + 18680 1369.8667 0.0018330003 0.00048842189 + 18700 1371.3333 0.0018328613 0.00048778042 + 18720 1372.8 0.0018326423 0.0004879605 + 18740 1374.2667 0.0018322085 0.00048760414 + 18760 1375.7333 0.0018316466 0.00048749865 + 18780 1377.2 0.0018311569 0.00048717362 + 18800 1378.6667 0.0018307322 0.0004871375 + 18820 1380.1333 0.0018303267 0.00048680704 + 18840 1381.6 0.0018299711 0.00048676556 + 18860 1383.0667 0.0018296776 0.00048663795 + 18880 1384.5333 0.0018294387 0.00048659964 + 18900 1386 0.0018292809 0.00048698663 + 18920 1387.4667 0.0018292225 0.00048709797 + 18940 1388.9333 0.0018292283 0.0004870647 + 18960 1390.4 0.0018292259 0.00048674819 + 18980 1391.8667 0.0018291569 0.00048679582 + 19000 1393.3333 0.0018290098 0.00048689638 + 19020 1394.8 0.001828716 0.00048714893 + 19040 1396.2667 0.0018281487 0.00048793626 + 19060 1397.7333 0.0018274368 0.00048766312 + 19080 1399.2 0.0018267859 0.00048800122 + 19100 1400.6667 0.0018262357 0.00048767989 + 19120 1402.1333 0.001825769 0.0004870923 + 19140 1403.6 0.001825325 0.00048705214 + 19160 1405.0667 0.0018249161 0.00048807286 + 19180 1406.5333 0.0018245622 0.0004872987 + 19200 1408 0.001824239 0.00048742747 + 19220 1409.4667 0.0018239467 0.00048750738 + 19240 1410.9333 0.0018230912 0.00048779822 + 19260 1412.4 0.0018134463 0.00048497862 + 19280 1413.8667 0.0018021878 0.00048230785 + 19300 1415.3333 0.0017955735 0.00048083973 + 19320 1416.8 0.0017872753 0.0004788259 + 19340 1418.2667 0.0017779883 0.00047646403 + 19360 1419.7333 0.0017738211 0.00047574559 + 19380 1421.2 0.0017704561 0.00047501448 + 19400 1422.6667 0.0017677224 0.00047433091 + 19420 1424.1333 0.0017653706 0.00047260445 + 19440 1425.6 0.0017632679 0.00047170106 + 19460 1427.0667 0.0017613642 0.00047105927 + 19480 1428.5333 0.001759646 0.00047082774 + 19500 1430 0.001758063 0.00047009269 + 19520 1431.4667 0.0017566191 0.00046954867 + 19540 1432.9333 0.0017551775 0.00046892643 + 19560 1434.4 0.0017536259 0.00046842898 + 19580 1435.8667 0.0017521006 0.00046822248 + 19600 1437.3333 0.0017508378 0.00046758045 + 19620 1438.8 0.0017499266 0.0004680761 + 19640 1440.2667 0.0017492698 0.00046815863 + 19660 1441.7333 0.0017486531 0.00046811847 + 19680 1443.2 0.0017479735 0.00046864003 + 19700 1444.6667 0.0017472425 0.00046795012 + 19720 1446.1333 0.0017465091 0.0004669531 + 19740 1447.6 0.0017458236 0.00046666543 + 19760 1449.0667 0.0017452108 0.00046610386 + 19780 1450.5333 0.0017446777 0.00046578676 + 19800 1452 0.0017442315 0.00046559966 + 19820 1453.4667 0.0017438755 0.00046570962 + 19840 1454.9333 0.0017435917 0.00046591684 + 19860 1456.4 0.0017433538 0.00046605781 + 19880 1457.8667 0.0017431368 0.0004662092 + 19900 1459.3333 0.0017429113 0.00046639344 + 19920 1460.8 0.0017426466 0.00046609654 + 19940 1462.2667 0.0017423307 0.00046558461 + 19960 1463.7333 0.0017419767 0.00046538275 + 19980 1465.2 0.0017416057 0.00046473626 + 20000 1466.6667 0.0017412248 0.00046427697 + 20020 1468.1333 0.0017408365 0.00046360441 + 20040 1469.6 0.0017404537 0.00046250116 + 20060 1471.0667 0.0017400878 0.00046219676 + 20080 1472.5333 0.0017397348 0.0004620366 + 20100 1474 0.0017393906 0.00046142035 + 20120 1475.4667 0.0017390634 0.00046119888 + 20140 1476.9333 0.0017387599 0.00046114118 + 20160 1478.4 0.0017384654 0.00046119273 + 20180 1479.8667 0.0017381599 0.00046112037 + 20200 1481.3333 0.001737838 0.00046085119 + 20220 1482.8 0.0017374971 0.00046088054 + 20240 1484.2667 0.0017371388 0.00046097027 + 20260 1485.7333 0.0017368201 0.00046112449 + 20280 1487.2 0.0017365948 0.00046064697 + 20300 1488.6667 0.0017364148 0.00046068874 + 20320 1490.1333 0.001736224 0.00046068502 + 20340 1491.6 0.0017360297 0.00046057861 + 20360 1493.0667 0.0017358482 0.00046044137 + 20380 1494.5333 0.0017356781 0.00046043159 + 20400 1496 0.0017355222 0.00046062752 + 20420 1497.4667 0.0017353902 0.00046067799 + 20440 1498.9333 0.0017352915 0.00046071384 + 20460 1500.4 0.0017352299 0.00046111809 + 20480 1501.8667 0.0017352025 0.0004613299 + 20500 1503.3333 0.0017352027 0.00046183541 + 20520 1504.8 0.0017352278 0.00046106542 + 20540 1506.2667 0.0017352815 0.00046149717 + 20560 1507.7333 0.0017353649 0.00046105371 + 20580 1509.2 0.0017354697 0.00046104238 + 20600 1510.6667 0.0017355805 0.00046116932 + 20620 1512.1333 0.001735681 0.00046162233 + 20640 1513.6 0.001735758 0.00046178245 + 20660 1515.0667 0.0017358047 0.00046196886 + 20680 1516.5333 0.0017358199 0.00046215457 + 20700 1518 0.0017358084 0.00046228161 + 20720 1519.4667 0.0017357806 0.00046261955 + 20740 1520.9333 0.0017357486 0.00046271037 + 20760 1522.4 0.0017357257 0.00046257919 + 20780 1523.8667 0.0017357263 0.00046250064 + 20800 1525.3333 0.0017357658 0.00046146349 + 20820 1526.8 0.0017358584 0.00046138905 + 20840 1528.2667 0.0017360144 0.00046135266 + 20860 1529.7333 0.0017362378 0.00046136088 + 20880 1531.2 0.0017365251 0.00046203214 + 20900 1532.6667 0.0017368656 0.00046240805 + 20920 1534.1333 0.0017372463 0.00046245586 + 20940 1535.6 0.0017376552 0.00046233017 + 20960 1537.0667 0.0017380838 0.00046211905 + 20980 1538.5333 0.0017385273 0.00046221175 + 21000 1540 0.0017389813 0.0004623322 + 21020 1541.4667 0.0017394408 0.00046248895 + 21040 1542.9333 0.0017399011 0.00046262683 + 21060 1544.4 0.0017403582 0.0004628631 + 21080 1545.8667 0.0017408086 0.00046287413 + 21100 1547.3333 0.0017412486 0.00046253863 + 21120 1548.8 0.0017416739 0.00046239188 + 21140 1550.2667 0.0017420824 0.00046252093 + 21160 1551.7333 0.0017424775 0.00046243663 + 21180 1553.2 0.0017428687 0.00046231674 + 21200 1554.6667 0.0017432678 0.00046228047 + 21220 1556.1333 0.0017436835 0.00046205345 + 21240 1557.6 0.0017441181 0.00046191794 + 21260 1559.0667 0.001744567 0.00046187817 + 21280 1560.5333 0.00174502 0.00046195933 + 21300 1562 0.0017454629 0.00046207568 + 21320 1563.4667 0.0017458791 0.00046237686 + 21340 1564.9333 0.0017462532 0.00046251185 + 21360 1566.4 0.00174658 0.00046256338 + 21380 1567.8667 0.0017468761 0.00046258103 + 21400 1569.3333 0.0017471787 0.00046203359 + 21420 1570.8 0.0017475092 0.00046236915 + 21440 1572.2667 0.0017478285 0.00046240886 + 21460 1573.7333 0.0017480488 0.00046268024 + 21480 1575.2 0.0017481357 0.00046249851 + 21500 1576.6667 0.0017481758 0.00046252177 + 21520 1578.1333 0.0017482237 0.00046224255 + 21540 1579.6 0.0017482326 0.00046244066 + 21560 1581.0667 0.0017481857 0.0004626825 + 21580 1582.5333 0.0017481066 0.00046272441 + 21600 1584 0.0017480121 0.00046281669 + 21620 1585.4667 0.0017479031 0.0004630027 + 21640 1586.9333 0.0017477655 0.00046237554 + 21660 1588.4 0.0017475794 0.00046236536 + 21680 1589.8667 0.0017473246 0.00046234947 + 21700 1591.3333 0.0017469863 0.00046229056 + 21720 1592.8 0.0017465596 0.00046226293 + 21740 1594.2667 0.0017460487 0.00046221488 + 21760 1595.7333 0.0017454604 0.00046228835 + 21780 1597.2 0.0017447972 0.00046224033 + 21800 1598.6667 0.0017440567 0.00046196921 + 21820 1600.1333 0.0017432373 0.00046193024 + 21840 1601.6 0.0017423442 0.00046190113 + 21860 1603.0667 0.0017413885 0.00046182645 + 21880 1604.5333 0.0017403804 0.00046153595 + 21900 1606 0.0017393239 0.00046141594 + 21920 1607.4667 0.0017382204 0.00046059163 + 21940 1608.9333 0.0017370711 0.00046011476 + 21960 1610.4 0.0017358772 0.00045995874 + 21980 1611.8667 0.001734638 0.00045946276 + 22000 1613.3333 0.0017333523 0.00045909152 + 22020 1614.8 0.0017320214 0.00045871657 + 22040 1616.2667 0.0017306506 0.00045875126 + 22060 1617.7333 0.001729244 0.00045851969 + 22080 1619.2 0.0017277891 0.00045815 + 22100 1620.6667 0.0017262472 0.00045800503 + 22120 1622.1333 0.0017245557 0.00045722613 + 22140 1623.6 0.0017226312 0.00045612428 + 22160 1625.0667 0.0017203846 0.00045558148 + 22180 1626.5333 0.0017177538 0.00045493102 + 22200 1628 0.0017147219 0.00045354235 + 22220 1629.4667 0.0017113235 0.00045252377 + 22240 1630.9333 0.0017076396 0.00045148679 + 22260 1632.4 0.0017037869 0.00045053035 + 22280 1633.8667 0.0016998953 0.0004495377 + 22300 1635.3333 0.0016960489 0.00044816777 + 22320 1636.8 0.0016922401 0.00044714973 + 22340 1638.2667 0.0016884053 0.00044610277 + 22360 1639.7333 0.0016844703 0.00044568763 + 22380 1641.2 0.0016803511 0.00044439173 + 22400 1642.6667 0.0016759401 0.00044314089 + 22420 1644.1333 0.0016711286 0.00044193566 + 22440 1645.6 0.0016658281 0.0004406589 + 22460 1647.0667 0.0016599393 0.00043844661 + 22480 1648.5333 0.001653471 0.00043656014 + 22500 1650 0.0016466439 0.00043470146 + 22520 1651.4667 0.0016396283 0.00043288723 + 22540 1652.9333 0.0016322717 0.00043091896 + 22560 1654.4 0.0016242406 0.00042878807 + 22580 1655.8667 0.0016143541 0.00042598276 + 22600 1657.3333 0.0015984531 0.00042184208 + 22620 1658.8 0.0015774545 0.00041639723 + 22640 1660.2667 0.0015581678 0.00041151234 + 22660 1661.7333 0.0015392455 0.0004074519 + 22680 1663.2 0.0015238703 0.0004031907 + 22700 1664.6667 0.0015082033 0.00039905746 + 22720 1666.1333 0.0014910701 0.00039410593 + 22740 1667.6 0.0014773215 0.00039023578 + 22760 1669.0667 0.0014646054 0.00038693028 + 22780 1670.5333 0.0014509254 0.00038338321 + 22800 1672 0.0014387044 0.00038022989 + 22820 1673.4667 0.0014276038 0.00037738369 + 22840 1674.9333 0.0014165206 0.00037467759 + 22860 1676.4 0.0014054416 0.00037186956 + 22880 1677.8667 0.0013942654 0.00036919292 + 22900 1679.3333 0.0013833555 0.00036666326 + 22920 1680.8 0.0013733025 0.00036390292 + 22940 1682.2667 0.001364207 0.00036143657 + 22960 1683.7333 0.001355472 0.00035947361 + 22980 1685.2 0.0013467462 0.00035649775 + 23000 1686.6667 0.0013381467 0.00035425964 + 23020 1688.1333 0.0013298724 0.00035194314 + 23040 1689.6 0.0013219998 0.0003499467 + 23060 1691.0667 0.0013145189 0.00034806194 + 23080 1692.5333 0.0013073428 0.00034626601 + 23100 1694 0.0013004081 0.00034470285 + 23120 1695.4667 0.0012935813 0.00034306885 + 23140 1696.9333 0.0012865972 0.0003412658 + 23160 1698.4 0.0012792092 0.00033945219 + 23180 1699.8667 0.0012712869 0.00033750315 + 23200 1701.3333 0.0012627886 0.0003353201 + 23220 1702.8 0.001253784 0.00033296654 + 23240 1704.2667 0.0012445082 0.00033053745 + 23260 1705.7333 0.001235266 0.00032759425 + 23280 1707.2 0.0012261717 0.000325215 + 23300 1708.6667 0.0012168943 0.00032279239 + 23320 1710.1333 0.0012071081 0.00032042001 + 23340 1711.6 0.0011971594 0.00031782638 + 23360 1713.0667 0.0011876725 0.00031524799 + 23380 1714.5333 0.0011786269 0.00031289556 + 23400 1716 0.001169404 0.00031049786 + 23420 1717.4667 0.0011595669 0.00030723977 + 23440 1718.9333 0.001149266 0.00030443096 + 23460 1720.4 0.001138992 0.00030161041 + 23480 1721.8667 0.001129081 0.00029923744 + 23500 1723.3333 0.0011195152 0.00029668379 + 23520 1724.8 0.0011100863 0.00029417354 + 23540 1726.2667 0.0011005982 0.00029164586 + 23560 1727.7333 0.0010910778 0.0002889626 + 23580 1729.2 0.0010816854 0.00028655072 + 23600 1730.6667 0.001072494 0.00028419823 + 23620 1732.1333 0.0010634481 0.00028189699 + 23640 1733.6 0.0010544699 0.00027928614 + 23660 1735.0667 0.0010455565 0.00027694249 + 23680 1736.5333 0.0010367472 0.00027466258 + 23700 1738 0.0010280561 0.00027240232 + 23720 1739.4667 0.0010194696 0.00027014395 + 23740 1740.9333 0.0010109726 0.00026815472 + 23760 1742.4 0.0010025582 0.00026636602 + 23780 1743.8667 0.00099420961 0.0002639384 + 23800 1745.3333 0.00098589439 0.00026185788 + 23820 1746.8 0.00097758322 0.00025980082 + 23840 1748.2667 0.00096925998 0.00025767237 + 23860 1749.7333 0.00096092015 0.00025564227 + 23880 1751.2 0.00095256615 0.0002533114 + 23900 1752.6667 0.00094419511 0.00025115421 + 23920 1754.1333 0.00093579195 0.00024903122 + 23940 1755.6 0.00092733111 0.00024683875 + 23960 1757.0667 0.00091878509 0.00024461091 + 23980 1758.5333 0.00091013147 0.00024236826 + 24000 1760 0.00090135324 0.0002404806 + 24020 1761.4667 0.00089243423 0.0002380936 + 24040 1762.9333 0.00088336053 0.00023549546 + 24060 1764.4 0.00087412784 0.00023319301 + 24080 1765.8667 0.00086474945 0.00023084155 + 24100 1767.3333 0.00085525774 0.00022851664 + 24120 1768.8 0.0008456963 0.00022615872 + 24140 1770.2667 0.00083610859 0.00022375601 + 24160 1771.7333 0.00082652908 0.00022120807 + 24180 1773.2 0.00081698057 0.00021815795 + 24200 1774.6667 0.00080747609 0.00021555543 + 24220 1776.1333 0.00079802183 0.00021298564 + 24240 1777.6 0.00078862131 0.00021045545 + 24260 1779.0667 0.00077927933 0.00020806904 + 24280 1780.5333 0.00077000523 0.0002058181 + 24300 1782 0.00076081568 0.00020320246 + 24320 1783.4667 0.00075173462 0.00020084308 + 24340 1784.9333 0.0007427896 0.00019868422 + 24360 1786.4 0.00073400423 0.00019651532 + 24380 1787.8667 0.00072538996 0.00019445357 + 24400 1789.3333 0.00071694344 0.00019222062 + 24420 1790.8 0.00070865664 0.0001900288 + 24440 1792.2667 0.00070053087 0.00018789961 + 24460 1793.7333 0.00069258266 0.0001848306 + 24480 1795.2 0.00068483291 0.00018274366 + 24500 1796.6667 0.00067729047 0.00018074446 + 24520 1798.1333 0.00066994193 0.00017882986 + 24540 1799.6 0.00066275021 0.00017698882 + 24560 1801.0667 0.00065565627 0.00017510426 + 24580 1802.5333 0.00064858738 0.00017328965 + 24600 1804 0.00064147322 0.00017147388 + 24620 1805.4667 0.00063426805 0.00016964736 + 24640 1806.9333 0.0006269663 0.00016781232 + 24660 1808.4 0.00061960354 0.00016597943 + 24680 1809.8667 0.00061223634 0.00016419561 + 24700 1811.3333 0.00060491662 0.00016237355 + 24720 1812.8 0.00059767953 0.00016075431 + 24740 1814.2667 0.00059053949 0.00015905558 + 24760 1815.7333 0.00058349084 0.00015739614 + 24780 1817.2 0.0005765115 0.00015502575 + 24800 1818.6667 0.0005695693 0.00015330761 + 24820 1820.1333 0.00056263283 0.00015162196 + 24840 1821.6 0.00055568243 0.00014995088 + 24860 1823.0667 0.00054871692 0.00014819243 + 24880 1824.5333 0.00054175223 0.00014652991 + 24900 1826 0.00053481455 0.00014490663 + 24920 1827.4667 0.00052793142 0.00014324987 + 24940 1828.9333 0.00052112566 0.00014156756 + 24960 1830.4 0.00051441308 0.0001397807 + 24980 1831.8667 0.00050780341 0.00013808181 + 25000 1833.3333 0.0005013017 0.00013637046 + 25020 1834.8 0.00049490926 0.00013464589 + 25040 1836.2667 0.00048862482 0.00013292356 + 25060 1837.7333 0.0004824453 0.0001314188 + 25080 1839.2 0.00047636617 0.0001293314 + 25100 1840.6667 0.00047038116 0.00012754146 + 25120 1842.1333 0.00046448251 0.00012554913 + 25140 1843.6 0.0004586615 0.00012383425 + 25160 1845.0667 0.00045290921 0.00012215229 + 25180 1846.5333 0.00044721746 0.00012074608 + 25200 1848 0.00044157971 0.0001189818 + 25220 1849.4667 0.00043599245 0.00011737642 + 25240 1850.9333 0.00043045564 0.00011575387 + 25260 1852.4 0.00042497205 0.00011421704 + 25280 1853.8667 0.00041954608 0.00011269281 + 25300 1855.3333 0.00041418267 0.00011124707 + 25320 1856.8 0.0004088869 0.00010985539 + 25340 1858.2667 0.00040366377 0.00010856688 + 25360 1859.7333 0.0003985179 0.00010747086 + 25380 1861.2 0.00039345294 0.00010624143 + 25400 1862.6667 0.00038847115 0.00010464611 + 25420 1864.1333 0.00038357328 0.00010342367 + 25440 1865.6 0.00037875866 0.00010197951 + 25460 1867.0667 0.0003740255 0.00010083387 + 25480 1868.5333 0.00036937131 9.9727459e-05 + 25500 1870 0.00036479358 9.8715792e-05 + 25520 1871.4667 0.00036029053 9.7693667e-05 + 25540 1872.9333 0.00035586162 9.6659947e-05 + 25560 1874.4 0.00035150779 9.5730365e-05 + 25580 1875.8667 0.000347231 9.4850676e-05 + 25600 1877.3333 0.00034303359 9.4132269e-05 + 25620 1878.8 0.00033891749 9.3355928e-05 + 25640 1880.2667 0.00033488372 9.282199e-05 + 25660 1881.7333 0.00033093187 9.2101633e-05 + 25680 1883.2 0.00032705982 9.1331225e-05 + 25700 1884.6667 0.00032326391 8.9490029e-05 + 25720 1886.1333 0.0003195392 8.8603192e-05 + 25740 1887.6 0.00031588037 8.7694411e-05 + 25760 1889.0667 0.0003122828 8.6761483e-05 + 25780 1890.5333 0.00030874312 8.5806827e-05 + 25800 1892 0.00030525908 8.4835735e-05 + 25820 1893.4667 0.00030182927 8.402954e-05 + 25840 1894.9333 0.00029845296 8.3049666e-05 + 25860 1896.4 0.00029512991 8.211056e-05 + 25880 1897.8667 0.00029186078 8.1134374e-05 + 25900 1899.3333 0.00028864743 8.0199975e-05 + 25920 1900.8 0.00028549282 7.9325687e-05 + 25940 1902.2667 0.0002824008 7.8437438e-05 + 25960 1903.7333 0.00027937535 7.7544386e-05 + 25980 1905.2 0.00027642007 7.6706594e-05 + 26000 1906.6667 0.00027353814 7.579826e-05 + 26020 1908.1333 0.00027073244 7.5008665e-05 + 26040 1909.6 0.00026800557 7.4544912e-05 + 26060 1911.0667 0.00026535971 7.3786981e-05 + 26080 1912.5333 0.00026279611 7.2166049e-05 + 26100 1914 0.00026031456 7.1403392e-05 + 26120 1915.4667 0.00025791305 7.0702466e-05 + 26140 1916.9333 0.00025558794 7.0006351e-05 + 26160 1918.4 0.00025333488 6.9317329e-05 + 26180 1919.8667 0.00025115003 6.8688062e-05 + 26200 1921.3333 0.00024903038 6.8122851e-05 + 26220 1922.8 0.00024697358 6.7568833e-05 + 26240 1924.2667 0.00024497771 6.6968209e-05 + 26260 1925.7333 0.00024304157 6.6501986e-05 + 26280 1927.2 0.0002411651 6.6088755e-05 + 26300 1928.6667 0.00023934939 6.5705322e-05 + 26320 1930.1333 0.00023759592 6.5362857e-05 + 26340 1931.6 0.00023590514 6.5049803e-05 + 26360 1933.0667 0.00023427484 6.473807e-05 + 26380 1934.5333 0.00023269956 6.4466061e-05 + 26400 1936 0.00023117121 6.4080253e-05 + 26420 1937.4667 0.0002296809 6.3752394e-05 + 26440 1938.9333 0.00022822123 6.3357126e-05 + 26460 1940.4 0.00022678837 6.3049852e-05 + 26480 1941.8667 0.00022538306 6.2753673e-05 + 26500 1943.3333 0.00022400995 6.2294535e-05 + 26520 1944.8 0.00022267608 6.2038117e-05 + 26540 1946.2667 0.00022138844 6.1782883e-05 + 26560 1947.7333 0.00022015168 6.1574119e-05 + 26580 1949.2 0.00021896802 6.1384003e-05 + 26600 1950.6667 0.00021783788 6.1156768e-05 + 26620 1952.1333 0.00021676111 6.0986244e-05 + 26640 1953.6 0.0002157381 6.0849325e-05 + 26660 1955.0667 0.00021477001 6.0683878e-05 + 26680 1956.5333 0.00021385807 6.0516059e-05 + 26700 1958 0.00021300223 6.0329517e-05 + 26720 1959.4667 0.00021220038 6.0110922e-05 + 26740 1960.9333 0.0002114485 5.9940604e-05 + 26760 1962.4 0.00021074077 5.977174e-05 + 26780 1963.8667 0.00021007047 5.9606511e-05 + 26800 1965.3333 0.00020943091 5.9060466e-05 + 26820 1966.8 0.00020881619 5.8839697e-05 + 26840 1968.2667 0.00020822134 5.8633638e-05 + 26860 1969.7333 0.00020764269 5.8541664e-05 + 26880 1971.2 0.0002070779 5.83276e-05 + 26900 1972.6667 0.00020652606 5.8076903e-05 + 26920 1974.1333 0.00020598762 5.7951516e-05 + 26940 1975.6 0.00020546407 5.7793633e-05 + 26960 1977.0667 0.00020495767 5.7642438e-05 + 26980 1978.5333 0.00020447095 5.7497463e-05 + 27000 1980 0.00020400643 5.7358967e-05 + 27020 1981.4667 0.00020356638 5.7197798e-05 + 27040 1982.9333 0.00020315297 5.7081118e-05 + 27060 1984.4 0.00020276878 5.6970958e-05 + 27080 1985.8667 0.0002024165 5.6875439e-05 + 27100 1987.3333 0.00020209914 5.6749323e-05 + 27120 1988.8 0.00020182082 5.6684087e-05 + 27140 1990.2667 0.0002015866 5.6665814e-05 + 27160 1991.7333 0.00020140121 5.6663183e-05 + 27180 1993.2 0.0002012666 5.6636454e-05 + 27200 1994.6667 0.00020117997 5.6723443e-05 + 27220 1996.1333 0.00020113417 5.6708615e-05 + 27240 1997.6 0.00020111982 5.6574526e-05 + 27260 1999.0667 0.00020112751 5.6159e-05 + 27280 2000.5333 0.00020114945 5.612955e-05 + 27300 2002 0.00020118054 5.607577e-05 + 27320 2003.4667 0.00020121792 5.6026534e-05 + 27340 2004.9333 0.00020125939 5.5904818e-05 + 27360 2006.4 0.0002013021 5.5872498e-05 + 27380 2007.8667 0.00020134272 5.5850226e-05 + 27400 2009.3333 0.00020137844 5.5792845e-05 + 27420 2010.8 0.0002014071 5.5793502e-05 + 27440 2012.2667 0.00020142601 5.5834389e-05 + 27460 2013.7333 0.00020143246 5.5853674e-05 + 27480 2015.2 0.00020142475 5.5879946e-05 + 27500 2016.6667 0.00020140167 5.5911328e-05 + 27520 2018.1333 0.000201362 5.5946112e-05 + 27540 2019.6 0.00020130361 5.5982457e-05 + 27560 2021.0667 0.00020122365 5.6018854e-05 + 27580 2022.5333 0.00020111911 5.6199876e-05 + 27600 2024 0.00020098676 5.6207908e-05 + 27620 2025.4667 0.00020082461 5.6235125e-05 + 27640 2026.9333 0.00020063251 5.6261668e-05 + 27660 2028.4 0.00020041288 5.6264024e-05 + 27680 2029.8667 0.00020017135 5.6292857e-05 + 27700 2031.3333 0.00019991548 5.6350987e-05 + 27720 2032.8 0.00019965421 5.6386525e-05 + 27740 2034.2667 0.00019939714 5.6330983e-05 + 27760 2035.7333 0.00019915264 5.6315529e-05 + 27780 2037.2 0.00019892685 5.6357912e-05 + 27800 2038.6667 0.00019872342 5.6400674e-05 + 27820 2040.1333 0.00019854343 5.592942e-05 + 27840 2041.6 0.00019838552 5.5933967e-05 + 27860 2043.0667 0.00019824625 5.5937495e-05 + 27880 2044.5333 0.00019812108 5.5939048e-05 + 27900 2046 0.00019800547 5.5938225e-05 + 27920 2047.4667 0.00019789596 5.5934984e-05 + 27940 2048.9333 0.00019779049 5.5998316e-05 + 27960 2050.4 0.00019768847 5.5990459e-05 + 27980 2051.8667 0.00019759007 5.5934942e-05 + 28000 2053.3333 0.00019749517 5.5921371e-05 + 28020 2054.8 0.00019740272 5.5903442e-05 + 28040 2056.2667 0.00019731052 5.5860176e-05 + 28060 2057.7333 0.00019721613 5.58009e-05 + 28080 2059.2 0.00019711761 5.576013e-05 + 28100 2060.6667 0.00019701413 5.5709878e-05 + 28120 2062.1333 0.00019690592 5.5650013e-05 + 28140 2063.6 0.00019679371 5.549438e-05 + 28160 2065.0667 0.00019667803 5.5419813e-05 + 28180 2066.5333 0.00019655854 5.5339684e-05 + 28200 2068 0.0001964341 5.5255642e-05 + 28220 2069.4667 0.00019630305 5.516945e-05 + 28240 2070.9333 0.00019616373 5.5082892e-05 + 28260 2072.4 0.00019601462 5.4997644e-05 + 28280 2073.8667 0.00019585462 5.4915059e-05 + 28300 2075.3333 0.00019568308 5.4836332e-05 + 28320 2076.8 0.00019549977 5.4945429e-05 + 28340 2078.2667 0.00019530501 5.4861235e-05 + 28360 2079.7333 0.00019509987 5.46661e-05 + 28380 2081.2 0.00019488603 5.4604902e-05 + 28400 2082.6667 0.00019466562 5.4548672e-05 + 28420 2084.1333 0.00019444125 5.4495481e-05 + 28440 2085.6 0.00019421575 5.4450188e-05 + 28460 2087.0667 0.00019399217 5.441163e-05 + 28480 2088.5333 0.00019377343 5.4375395e-05 + 28500 2090 0.00019356194 5.4441594e-05 + 28520 2091.4667 0.00019335923 5.4431527e-05 + 28540 2092.9333 0.00019316575 5.4433248e-05 + 28560 2094.4 0.00019298088 5.4331854e-05 + 28580 2095.8667 0.00019280294 5.4731573e-05 + 28600 2097.3333 0.00019262915 5.4763809e-05 + 28620 2098.8 0.00019245592 5.4802719e-05 + 28640 2100.2667 0.00019227949 5.4072056e-05 + 28660 2101.7333 0.00019209613 5.4088674e-05 + 28680 2103.2 0.00019190237 5.4104871e-05 + 28700 2104.6667 0.00019169556 5.4118777e-05 + 28720 2106.1333 0.00019147409 5.4129434e-05 + 28740 2107.6 0.00019123755 5.4109248e-05 + 28760 2109.0667 0.00019098676 5.4095416e-05 + 28780 2110.5333 0.00019072352 5.40944e-05 + 28800 2112 0.0001904505 5.4089923e-05 + 28820 2113.4667 0.00019017109 5.4081987e-05 + 28840 2114.9333 0.00018988915 5.4070363e-05 + 28860 2116.4 0.00018960886 5.4054643e-05 + 28880 2117.8667 0.00018933429 5.4034314e-05 + 28900 2119.3333 0.00018906938 5.4008966e-05 + 28920 2120.8 0.00018881786 5.3978254e-05 + 28940 2122.2667 0.00018858319 5.3942187e-05 + 28960 2123.7333 0.00018836835 5.3901318e-05 + 28980 2125.2 0.00018817583 5.4169759e-05 + 29000 2126.6667 0.00018800763 5.4121319e-05 + 29020 2128.1333 0.00018786525 5.4070295e-05 + 29040 2129.6 0.00018774951 5.4018165e-05 + 29060 2131.0667 0.00018766058 5.3884893e-05 + 29080 2132.5333 0.00018759795 5.3876376e-05 + 29100 2134 0.00018756047 5.3823317e-05 + 29120 2135.4667 0.00018754627 5.3770657e-05 + 29140 2136.9333 0.00018755268 5.3718045e-05 + 29160 2138.4 0.00018757627 5.3665402e-05 + 29180 2139.8667 0.00018761287 5.3612408e-05 + 29200 2141.3333 0.00018765753 5.3558506e-05 + 29220 2142.8 0.0001877046 5.3503291e-05 + 29240 2144.2667 0.00018774817 5.3446796e-05 + 29260 2145.7333 0.00018778315 5.3389512e-05 + 29280 2147.2 0.00018780643 5.3332431e-05 + 29300 2148.6667 0.00018781742 5.3277223e-05 + 29320 2150.1333 0.00018781793 5.3226314e-05 + 29340 2151.6 0.00018781143 5.3176641e-05 + 29360 2153.0667 0.00018780238 5.3141246e-05 + 29380 2154.5333 0.00018779594 5.3117607e-05 + 29400 2156 0.00018779765 5.310825e-05 + 29420 2157.4667 0.0001878128 5.3115468e-05 + 29440 2158.9333 0.00018784561 5.3139946e-05 + 29460 2160.4 0.00018789868 5.288786e-05 + 29480 2161.8667 0.00018797309 5.294168e-05 + 29500 2163.3333 0.00018806883 5.3008359e-05 + 29520 2164.8 0.0001881852 5.3085712e-05 + 29540 2166.2667 0.000188321 5.317109e-05 + 29560 2167.7333 0.00018847475 5.3261964e-05 + 29580 2169.2 0.00018864479 5.3217461e-05 + 29600 2170.6667 0.00018882945 5.3313718e-05 + 29620 2172.1333 0.00018902706 5.3374367e-05 + 29640 2173.6 0.00018923607 5.347584e-05 + 29660 2175.0667 0.00018945509 5.3579085e-05 + 29680 2176.5333 0.000189683 5.3683544e-05 + 29700 2178 0.00018991893 5.3789562e-05 + 29720 2179.4667 0.00019016223 5.3898155e-05 + 29740 2180.9333 0.00019041244 5.4010173e-05 + 29760 2182.4 0.00019066923 5.4125994e-05 + 29780 2183.8667 0.00019093232 5.4245712e-05 + 29800 2185.3333 0.00019120142 5.436933e-05 + 29820 2186.8 0.00019147625 5.449677e-05 + 29840 2188.2667 0.00019175653 5.4627812e-05 + 29860 2189.7333 0.00019204205 5.476186e-05 + 29880 2191.2 0.00019233262 5.4897917e-05 + 29900 2192.6667 0.00019262806 5.5034988e-05 + 29920 2194.1333 0.00019292829 5.5172428e-05 + 29940 2195.6 0.00019323338 5.5309532e-05 + 29960 2197.0667 0.0001935435 5.5445368e-05 + 29980 2198.5333 0.00019385897 5.5579065e-05 + 30000 2200 0.00019418014 5.5710007e-05 +Loop time of 120.806 on 4 procs for 30000 steps with 3046 atoms + +Performance: 1573425.361 tau/day, 248.331 timesteps/s, 756.416 katom-step/s +99.3% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.89764 | 12.463 | 25.361 | 316.2 | 10.32 +Neigh | 0.083839 | 0.94363 | 1.8654 | 87.4 | 0.78 +Comm | 0.23436 | 0.25427 | 0.27244 | 2.9 | 0.21 +Output | 1.2745 | 2.0289 | 2.7205 | 46.3 | 1.68 +Modify | 88.101 | 92.266 | 95.765 | 34.6 | 76.38 +Other | | 12.85 | | | 10.64 + +Nlocal: 761.5 ave 1685 max 105 min +Histogram: 2 0 0 0 0 0 1 0 0 1 +Nghost: 28.5 ave 51 max 7 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Neighs: 6128.5 ave 14174 max 567 min +Histogram: 2 0 0 0 0 0 1 0 0 1 +FullNghs: 12164 ave 28184 max 1117 min +Histogram: 2 0 0 0 0 0 1 0 0 1 + +Total # of neighbors = 48656 +Ave neighs/atom = 15.973736 +Neighbor list builds = 3012 +Dangerous builds = 0 + +Total wall time: 0:02:00 diff --git a/examples/rheo/ice-cubes/in.rheo.ice.cubes b/examples/rheo/ice-cubes/in.rheo.ice.cubes index b023a8bac9..91e02c780d 100644 --- a/examples/rheo/ice-cubes/in.rheo.ice.cubes +++ b/examples/rheo/ice-cubes/in.rheo.ice.cubes @@ -77,5 +77,6 @@ compute nbond all nbond/atom thermo 200 thermo_style custom step time ke press atoms -dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond c_rho +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond c_rho + run 30000 diff --git a/examples/rheo/ice-cubes/log.17Apr2024.ice.g++.4 b/examples/rheo/ice-cubes/log.17Apr2024.ice.g++.4 new file mode 100644 index 0000000000..98fc2e7540 --- /dev/null +++ b/examples/rheo/ice-cubes/log.17Apr2024.ice.g++.4 @@ -0,0 +1,379 @@ +LAMMPS (17 Apr 2024 - Development - patch_5May2020-18508-g3c0eaf6870-modified) +# ------ 2D Ice Cube Pour ------ # + +dimension 2 +units lj +atom_style hybrid rheo/thermal bond +boundary m m p +comm_modify vel yes +newton off +special_bonds lj 0.0 1.0 1.0 coul 1.0 1.0 1.0 + +region box block -25 25 0 100 -0.01 0.01 units box +create_box 1 box bond/types 1 extra/bond/per/atom 15 extra/special/per/atom 50 +Created orthogonal box = (-25 0 -0.01) to (25 100 0.01) + 2 by 2 by 1 MPI processor grid + +region fluid block $(xlo+1) $(xhi-1) $(ylo+1) $(ylo+30) EDGE EDGE units box +region fluid block -24 $(xhi-1) $(ylo+1) $(ylo+30) EDGE EDGE units box +region fluid block -24 24 $(ylo+1) $(ylo+30) EDGE EDGE units box +region fluid block -24 24 1 $(ylo+30) EDGE EDGE units box +region fluid block -24 24 1 30 EDGE EDGE units box +lattice sq 1.0 +Lattice spacing in x,y,z = 1 1 1 +create_atoms 1 region fluid +Created 1470 atoms + using lattice units in orthogonal box = (-25 0 -0.01) to (25 100 0.01) + create_atoms CPU = 0.001 seconds + +set group all sph/e 8.0 +Setting atom values ... + 1470 settings made for sph/e + +# ------ Model parameters ------# + +variable cut equal 3.0 +variable n equal 1.0 +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable mp equal 1/${n} +variable mp equal 1/1 +variable zeta equal 0.05 +variable kappa equal 0.01*${rho0}/${mp} +variable kappa equal 0.01*1/${mp} +variable kappa equal 0.01*1/1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable dt_max equal 0.1*3/${cs}/3 +variable dt_max equal 0.1*3/1/3 +variable eta equal 0.05 +variable Cv equal 1.0 +variable L equal 1.0 +variable Tf equal 1.0 + +mass * ${mp} +mass * 1 +timestep 0.1 + +pair_style hybrid/overlay rheo ${cut} artificial/visc ${zeta} rheo/solid +pair_style hybrid/overlay rheo 3 artificial/visc ${zeta} rheo/solid +pair_style hybrid/overlay rheo 3 artificial/visc 0.05 rheo/solid +pair_coeff * * rheo +pair_coeff * * rheo/solid 1.0 1.0 1.0 + +bond_style bpm/spring +bond_coeff 1 1.0 1.0 1.0 + +# ------ Pour particles ------# + +molecule my_mol "square.mol" +Read molecule template my_mol: +#Made with create_mol.py + 1 molecules + 0 fragments + 100 atoms with max type 1 + 342 bonds with max type 1 + 0 angles with max type 0 + 0 dihedrals with max type 0 + 0 impropers with max type 0 + +# Wall region extends far enough in z to avoid contact +region wall block EDGE EDGE EDGE EDGE -5 5 side in open 4 units box +region drop block -16 16 70 90 EDGE EDGE side in units box + +fix 1 all rheo ${cut} quintic 0 thermal shift surface/detection coordination 22 8 +fix 1 all rheo 3 quintic 0 thermal shift surface/detection coordination 22 8 +fix 2 all rheo/viscosity * constant ${eta} +fix 2 all rheo/viscosity * constant 0.05 +fix 3 all rheo/pressure * linear +fix 4 all rheo/thermal conductivity * constant ${kappa} specific/heat * constant ${Cv} Tfreeze * constant ${Tf} latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.01 specific/heat * constant ${Cv} Tfreeze * constant ${Tf} latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.01 specific/heat * constant 1 Tfreeze * constant ${Tf} latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.01 specific/heat * constant 1 Tfreeze * constant 1 latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.01 specific/heat * constant 1 Tfreeze * constant 1 latent/heat * constant 1 react 1.5 1 +fix 5 all wall/region wall harmonic 1.0 1.0 1.0 +fix 6 all gravity 5e-4 vector 0 -1 0 +fix 7 all deposit 8 0 1000 37241459 mol my_mol region drop near 2.0 vy -0.02 -0.02 +WARNING: Molecule attributes do not match system attributes (../molecule.cpp:1881) +fix 8 all enforce2d + +compute rho all rheo/property/atom rho +compute phase all rheo/property/atom phase +compute temp all rheo/property/atom temperature +compute eng all rheo/property/atom energy +compute nbond all nbond/atom + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press atoms + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond c_rho + +run 30000 + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Your simulation uses code contributions which should be cited: + +- BPM bond style: doi:10.1039/D3SM01373A + +@Article{Clemmer2024, + author = {Clemmer, Joel T. and Monti, Joseph M. and Lechman, Jeremy B.}, + title = {A soft departure from jamming: the compaction of deformable + granular matter under high pressures}, + journal = {Soft Matter}, + year = 2024, + volume = 20, + number = 8, + pages = {1702--1718} +} + +- @article{PalermoInPrep, + journal = {in prep}, + title = {RHEO: A Hybrid Mesh-Free Model Framework for Dynamic Multi-Phase Flows}, + year = {2024}, + author = {Eric T. Palermo and Ki T. Wolf and Joel T. Clemmer and Thomas C. O'Connor}, +} + +- @article{ApplMathModel.130.310, + title = {A hybrid smoothed-particle hydrodynamics model of oxide skins on molten aluminum}, + journal = {Applied Mathematical Modelling}, + volume = {130}, + pages = {310-326}, + year = {2024}, + issn = {0307-904X}, + doi = {https://doi.org/10.1016/j.apm.2024.02.027}, + author = {Joel T. Clemmer and Flint Pierce and Thomas C. O'Connor and Thomas D. Nevins and Elizabeth M.C. Jones and Jeremy B. Lechman and John Tencer}, +} + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Generated 0 of 0 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 3.3 + ghost atom cutoff = 3.3 + binsize = 1.65, bins = 31 61 1 + 7 neighbor lists, perpetual/occasional/extra = 6 1 0 + (1) pair rheo, perpetual, half/full from (3) + attributes: half, newton off + pair build: halffull/newtoff + stencil: none + bin: none + (2) pair rheo/solid, perpetual, trim from (4) + attributes: half, newton off, cut 1.3 + pair build: trim + stencil: none + bin: none + (3) compute RHEO/KERNEL, perpetual + attributes: full, newton off + pair build: full/bin + stencil: full/bin/2d + bin: standard + (4) compute RHEO/GRAD, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (5) compute RHEO/VSHIFT, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (6) compute RHEO/SURFACE, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (7) fix rheo/thermal, occasional, trim from (4) + attributes: half, newton off, cut 3 + pair build: trim + stencil: none + bin: none +Per MPI rank memory allocation (min/avg/max) = 15.53 | 15.61 | 15.69 Mbytes + Step Time KinEng Press Atoms + 0 0 0 0 1470 + 200 20 5.6002982e-05 3.4434234e-05 1570 + 400 40 8.2173099e-05 8.6171768e-05 1570 + 600 60 8.019018e-05 0.00010750355 1570 + 800 80 0.00013866953 0.00010265608 1570 + 1000 100 0.00018965028 8.1985605e-05 1570 + 1200 120 0.00022033242 7.4736443e-05 1670 + 1400 140 0.00030767062 0.00011264333 1670 + 1600 160 0.00040770127 0.00018779992 1670 + 1800 180 0.00047476332 0.00023153009 1670 + 2000 200 0.00059116774 0.00027200445 1670 + 2200 220 0.0007151733 0.0002919963 1770 + 2400 240 0.00083392135 0.00029757889 1770 + 2600 260 0.00099653466 0.00036547269 1770 + 2800 280 0.0011964069 0.00045983458 1770 + 3000 300 0.0013716953 0.00055013647 1770 + 3200 320 0.0015174096 0.00064203572 1870 + 3400 340 0.0016539743 0.00086671622 1870 + 3600 360 0.0015887858 0.00066353749 1870 + 3800 380 0.0016451684 0.00070551483 1870 + 4000 400 0.0017330971 0.00080722283 1870 + 4200 420 0.001812193 0.00073573903 1970 + 4400 440 0.001755871 0.0010621909 1970 + 4600 460 0.0016190772 0.00072913706 1970 + 4800 480 0.0015741931 0.00073524088 1970 + 5000 500 0.0016488815 0.00088684275 1970 + 5200 520 0.0017213288 0.00077042378 2070 + 5400 540 0.0018509598 0.0010219434 2070 + 5600 560 0.0020251064 0.00083182483 2070 + 5800 580 0.0022473255 0.00095076144 2070 + 6000 600 0.0024843519 0.0011247014 2070 + 6200 620 0.0022282321 0.0018105932 2170 + 6400 640 0.0020289063 0.0014158497 2170 + 6600 660 0.002145241 0.0011359383 2170 + 6800 680 0.0024313937 0.0016475504 2170 + 7000 700 0.0021000599 0.0020983745 2170 + 7200 720 0.0019137235 0.0010439152 2270 + 7400 740 0.0018801367 0.00095436448 2270 + 7600 760 0.0017979449 0.0011184039 2270 + 7800 780 0.0018005205 0.0009243205 2270 + 8000 800 0.0017827073 0.0013671228 2270 + 8200 820 0.0018387108 0.0015426012 2270 + 8400 840 0.0016000788 0.0016751514 2270 + 8600 860 0.0013954964 0.0016884335 2270 + 8800 880 0.0013283728 0.0012399398 2270 + 9000 900 0.001389385 0.0012968496 2270 + 9200 920 0.0012295438 0.0012995821 2270 + 9400 940 0.0010522655 0.00082245528 2270 + 9600 960 0.00097085496 0.00053833131 2270 + 9800 980 0.0009398987 0.00063467387 2270 + 10000 1000 0.00092710392 0.00059494446 2270 + 10200 1020 0.00095545471 0.00074560644 2270 + 10400 1040 0.0009645841 0.00085429807 2270 + 10600 1060 0.00064037148 0.0017222246 2270 + 10800 1080 0.00046790978 0.00088204234 2270 + 11000 1100 0.00030106229 0.00074950209 2270 + 11200 1120 0.00027746016 0.00052831745 2270 + 11400 1140 0.0002533348 0.0006272715 2270 + 11600 1160 0.00021825085 0.00029691552 2270 + 11800 1180 0.0001451308 0.00015037478 2270 + 12000 1200 0.0001314823 0.00017227174 2270 + 12200 1220 0.00013693632 0.00017791384 2270 + 12400 1240 0.00014987347 0.0002286677 2270 + 12600 1260 0.00015092598 0.0003698436 2270 + 12800 1280 0.0001291653 0.00047229532 2270 + 13000 1300 0.00011949988 0.00049560375 2270 + 13200 1320 0.00011694665 0.00057542084 2270 + 13400 1340 9.6164519e-05 0.00062714755 2270 + 13600 1360 8.4517591e-05 0.00044156913 2270 + 13800 1380 0.00019140516 0.0003264745 2270 + 14000 1400 0.00013868599 0.00037753497 2270 + 14200 1420 9.3701636e-05 0.00031517848 2270 + 14400 1440 6.7389077e-05 0.0002946861 2270 + 14600 1460 5.3640086e-05 0.00026650711 2270 + 14800 1480 4.2699992e-05 0.00023789279 2270 + 15000 1500 5.3012016e-05 0.00019933234 2270 + 15200 1520 5.8834197e-05 0.00022407007 2270 + 15400 1540 5.0899982e-05 0.00029695531 2270 + 15600 1560 3.0476742e-05 0.00039119066 2270 + 15800 1580 1.6633264e-05 0.00033770401 2270 + 16000 1600 1.098906e-05 0.00036684894 2270 + 16200 1620 1.464848e-05 0.00036449759 2270 + 16400 1640 1.9598429e-05 0.00021056689 2270 + 16600 1660 1.2644955e-05 0.00020781781 2270 + 16800 1680 8.8428553e-06 0.000165 2270 + 17000 1700 8.8971439e-06 0.00012266475 2270 + 17200 1720 1.7032781e-05 0.00019873443 2270 + 17400 1740 1.9448563e-05 0.00025661663 2270 + 17600 1760 1.3714713e-05 0.000324022 2270 + 17800 1780 9.1326468e-06 0.00031392513 2270 + 18000 1800 9.2464802e-06 0.00029729527 2270 + 18200 1820 1.5553042e-05 0.00027488475 2270 + 18400 1840 1.4132933e-05 0.00019565459 2270 + 18600 1860 9.4734832e-06 0.00016716988 2270 + 18800 1880 5.5115145e-06 0.00013728033 2270 + 19000 1900 8.268812e-06 0.00015119605 2270 + 19200 1920 1.2470136e-05 0.00020222131 2270 + 19400 1940 9.9387775e-06 0.00024503373 2270 + 19600 1960 5.4241999e-06 0.00026921858 2270 + 19800 1980 2.7987348e-06 0.00026201267 2270 + 20000 2000 6.272538e-06 0.00025626323 2270 + 20200 2020 8.0157781e-06 0.000220139 2270 + 20400 2040 6.1652093e-06 0.00017089058 2270 + 20600 2060 2.9967592e-06 0.00014582864 2270 + 20800 2080 3.016678e-06 0.000148629 2270 + 21000 2100 7.287645e-06 0.00016486102 2270 + 21200 2120 8.6905277e-06 0.00020276916 2270 + 21400 2140 6.8453018e-06 0.00023156153 2270 + 21600 2160 3.3853799e-06 0.0002432462 2270 + 21800 2180 4.1241209e-06 0.00022829024 2270 + 22000 2200 7.0802396e-06 0.00020784823 2270 + 22200 2220 7.3361691e-06 0.00018114134 2270 + 22400 2240 5.0764593e-06 0.00014351106 2270 + 22600 2260 2.7487537e-06 0.00012919872 2270 + 22800 2280 4.620167e-06 0.00013746218 2270 + 23000 2300 6.9819357e-06 0.00015985102 2270 + 23200 2320 6.8923916e-06 0.00018713045 2270 + 23400 2340 4.1795088e-06 0.00019846682 2270 + 23600 2360 2.2871028e-06 0.00021068421 2270 + 23800 2380 3.862046e-06 0.00019553306 2270 + 24000 2400 5.2448555e-06 0.00017398041 2270 + 24200 2420 4.7565441e-06 0.00015008142 2270 + 24400 2440 2.2952135e-06 0.00012747106 2270 + 24600 2460 2.1575617e-06 0.00012516996 2270 + 24800 2480 4.1777868e-06 0.0001331902 2270 + 25000 2500 5.5679133e-06 0.00015504562 2270 + 25200 2520 4.5758741e-06 0.00017146032 2270 + 25400 2540 2.3403277e-06 0.00017611666 2270 + 25600 2560 2.7029302e-06 0.00016850788 2270 + 25800 2580 4.3601102e-06 0.00015884642 2270 + 26000 2600 5.2244249e-06 0.00013793898 2270 + 26200 2620 3.4577672e-06 0.00012395875 2270 + 26400 2640 2.361577e-06 0.00011600057 2270 + 26600 2660 2.8515644e-06 0.00011277063 2270 + 26800 2680 4.0851213e-06 0.0001290832 2270 + 27000 2700 4.2579644e-06 0.0001476495 2270 + 27200 2720 2.6593858e-06 0.00015977745 2270 + 27400 2740 1.990115e-06 0.00015612787 2270 + 27600 2760 2.6756835e-06 0.00014913772 2270 + 27800 2780 3.9032806e-06 0.00014014763 2270 + 28000 2800 3.2729446e-06 0.00012216846 2270 + 28200 2820 1.9357278e-06 0.00011078621 2270 + 28400 2840 1.7094832e-06 0.00010910509 2270 + 28600 2860 2.8731406e-06 0.00011179644 2270 + 28800 2880 3.7062354e-06 0.00012254091 2270 + 29000 2900 2.7844262e-06 0.00013060331 2270 + 29200 2920 1.7680655e-06 0.00013797514 2270 + 29400 2940 1.706873e-06 0.0001350685 2270 + 29600 2960 2.8764562e-06 0.00012428508 2270 + 29800 2980 3.1502029e-06 0.00011456718 2270 + 30000 3000 2.1833409e-06 0.00010317469 2270 +Loop time of 165.611 on 4 procs for 30000 steps with 2270 atoms + +Performance: 1565111.240 tau/day, 181.147 timesteps/s, 411.204 katom-step/s +99.7% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.63183 | 21.226 | 42.266 | 444.6 | 12.82 +Bond | 0.095073 | 0.17799 | 0.27877 | 17.0 | 0.11 +Neigh | 2.0745 | 2.0781 | 2.0822 | 0.2 | 1.25 +Comm | 0.32024 | 0.38703 | 0.45564 | 8.1 | 0.23 +Output | 0.60459 | 0.76798 | 0.93724 | 18.6 | 0.46 +Modify | 119.85 | 140.76 | 161.36 | 172.2 | 85.00 +Other | | 0.2124 | | | 0.13 + +Nlocal: 567.5 ave 1139 max 0 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Nghost: 75.5 ave 152 max 0 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Neighs: 9238.25 ave 18490 max 0 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +FullNghs: 17945 ave 35917 max 0 min +Histogram: 2 0 0 0 0 0 0 0 0 2 + +Total # of neighbors = 71780 +Ave neighs/atom = 31.621145 +Ave special neighs/atom = 0.22026432 +Neighbor list builds = 2071 +Dangerous builds = 0 + +Total wall time: 0:02:45 diff --git a/examples/rheo/oxidation/in.rheo.oxidation b/examples/rheo/oxidation/in.rheo.oxidation index d26b379adb..d8b4b1a464 100644 --- a/examples/rheo/oxidation/in.rheo.oxidation +++ b/examples/rheo/oxidation/in.rheo.oxidation @@ -98,5 +98,6 @@ compute nbond_solid all nbond/atom bond/type 1 thermo 200 thermo_style custom step time ke press atoms -dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond_solid c_nbond_shell c_rho c_surf c_status +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond_solid c_nbond_shell c_rho c_surf c_status + run 40000 diff --git a/examples/rheo/oxidation/log.17Apr2024.oxidation.g++.4 b/examples/rheo/oxidation/log.17Apr2024.oxidation.g++.4 new file mode 100644 index 0000000000..92eb4aa94a --- /dev/null +++ b/examples/rheo/oxidation/log.17Apr2024.oxidation.g++.4 @@ -0,0 +1,488 @@ +LAMMPS (17 Apr 2024 - Development - patch_5May2020-18508-g3c0eaf6870-modified) +# ------ 2D oxidizing bar ------ # + +dimension 2 +units lj +atom_style hybrid rheo/thermal bond +boundary m m p +comm_modify vel yes +newton off + +region box block -60 60 0 80 -0.01 0.01 units box +create_box 3 box bond/types 2 extra/bond/per/atom 20 extra/special/per/atom 50 +Created orthogonal box = (-60 0 -0.01) to (60 80 0.01) + 2 by 2 by 1 MPI processor grid + +region lbar block -15 0 3 80 EDGE EDGE units box +region rbar block 0 15 3 80 EDGE EDGE units box +region bar union 2 lbar rbar +region floor block EDGE EDGE EDGE 3.0 EDGE EDGE units box + +lattice hex 1.0 +Lattice spacing in x,y,z = 1.0745699 1.8612097 1.0745699 +create_atoms 1 region bar +Created 2255 atoms + using lattice units in orthogonal box = (-60 0 -0.01) to (60 80 0.01) + create_atoms CPU = 0.001 seconds +create_atoms 3 region floor +Created 446 atoms + using lattice units in orthogonal box = (-60 0 -0.01) to (60 80 0.01) + create_atoms CPU = 0.000 seconds + +set region rbar type 2 +Setting atom values ... + 1148 settings made for type +group bar type 1 2 +2255 atoms in group bar +group rbar type 2 +1148 atoms in group rbar +group floor type 3 +446 atoms in group floor + +set group all sph/e 0.0 +Setting atom values ... + 2701 settings made for sph/e +set group all rheo/status 1 +Setting atom values ... + 2701 settings made for rheo/status + +# ------ Model parameters ------# + +variable cut equal 3.0 +variable n equal 1.0 +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable mp equal 1/${n} +variable mp equal 1/1 +variable zeta equal 0.05 +variable kappa equal 0.1*${rho0}/${mp} +variable kappa equal 0.1*1/${mp} +variable kappa equal 0.1*1/1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable dt_max equal 0.1*3/${cs}/3 +variable dt_max equal 0.1*3/1/3 +variable eta equal 0.05 +variable Cv equal 1.0 +variable L equal 0.1 +variable Tf equal 1.0 + +mass * ${mp} +mass * 1 +timestep 0.1 + +pair_style hybrid/overlay rheo ${cut} artificial/visc ${zeta} rheo/solid +pair_style hybrid/overlay rheo 3 artificial/visc ${zeta} rheo/solid +pair_style hybrid/overlay rheo 3 artificial/visc 0.05 rheo/solid +pair_coeff * * rheo +pair_coeff * * rheo/solid 1.0 1.0 1.0 + +special_bonds lj 0.0 1.0 1.0 coul 0.0 1.0 1.0 +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 1 1 + special bond factors coul: 0 1 1 + 0 = max # of 1-2 neighbors + 101 = max # of special neighbors + special bonds CPU = 0.000 seconds +create_bonds many bar bar 1 0 1.5 +Generated 0 of 3 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 3.3 + ghost atom cutoff = 3.3 + binsize = 1.65, bins = 73 49 1 + 3 neighbor lists, perpetual/occasional/extra = 2 1 0 + (1) command create_bonds, occasional + attributes: full, newton off + pair build: full/bin + stencil: full/bin/2d + bin: standard + (2) pair rheo, perpetual + attributes: half, newton off + pair build: half/bin/newtoff + stencil: full/bin/2d + bin: standard + (3) pair rheo/solid, perpetual, trim from (2) + attributes: half, newton off, cut 1.3 + pair build: trim + stencil: none + bin: none +Added 6547 bonds, new total = 6547 +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 1 1 + special bond factors coul: 0 1 1 + 6 = max # of 1-2 neighbors + 101 = max # of special neighbors + special bonds CPU = 0.000 seconds +special_bonds lj 0.0 1.0 1.0 coul 1.0 1.0 1.0 + +bond_style hybrid bpm/spring rheo/shell t/form 100 +bond_coeff 1 bpm/spring 1.0 1.0 1.0 +bond_coeff 2 rheo/shell 0.2 0.2 0.1 + +# ------ Apply dynamics ------# + +# Note: surface detection is not performed on solid bodies, so cannot use surface property +compute coord all rheo/property/atom coordination +variable surf atom c_coord<22 +group surf dynamic all var surf every 10 +dynamic group surf defined + +fix 1 all rheo ${cut} quintic 0 thermal shift surface/detection coordination 22 8 +fix 1 all rheo 3 quintic 0 thermal shift surface/detection coordination 22 8 +fix 2 all rheo/viscosity * constant ${eta} +fix 2 all rheo/viscosity * constant 0.05 +fix 3 all rheo/pressure * linear +fix 4 all rheo/thermal conductivity * constant ${kappa} specific/heat * constant ${Cv} Tfreeze * constant ${Tf} latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.1 specific/heat * constant ${Cv} Tfreeze * constant ${Tf} latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.1 specific/heat * constant 1 Tfreeze * constant ${Tf} latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.1 specific/heat * constant 1 Tfreeze * constant 1 latent/heat * constant ${L} react 1.5 1 +fix 4 all rheo/thermal conductivity * constant 0.1 specific/heat * constant 1 Tfreeze * constant 1 latent/heat * constant 0.1 react 1.5 1 + +fix 5 rbar rheo/oxidation 1.5 2 1.0 +fix 6 all wall/harmonic ylo EDGE 2.0 1.0 1.0 +fix 7 all gravity 5e-5 vector 0 -1 0 +fix 8 floor setforce 0.0 0.0 0.0 +fix 9 surf add/heat linear 1.1 0.05 +fix 10 floor add/heat constant 0 overwrite yes # fix the temperature of the floor +fix 11 all enforce2d + +compute surf all rheo/property/atom surface +compute rho all rheo/property/atom rho +compute phase all rheo/property/atom phase +compute status all rheo/property/atom status +compute temp all rheo/property/atom temperature +compute eng all rheo/property/atom energy +compute nbond_shell all rheo/property/atom nbond/shell +compute nbond_solid all nbond/atom bond/type 1 + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press atoms + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond_solid c_nbond_shell c_rho c_surf c_status + +run 40000 + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Your simulation uses code contributions which should be cited: + +- BPM bond style: doi:10.1039/D3SM01373A + +@Article{Clemmer2024, + author = {Clemmer, Joel T. and Monti, Joseph M. and Lechman, Jeremy B.}, + title = {A soft departure from jamming: the compaction of deformable + granular matter under high pressures}, + journal = {Soft Matter}, + year = 2024, + volume = 20, + number = 8, + pages = {1702--1718} +} + +- @article{PalermoInPrep, + journal = {in prep}, + title = {RHEO: A Hybrid Mesh-Free Model Framework for Dynamic Multi-Phase Flows}, + year = {2024}, + author = {Eric T. Palermo and Ki T. Wolf and Joel T. Clemmer and Thomas C. O'Connor}, +} + +- @article{ApplMathModel.130.310, + title = {A hybrid smoothed-particle hydrodynamics model of oxide skins on molten aluminum}, + journal = {Applied Mathematical Modelling}, + volume = {130}, + pages = {310-326}, + year = {2024}, + issn = {0307-904X}, + doi = {https://doi.org/10.1016/j.apm.2024.02.027}, + author = {Joel T. Clemmer and Flint Pierce and Thomas C. O'Connor and Thomas D. Nevins and Elizabeth M.C. Jones and Jeremy B. Lechman and John Tencer}, +} + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Generated 0 of 3 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 3.3 + ghost atom cutoff = 3.3 + binsize = 1.65, bins = 73 49 1 + 8 neighbor lists, perpetual/occasional/extra = 7 1 0 + (1) pair rheo, perpetual, half/full from (3) + attributes: half, newton off + pair build: halffull/newtoff + stencil: none + bin: none + (2) pair rheo/solid, perpetual, trim from (4) + attributes: half, newton off, cut 1.3 + pair build: trim + stencil: none + bin: none + (3) compute RHEO/KERNEL, perpetual + attributes: full, newton off + pair build: full/bin + stencil: full/bin/2d + bin: standard + (4) compute RHEO/GRAD, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (5) compute RHEO/VSHIFT, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (6) compute RHEO/SURFACE, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (7) fix rheo/thermal, occasional, trim from (4) + attributes: half, newton off, cut 3 + pair build: trim + stencil: none + bin: none + (8) fix rheo/oxidation, perpetual, trim from (3) + attributes: full, newton off, cut 1.8 + pair build: trim + stencil: none + bin: none +Per MPI rank memory allocation (min/avg/max) = 25.96 | 25.96 | 25.96 Mbytes + Step Time KinEng Press Atoms + 0 0 0 0 2701 + 200 20 4.1743799e-07 1.1743617e-07 2701 + 400 40 1.6697519e-06 4.6974469e-07 2701 + 600 60 3.7127333e-06 1.0646825e-05 2701 + 800 80 4.6683656e-06 0.00015182605 2701 + 1000 100 4.7368707e-06 0.00028128761 2701 + 1200 120 3.4384322e-06 0.00045913378 2701 + 1400 140 1.4119866e-06 0.00055627091 2701 + 1600 160 4.4114517e-07 0.00058247308 2701 + 1800 180 4.8289229e-07 0.0005510948 2701 + 2000 200 1.8494183e-06 0.00048386222 2701 + 2200 220 3.3319816e-06 0.00037903264 2701 + 2400 240 3.8128922e-06 0.00024115906 2701 + 2600 260 3.1943401e-06 9.727407e-05 2701 + 2800 280 1.6172816e-06 -2.632162e-05 2701 + 3000 300 3.6100709e-07 -8.5761867e-05 2701 + 3200 320 1.4745502e-07 -5.9204127e-05 2701 + 3400 340 8.3369782e-07 8.8312464e-07 2701 + 3600 360 2.0484052e-06 5.8521477e-05 2701 + 3800 380 3.1639387e-06 0.0001685663 2701 + 4000 400 3.1692907e-06 0.00026875988 2701 + 4200 420 2.391933e-06 0.00038621787 2701 + 4400 440 1.1964404e-06 0.00048901286 2701 + 4600 460 4.0508824e-07 0.00051863639 2701 + 4800 480 5.4908507e-07 0.00049263754 2701 + 5000 500 1.3139665e-06 0.00041984264 2701 + 5200 520 2.1939161e-06 0.00033095351 2701 + 5400 540 2.3687031e-06 0.00022422981 2701 + 5600 560 1.8280882e-06 0.00011544328 2701 + 5800 580 8.8610517e-07 2.9307791e-05 2701 + 6000 600 2.0989359e-07 -1.7340941e-05 2701 + 6200 620 2.8658301e-07 -8.1237835e-06 2701 + 6400 640 9.7636239e-07 4.3755922e-05 2701 + 6600 660 1.891303e-06 0.0001185719 2701 + 6800 680 2.4149904e-06 0.00020830273 2701 + 7000 700 2.3174953e-06 0.00030114767 2701 + 7200 720 1.7918612e-06 0.00037821537 2701 + 7400 740 1.2114987e-06 0.0004233475 2701 + 7600 760 9.9661553e-07 0.00042958263 2701 + 7800 780 1.1552559e-06 0.00039944618 2701 + 8000 800 1.5249138e-06 0.00034034478 2701 + 8200 820 1.7453861e-06 0.00026826463 2701 + 8400 840 1.6259021e-06 0.00019131768 2701 + 8600 860 1.2612805e-06 0.0001162957 2701 + 8800 880 8.6964518e-07 7.1771506e-05 2701 + 9000 900 7.6892472e-07 5.6170687e-05 2701 + 9200 920 1.0780045e-06 7.1925995e-05 2701 + 9400 940 1.6514902e-06 0.00011635293 2701 + 9600 960 2.1891377e-06 0.00017599885 2701 + 9800 980 2.4551701e-06 0.00024127934 2701 + 10000 1000 2.4277051e-06 0.00029918622 2701 + 10200 1020 2.2655987e-06 0.00034067996 2701 + 10400 1040 2.1767207e-06 0.00035598133 2701 + 10600 1060 2.2796719e-06 0.00034359076 2701 + 10800 1080 2.4884225e-06 0.00030749714 2701 + 11000 1100 2.6387215e-06 0.00025725198 2701 + 11200 1120 2.5968908e-06 0.00020170699 2701 + 11400 1140 2.4108931e-06 0.00015185858 2701 + 11600 1160 2.2375166e-06 0.00011800349 2701 + 11800 1180 2.2407196e-06 0.00010646971 2701 + 12000 1200 2.4845263e-06 0.00011817498 2701 + 12200 1220 2.8733204e-06 0.00015013186 2701 + 12400 1240 3.2437087e-06 0.00019211975 2701 + 12600 1260 3.4732728e-06 0.00023620276 2701 + 12800 1280 3.5836611e-06 0.00027352269 2701 + 13000 1300 3.6592211e-06 0.00029533734 2701 + 13200 1320 3.782506e-06 0.00030032559 2701 + 13400 1340 3.9807086e-06 0.00028395722 2701 + 13600 1360 4.2023176e-06 0.00025390325 2701 + 13800 1380 4.3559781e-06 0.00021794236 2701 + 14000 1400 4.4273371e-06 0.00018026034 2701 + 14200 1420 4.49867e-06 0.0001526569 2701 + 14400 1440 4.6591574e-06 0.00013707051 2701 + 14600 1460 4.9589583e-06 0.00013803875 2701 + 14800 1480 5.3859375e-06 0.00015455425 2701 + 15000 1500 5.8639557e-06 0.00017954785 2701 + 15200 1520 6.3075561e-06 0.0002084257 2701 + 15400 1540 6.7022179e-06 0.0002347669 2701 + 15600 1560 7.0789688e-06 0.00025020766 2701 + 15800 1580 7.4734777e-06 0.00025394845 2701 + 16000 1600 7.8884743e-06 0.00024571725 2701 + 16200 1620 8.3224059e-06 0.00022706648 2701 + 16400 1640 8.7337783e-06 0.00020320706 2701 + 16600 1660 9.1454649e-06 0.00017824346 2701 + 16800 1680 9.5948793e-06 0.00015961835 2701 + 17000 1700 1.0106407e-05 0.00015135471 2701 + 17200 1720 1.0707273e-05 0.00015166884 2701 + 17400 1740 1.1392597e-05 0.0001645916 2701 + 17600 1760 1.2118829e-05 0.00018119729 2701 + 17800 1780 1.2846056e-05 0.0002003616 2701 + 18000 1800 1.3555288e-05 0.00021585952 2701 + 18200 1820 1.4301024e-05 0.00022290158 2701 + 18400 1840 1.5089217e-05 0.00021970192 2701 + 18600 1860 1.5902351e-05 0.00020911128 2701 + 18800 1880 1.6753175e-05 0.00019278718 2701 + 19000 1900 1.7602996e-05 0.00017584076 2701 + 19200 1920 1.8479378e-05 0.00016206226 2701 + 19400 1940 1.9421603e-05 0.00015575677 2701 + 19600 1960 2.0477421e-05 0.00015687558 2701 + 19800 1980 2.1617288e-05 0.00016424998 2701 + 20000 2000 2.2814347e-05 0.00017466664 2701 + 20200 2020 2.4029097e-05 0.00018647149 2701 + 20400 2040 2.5255953e-05 0.00019516077 2701 + 20600 2060 2.649418e-05 0.00019906384 2701 + 20800 2080 2.7755897e-05 0.00019630586 2701 + 21000 2100 2.9067854e-05 0.00018674721 2701 + 21200 2120 3.0396477e-05 0.0001758048 2701 + 21400 2140 3.1759719e-05 0.00016782801 2701 + 21600 2160 3.3193597e-05 0.00016324138 2701 + 21800 2180 3.4729384e-05 0.00016124274 2701 + 22000 2200 3.6367594e-05 0.00016437457 2701 + 22200 2220 3.8095131e-05 0.00017015573 2701 + 22400 2240 3.9867003e-05 0.00017649465 2701 + 22600 2260 4.169511e-05 0.00018111374 2701 + 22800 2280 4.3566134e-05 0.00018104136 2701 + 23000 2300 4.5461538e-05 0.00017822707 2701 + 23200 2320 4.7377333e-05 0.00017285066 2701 + 23400 2340 4.9354403e-05 0.00016826524 2701 + 23600 2360 5.1399791e-05 0.00016517913 2701 + 23800 2380 5.3510931e-05 0.00016299649 2701 + 24000 2400 5.5681048e-05 0.00016256674 2701 + 24200 2420 5.7902429e-05 0.00016513449 2701 + 24400 2440 6.0216049e-05 0.00016895109 2701 + 24600 2460 6.270982e-05 0.00016946227 2701 + 24800 2480 6.5390117e-05 0.00016589426 2701 + 25000 2500 6.8121899e-05 0.00016241676 2701 + 25200 2520 7.0947331e-05 0.00015624292 2701 + 25400 2540 7.4304148e-05 0.0001449537 2701 + 25600 2560 7.7745077e-05 0.00013179658 2701 + 25800 2580 8.0739829e-05 0.00013098838 2701 + 26000 2600 8.3827874e-05 0.00014278841 2701 + 26200 2620 8.7060677e-05 0.00015381649 2701 + 26400 2640 9.0266508e-05 0.00016130999 2701 + 26600 2660 9.3339049e-05 0.00016908268 2701 + 26800 2680 9.6347013e-05 0.00016771087 2701 + 27000 2700 9.9294711e-05 0.00016577315 2701 + 27200 2720 0.00010230007 0.0001670893 2701 + 27400 2740 0.00010547172 0.00016569077 2701 + 27600 2760 0.00010872426 0.00016506303 2701 + 27800 2780 0.00011201844 0.00016482702 2701 + 28000 2800 0.00011532129 0.00016694886 2701 + 28200 2820 0.00011869854 0.00016163005 2701 + 28400 2840 0.00012209747 0.00015339281 2701 + 28600 2860 0.00012549322 0.00014765883 2701 + 28800 2880 0.00012898685 0.00014241765 2701 + 29000 2900 0.00013259039 0.00014215724 2701 + 29200 2920 0.00013628209 0.00014881155 2701 + 29400 2940 0.00014001213 0.00015671333 2701 + 29600 2960 0.00014379216 0.00016446215 2701 + 29800 2980 0.00014764687 0.0001639602 2701 + 30000 3000 0.00015142301 0.00015664816 2701 + 30200 3020 0.00015496407 0.00015545099 2701 + 30400 3040 0.00015797338 0.00015368625 2701 + 30600 3060 0.00016042141 0.00015679918 2701 + 30800 3080 0.00016244716 0.00016093678 2701 + 31000 3100 0.00016202247 0.00016066954 2701 + 31200 3120 0.0001613312 0.00015932059 2701 + 31400 3140 0.00016274961 0.00015988567 2701 + 31600 3160 0.00016541518 0.00015724809 2701 + 31800 3180 0.00016809362 0.00015498827 2701 + 32000 3200 0.00017067801 0.00014830489 2701 + 32200 3220 0.00017333906 0.00014371345 2701 + 32400 3240 0.0001759011 0.00014421259 2701 + 32600 3260 0.00017849952 0.00014228443 2701 + 32800 3280 0.00017801812 0.00014117391 2701 + 33000 3300 0.00017718857 0.00014644675 2701 + 33200 3320 0.00017833666 0.0001291286 2701 + 33400 3340 0.000178576 0.00014878558 2701 + 33600 3360 0.00017846711 0.00013905481 2701 + 33800 3380 0.00017822937 0.00015535996 2701 + 34000 3400 0.00017899663 0.00016094303 2701 + 34200 3420 0.00017924661 0.00015017553 2701 + 34400 3440 0.00018024855 0.00014723549 2701 + 34600 3460 0.00018143865 0.00013903131 2701 + 34800 3480 0.00018258173 0.00013722112 2701 + 35000 3500 0.00018404873 0.00014675949 2701 + 35200 3520 0.00018538521 0.00015108242 2701 + 35400 3540 0.00018669649 0.00014564852 2701 + 35600 3560 0.00018814608 0.00013762161 2701 + 35800 3580 0.00018967415 0.00014602307 2701 + 36000 3600 0.00019146735 0.000126909 2701 + 36200 3620 0.00019414036 0.00012384379 2701 + 36400 3640 0.00019613057 0.00011059573 2701 + 36600 3660 0.00019897104 0.00013621801 2701 + 36800 3680 0.00020169688 0.00013665462 2701 + 37000 3700 0.00020447655 0.00013929258 2701 + 37200 3720 0.00020711105 0.0001363895 2701 + 37400 3740 0.00021077854 0.00013610672 2701 + 37600 3760 0.00021303084 0.00015051235 2701 + 37800 3780 0.00021619561 0.00012664801 2701 + 38000 3800 0.0002194018 0.00012808247 2701 + 38200 3820 0.00022242646 0.0001360174 2701 + 38400 3840 0.00022531568 0.00013311221 2701 + 38600 3860 0.00022821731 0.00013523939 2701 + 38800 3880 0.000231228 0.00014090695 2701 + 39000 3900 0.00023404038 0.00013661835 2701 + 39200 3920 0.00023755044 0.00013659469 2701 + 39400 3940 0.00024009059 0.00012097907 2701 + 39600 3960 0.0002432098 9.7877876e-05 2701 + 39800 3980 0.00024475294 0.0001164688 2701 + 40000 4000 0.00024171274 0.00012432219 2701 +Loop time of 192.659 on 4 procs for 40000 steps with 2701 atoms + +Performance: 1793840.118 tau/day, 207.620 timesteps/s, 560.783 katom-step/s +99.6% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 16.881 | 24.402 | 30.74 | 114.6 | 12.67 +Bond | 1.1126 | 1.8917 | 2.6935 | 43.3 | 0.98 +Neigh | 35.387 | 35.508 | 35.625 | 1.5 | 18.43 +Comm | 1.5499 | 1.6694 | 1.8006 | 7.4 | 0.87 +Output | 0.99755 | 1.0072 | 1.0165 | 0.8 | 0.52 +Modify | 120.6 | 127.43 | 135.54 | 54.8 | 66.14 +Other | | 0.7553 | | | 0.39 + +Nlocal: 675.25 ave 1373 max 7 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Nghost: 103 ave 163 max 50 min +Histogram: 2 0 0 0 0 0 0 0 1 1 +Neighs: 10509 ave 21592 max 126 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +FullNghs: 20367 ave 41981 max 141 min +Histogram: 2 0 0 0 0 0 0 0 0 2 + +Total # of neighbors = 81468 +Ave neighs/atom = 30.162162 +Ave special neighs/atom = 1.6593854 +Neighbor list builds = 39932 +Dangerous builds = 0 + +Total wall time: 0:03:12 diff --git a/examples/rheo/poiseuille/in.rheo.poiseuille b/examples/rheo/poiseuille/in.rheo.poiseuille index 7c38c8a6e0..ec283d9a00 100644 --- a/examples/rheo/poiseuille/in.rheo.poiseuille +++ b/examples/rheo/poiseuille/in.rheo.poiseuille @@ -69,7 +69,7 @@ compute rho all rheo/property/atom rho thermo 200 thermo_style custom step time ke press -dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho run 20000 diff --git a/examples/rheo/poiseuille/log.17Apr2024.poiseuille.g++.4 b/examples/rheo/poiseuille/log.17Apr2024.poiseuille.g++.4 new file mode 100644 index 0000000000..1fd8377b7a --- /dev/null +++ b/examples/rheo/poiseuille/log.17Apr2024.poiseuille.g++.4 @@ -0,0 +1,288 @@ +LAMMPS (17 Apr 2024 - Development - patch_5May2020-18508-g3c0eaf6870-modified) +# ------ 2D Poiseuille flow ------ # + +dimension 2 +units lj +atom_style rheo +boundary p p p +comm_modify vel yes + +# ------ Create simulation box ------ # + +variable n equal 1.0 +variable cut equal 3.0 + +region box block 0 20 -10 10 -0.01 0.01 +create_box 2 box +Created orthogonal box = (0 -10 -0.01) to (20 10 0.01) + 2 by 2 by 1 MPI processor grid +lattice sq ${n} +lattice sq 1 +Lattice spacing in x,y,z = 1 1 1 + +region inner block INF INF -7.5 7.5 INF INF units box +region walls block INF INF -7.5 7.5 INF INF units box side out + +create_atoms 2 region walls +Created 100 atoms + using lattice units in orthogonal box = (0 -10 -0.01) to (20 10 0.01) + create_atoms CPU = 0.000 seconds +create_atoms 1 region inner +Created 300 atoms + using lattice units in orthogonal box = (0 -10 -0.01) to (20 10 0.01) + create_atoms CPU = 0.000 seconds + +group fluid type 1 +300 atoms in group fluid +group rig type 2 +100 atoms in group rig + +displace_atoms fluid random 0.1 0.1 0 135414 units box +Displacing atoms ... + +# ------ Model parameters ------ # + +variable rho0 equal 1.0 +variable cs equal 1.0 +variable mp equal ${rho0}/${n} +variable mp equal 1/${n} +variable mp equal 1/1 +variable zeta equal 1.0 +variable kappa equal 1.0*${rho0}/${mp} +variable kappa equal 1.0*1/${mp} +variable kappa equal 1.0*1/1 +variable fext equal 1e-4/${n} +variable fext equal 1e-4/1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable dt_max equal 0.1*3/${cs}/3 +variable dt_max equal 0.1*3/1/3 +variable Dr equal 0.05*${cut}*${cs} +variable Dr equal 0.05*3*${cs} +variable Dr equal 0.05*3*1 + +variable eta equal 0.1 +variable gd0 equal 5e-4 +variable npow equal 0.5 +variable K equal 0.001 + +mass * ${mp} +mass * 1 +set group all rheo/rho ${rho0} +set group all rheo/rho 1 +Setting atom values ... + 400 settings made for rheo/rho +set group all rheo/status 0 +Setting atom values ... + 400 settings made for rheo/status +set group rig rheo/status 1 +Setting atom values ... + 100 settings made for rheo/status + +timestep ${dt_max} +timestep 0.1 + +pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} +pair_style rheo 3 artificial/visc ${zeta} rho/damp ${Dr} +pair_style rheo 3 artificial/visc 1 rho/damp ${Dr} +pair_style rheo 3 artificial/visc 1 rho/damp 0.15 +pair_coeff * * + +# ------ Fixes & computes ------ # + +fix 1 all rheo ${cut} quintic 0 shift +fix 1 all rheo 3 quintic 0 shift +fix 2 all rheo/viscosity * constant ${eta} +fix 2 all rheo/viscosity * constant 0.1 +#fix 2 all rheo/viscosity * power ${eta} ${gd0} ${K} ${npow} +fix 3 all rheo/pressure * linear +fix 4 rig setforce 0.0 0.0 0.0 +fix 5 fluid addforce ${fext} 0.0 0.0 +fix 5 fluid addforce 0.0001 0.0 0.0 +fix 6 all enforce2d + +compute rho all rheo/property/atom rho + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho + +run 20000 + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Your simulation uses code contributions which should be cited: + +- @article{PalermoInPrep, + journal = {in prep}, + title = {RHEO: A Hybrid Mesh-Free Model Framework for Dynamic Multi-Phase Flows}, + year = {2024}, + author = {Eric T. Palermo and Ki T. Wolf and Joel T. Clemmer and Thomas C. O'Connor}, +} + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Generated 0 of 1 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 3.3 + ghost atom cutoff = 3.3 + binsize = 1.65, bins = 13 13 1 + 4 neighbor lists, perpetual/occasional/extra = 4 0 0 + (1) pair rheo, perpetual, half/full from (2) + attributes: half, newton on + pair build: halffull/newton + stencil: none + bin: none + (2) compute RHEO/KERNEL, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/2d + bin: standard + (3) compute RHEO/GRAD, perpetual, copy from (1) + attributes: half, newton on + pair build: copy + stencil: none + bin: none + (4) compute RHEO/VSHIFT, perpetual, copy from (1) + attributes: half, newton on + pair build: copy + stencil: none + bin: none +Per MPI rank memory allocation (min/avg/max) = 5.693 | 5.693 | 5.693 Mbytes + Step Time KinEng Press + 0 0 0 0 + 200 20 1.2220462e-06 3.7383146e-05 + 400 40 4.345762e-06 7.5866885e-05 + 600 60 8.8559433e-06 0.00011353743 + 800 80 1.4370506e-05 0.00015135634 + 1000 100 2.0576198e-05 0.00018903722 + 1200 120 2.721926e-05 0.00022533997 + 1400 140 3.4099653e-05 0.00026016069 + 1600 160 4.1064175e-05 0.00029445207 + 1800 180 4.8001225e-05 0.00032893763 + 2000 200 5.4832849e-05 0.00036402396 + 2200 220 6.1508431e-05 0.00039945249 + 2400 240 6.8000141e-05 0.00043534411 + 2600 260 7.430136e-05 0.00046943441 + 2800 280 8.0415328e-05 0.00049807225 + 3000 300 8.6335032e-05 0.00051815375 + 3200 320 9.2021626e-05 0.00052618224 + 3400 340 9.7387936e-05 0.00051877918 + 3600 360 0.00010231526 0.00048650828 + 3800 380 0.00010676617 0.00044578079 + 4000 400 0.00011080098 0.00044777126 + 4200 420 0.00011448127 0.00047047629 + 4400 440 0.00011787852 0.00050280249 + 4600 460 0.00012106805 0.0005397213 + 4800 480 0.00012412056 0.00057885539 + 5000 500 0.0001271078 0.00061396896 + 5200 520 0.00013006637 0.00063981812 + 5400 540 0.00013295039 0.00065094073 + 5600 560 0.00013561487 0.00063918847 + 5800 580 0.00013791796 0.00059087656 + 6000 600 0.00013983422 0.00052171998 + 6200 620 0.00014144833 0.00050658002 + 6400 640 0.00014286538 0.0005248626 + 6600 660 0.00014417734 0.00055826606 + 6800 680 0.00014546931 0.00060063748 + 7000 700 0.00014682553 0.00064421411 + 7200 720 0.0001482833 0.00068252242 + 7400 740 0.00014977996 0.00070671308 + 7600 760 0.00015114829 0.00069774026 + 7800 780 0.0001522719 0.00064408311 + 8000 800 0.00015312897 0.00055977044 + 8200 820 0.00015375669 0.0005225573 + 8400 840 0.00015425683 0.00053833691 + 8600 860 0.00015471278 0.00057447427 + 8800 880 0.0001552059 0.00061980921 + 9000 900 0.00015581593 0.0006659836 + 9200 920 0.0001565564 0.00070813532 + 9400 940 0.00015733573 0.00073378551 + 9600 960 0.00015802107 0.00071560835 + 9800 980 0.00015855339 0.00065636189 + 10000 1000 0.00015890743 0.0005699855 + 10200 1020 0.00015908095 0.00053138971 + 10400 1040 0.00015915523 0.00054790708 + 10600 1060 0.00015921254 0.00058899454 + 10800 1080 0.00015934193 0.00063964906 + 11000 1100 0.00015959891 0.00069241358 + 11200 1120 0.0001599636 0.00073734651 + 11400 1140 0.00016036526 0.00074477329 + 11600 1160 0.00016075471 0.00071047555 + 11800 1180 0.00016109516 0.00064173183 + 12000 1200 0.00016131524 0.00055500553 + 12200 1220 0.00016136366 0.0005290215 + 12400 1240 0.0001613025 0.00055124296 + 12600 1260 0.00016123023 0.00059758627 + 12800 1280 0.00016123043 0.00065488735 + 13000 1300 0.00016132935 0.0007140876 + 13200 1320 0.00016152165 0.00074795629 + 13400 1340 0.00016180372 0.00074730778 + 13600 1360 0.00016216585 0.00071370995 + 13800 1380 0.0001625339 0.00065176323 + 14000 1400 0.00016274999 0.00057515371 + 14200 1420 0.00016271295 0.00055878258 + 14400 1440 0.00016249768 0.00058448193 + 14600 1460 0.00016223675 0.00063096229 + 14800 1480 0.00016201846 0.00068639548 + 15000 1500 0.00016190593 0.00072444357 + 15200 1520 0.00016194466 0.00073830636 + 15400 1540 0.00016216164 0.00072773256 + 15600 1560 0.00016253174 0.00069215481 + 15800 1580 0.00016290895 0.00063239408 + 16000 1600 0.00016306463 0.00057466273 + 16200 1620 0.00016292218 0.00057951567 + 16400 1640 0.00016261117 0.00061504156 + 16600 1660 0.00016225906 0.00066066637 + 16800 1680 0.00016197993 0.00069751908 + 17000 1700 0.0001618568 0.00072202303 + 17200 1720 0.00016194264 0.00073255034 + 17400 1740 0.00016225911 0.0007231031 + 17600 1760 0.00016270465 0.00068931224 + 17800 1780 0.00016304053 0.00062934836 + 18000 1800 0.00016302624 0.00058060272 + 18200 1820 0.00016274847 0.00058859513 + 18400 1840 0.00016236893 0.00061804803 + 18600 1860 0.00016202777 0.00065393237 + 18800 1880 0.0001618184 0.00068747094 + 19000 1900 0.0001618044 0.00071352541 + 19200 1920 0.00016204402 0.00072351769 + 19400 1940 0.00016249999 0.00071330322 + 19600 1960 0.00016297924 0.00067984167 + 19800 1980 0.00016317435 0.00061634142 + 20000 2000 0.00016301186 0.00057234115 +Loop time of 15.6198 on 4 procs for 20000 steps with 400 atoms + +Performance: 11062881.511 tau/day, 1280.426 timesteps/s, 512.170 katom-step/s +99.7% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 2.1979 | 2.4473 | 2.6992 | 15.7 | 15.67 +Neigh | 0.024709 | 0.027006 | 0.029223 | 1.3 | 0.17 +Comm | 0.4657 | 0.71686 | 0.9662 | 29.0 | 4.59 +Output | 0.033698 | 0.036781 | 0.039359 | 1.1 | 0.24 +Modify | 12.306 | 12.313 | 12.319 | 0.2 | 78.83 +Other | | 0.07916 | | | 0.51 + +Nlocal: 100 ave 107 max 93 min +Histogram: 1 0 0 1 0 0 1 0 0 1 +Nghost: 185.5 ave 192 max 179 min +Histogram: 1 0 0 1 0 0 1 0 0 1 +Neighs: 1712 ave 1848 max 1598 min +Histogram: 1 0 1 0 0 1 0 0 0 1 +FullNghs: 3424 ave 3682 max 3174 min +Histogram: 1 0 1 0 0 0 1 0 0 1 + +Total # of neighbors = 13696 +Ave neighs/atom = 34.24 +Neighbor list builds = 331 +Dangerous builds = 0 + + +Total wall time: 0:00:15 diff --git a/examples/rheo/taylor-green/log.17Apr2024.taylor.green.g++.4 b/examples/rheo/taylor-green/log.17Apr2024.taylor.green.g++.4 new file mode 100644 index 0000000000..6daf4a6eee --- /dev/null +++ b/examples/rheo/taylor-green/log.17Apr2024.taylor.green.g++.4 @@ -0,0 +1,224 @@ +LAMMPS (17 Apr 2024 - Development - patch_5May2020-18508-g3c0eaf6870-modified) +# ------ 2D Taylor Green vortex ------ # + +dimension 2 +units lj +atom_style rheo +boundary p p p +comm_modify vel yes +newton off + +# ------ Create simulation box ------ # + +variable n equal 1.0 +variable cut equal 3.0 + +region box block 0 40 0 40 -0.01 0.01 +create_box 1 box +Created orthogonal box = (0 0 -0.01) to (40 40 0.01) + 2 by 2 by 1 MPI processor grid +lattice sq ${n} +lattice sq 1 +Lattice spacing in x,y,z = 1 1 1 + +create_atoms 1 region box +Created 1600 atoms + using lattice units in orthogonal box = (0 0 -0.01) to (40 40 0.01) + create_atoms CPU = 0.001 seconds + +displace_atoms all random 0.1 0.1 0 135414 units box +Displacing atoms ... + +# ------ Model parameters ------ # + +variable rho0 equal 1.0 +variable mp equal ${rho0}/${n} +variable mp equal 1/${n} +variable mp equal 1/1 +variable cs equal 1.0 +variable eta equal 0.05 +variable zeta equal 1 +variable dt_max equal 0.1*${cut}/${cs}/3 +variable dt_max equal 0.1*3/${cs}/3 +variable dt_max equal 0.1*3/1/3 +variable Dr equal 0.1*${cut}*${cs} +variable Dr equal 0.1*3*${cs} +variable Dr equal 0.1*3*1 + +mass * ${mp} +mass * 1 +set group all rheo/rho ${rho0} +set group all rheo/rho 1 +Setting atom values ... + 1600 settings made for rheo/rho +set group all rheo/status 0 +Setting atom values ... + 1600 settings made for rheo/status + +variable u0 equal 0.05 +variable uy atom ${u0}*sin(2*PI*x/lx)*cos(2*PI*y/ly) +variable uy atom 0.05*sin(2*PI*x/lx)*cos(2*PI*y/ly) +variable ux atom -${u0}*sin(2*PI*y/ly)*cos(2*PI*x/ly) +variable ux atom -0.05*sin(2*PI*y/ly)*cos(2*PI*x/ly) +variable d0 atom ${rho0}-${u0}*${u0}*${rho0}*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/${cs}/${cs} +variable d0 atom 1-${u0}*${u0}*${rho0}*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/${cs}/${cs} +variable d0 atom 1-0.05*${u0}*${rho0}*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/${cs}/${cs} +variable d0 atom 1-0.05*0.05*${rho0}*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/${cs}/${cs} +variable d0 atom 1-0.05*0.05*1*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/${cs}/${cs} +variable d0 atom 1-0.05*0.05*1*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/1/${cs} +variable d0 atom 1-0.05*0.05*1*0.25*(cos(4*PI*x/lx)+cos(4*PI*y/ly))/1/1 + +velocity all set v_ux v_uy 0.0 units box + +timestep ${dt_max} +timestep 0.1 + +pair_style rheo ${cut} artificial/visc ${zeta} rho/damp ${Dr} +pair_style rheo 3 artificial/visc ${zeta} rho/damp ${Dr} +pair_style rheo 3 artificial/visc 1 rho/damp ${Dr} +pair_style rheo 3 artificial/visc 1 rho/damp 0.3 +pair_coeff * * + +# ------ Fixes & computes ------ # + +fix 1 all rheo ${cut} RK1 8 shift +fix 1 all rheo 3 RK1 8 shift +fix 2 all rheo/viscosity * constant ${eta} +fix 2 all rheo/viscosity * constant 0.05 +fix 3 all rheo/pressure * linear +fix 4 all enforce2d + +compute rho all rheo/property/atom rho + +# ------ Output & Run ------ # + +thermo 200 +thermo_style custom step time ke press + +dump 1 all custom 200 atomDump id type x y vx vy fx fy c_rho + +run 10000 + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Your simulation uses code contributions which should be cited: + +- @article{PalermoInPrep, + journal = {in prep}, + title = {RHEO: A Hybrid Mesh-Free Model Framework for Dynamic Multi-Phase Flows}, + year = {2024}, + author = {Eric T. Palermo and Ki T. Wolf and Joel T. Clemmer and Thomas C. O'Connor}, +} + +CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE-CITE + +Generated 0 of 0 mixed pair_coeff terms from geometric mixing rule +Neighbor list info ... + update: every = 1 steps, delay = 0 steps, check = yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 3.3 + ghost atom cutoff = 3.3 + binsize = 1.65, bins = 25 25 1 + 4 neighbor lists, perpetual/occasional/extra = 4 0 0 + (1) pair rheo, perpetual, half/full from (2) + attributes: half, newton off + pair build: halffull/newtoff + stencil: none + bin: none + (2) compute RHEO/KERNEL, perpetual + attributes: full, newton off + pair build: full/bin/atomonly + stencil: full/bin/2d + bin: standard + (3) compute RHEO/GRAD, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none + (4) compute RHEO/VSHIFT, perpetual, copy from (1) + attributes: half, newton off + pair build: copy + stencil: none + bin: none +Per MPI rank memory allocation (min/avg/max) = 6.835 | 6.835 | 6.835 Mbytes + Step Time KinEng Press + 0 0 0.00062497276 0.00062607301 + 200 20 0.00056200647 0.00056633785 + 400 40 0.00050570968 0.00051098771 + 600 60 0.00045586684 0.00046081672 + 800 80 0.00041124523 0.00041549607 + 1000 100 0.00037065341 0.00037412741 + 1200 120 0.00033391585 0.00033580899 + 1400 140 0.00030078316 0.00030057307 + 1600 160 0.00027093231 0.00026842603 + 1800 180 0.00024403239 0.00023839026 + 2000 200 0.0002197865 0.00021148941 + 2200 220 0.0001979269 0.00018659386 + 2400 240 0.00017822267 0.00016430442 + 2600 260 0.00016047141 0.00014408514 + 2800 280 0.00014448504 0.00012574125 + 3000 300 0.00013009159 0.00010869938 + 3200 320 0.00011713578 9.414951e-05 + 3400 340 0.00010547564 8.1900579e-05 + 3600 360 9.4982139e-05 7.1285649e-05 + 3800 380 8.5538983e-05 6.1571123e-05 + 4000 400 7.7040171e-05 5.3462572e-05 + 4200 420 6.9390317e-05 4.6338308e-05 + 4400 440 6.2503763e-05 3.9697323e-05 + 4600 460 5.6303766e-05 3.4234465e-05 + 4800 480 5.0721595e-05 3.0841338e-05 + 5000 500 4.5695301e-05 2.7788566e-05 + 5200 520 4.1169161e-05 2.5744409e-05 + 5400 540 3.7093059e-05 2.3912739e-05 + 5600 560 3.3421819e-05 2.2494185e-05 + 5800 580 3.0114735e-05 2.1594384e-05 + 6000 600 2.7135224e-05 2.1164421e-05 + 6200 620 2.4450446e-05 2.0979349e-05 + 6400 640 2.2030925e-05 2.0858567e-05 + 6600 660 1.9850196e-05 2.098115e-05 + 6800 680 1.7884553e-05 2.1134827e-05 + 7000 700 1.6112763e-05 2.1242242e-05 + 7200 720 1.4515783e-05 2.1312763e-05 + 7400 740 1.3076456e-05 2.1370947e-05 + 7600 760 1.1779327e-05 2.1332126e-05 + 7800 780 1.0610469e-05 2.1156562e-05 + 8000 800 9.5573298e-06 2.0898126e-05 + 8200 820 8.6085799e-06 2.0517958e-05 + 8400 840 7.7539888e-06 1.9841551e-05 + 8600 860 6.9843033e-06 1.9114769e-05 + 8800 880 6.2911575e-06 1.8362959e-05 + 9000 900 5.6669785e-06 1.7473404e-05 + 9200 920 5.1049208e-06 1.6452745e-05 + 9400 940 4.5987908e-06 1.5578629e-05 + 9600 960 4.1429972e-06 1.4427274e-05 + 9800 980 3.7324962e-06 1.3169649e-05 + 10000 1000 3.3627455e-06 1.1938723e-05 +Loop time of 38.2006 on 4 procs for 10000 steps with 1600 atoms + +Performance: 2261743.875 tau/day, 261.776 timesteps/s, 418.841 katom-step/s +99.7% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 8.2958 | 8.7273 | 9.3582 | 15.2 | 22.85 +Neigh | 0.034282 | 0.035689 | 0.037115 | 0.7 | 0.09 +Comm | 0.16788 | 0.17018 | 0.17278 | 0.4 | 0.45 +Output | 0.066977 | 0.06882 | 0.071704 | 0.7 | 0.18 +Modify | 28.483 | 28.793 | 28.962 | 3.6 | 75.37 +Other | | 0.4053 | | | 1.06 + +Nlocal: 400 ave 402 max 399 min +Histogram: 2 0 0 1 0 0 0 0 0 1 +Nghost: 307.25 ave 308 max 305 min +Histogram: 1 0 0 0 0 0 0 0 0 3 +Neighs: 7618.25 ave 7697 max 7564 min +Histogram: 1 0 1 1 0 0 0 0 0 1 +FullNghs: 13343 ave 13497 max 13258 min +Histogram: 1 1 1 0 0 0 0 0 0 1 + +Total # of neighbors = 53372 +Ave neighs/atom = 33.3575 +Neighbor list builds = 123 +Dangerous builds = 0 +Total wall time: 0:00:38 diff --git a/src/BPM/bond_bpm_spring.cpp b/src/BPM/bond_bpm_spring.cpp index 775d8d1597..2863bbf317 100644 --- a/src/BPM/bond_bpm_spring.cpp +++ b/src/BPM/bond_bpm_spring.cpp @@ -23,8 +23,6 @@ #include "modify.h" #include "neighbor.h" -#include "update.h" - #include #include diff --git a/src/BPM/compute_nbond_atom.cpp b/src/BPM/compute_nbond_atom.cpp index 98263f3b4d..31428b1912 100644 --- a/src/BPM/compute_nbond_atom.cpp +++ b/src/BPM/compute_nbond_atom.cpp @@ -30,7 +30,7 @@ ComputeNBondAtom::ComputeNBondAtom(LAMMPS *_lmp, int narg, char **arg) : if (narg < 3) utils::missing_cmd_args(FLERR, "compute nbond/atom", error); if (atom->avec->bonds_allow == 0) - error->all(FLERR,"Compute nbond/atom used when bonds are not allowed"); + error->all(FLERR,"Compute nbond/atom used in system without bonds"); btype = -1; int iarg = 3; diff --git a/src/BPM/fix_update_special_bonds.cpp b/src/BPM/fix_update_special_bonds.cpp index 5dddbdd55e..c71f6973d0 100644 --- a/src/BPM/fix_update_special_bonds.cpp +++ b/src/BPM/fix_update_special_bonds.cpp @@ -169,7 +169,7 @@ void FixUpdateSpecialBonds::pre_force(int /*vflag*/) tagint *tag = atom->tag; // In theory could communicate a list of broken bonds to neighboring processors here - // to remove restriction that users use Newton bond off + // to remove restriction on Newton bond off for (int ilist = 0; ilist < neighbor->nlist; ilist++) { list = neighbor->lists[ilist]; diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index c8eee29438..9c198364d6 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -250,8 +250,8 @@ void BondRHEOShell::compute(int eflag, int vflag) if (t >= tform) { bondstore[n][0] = r; r0 = r; - if (newton_bond || i1 < nlocal) dbond[i1] ++; - if (newton_bond || i2 < nlocal) dbond[i2] ++; + if (newton_bond || i1 < nlocal) dbond[i1]++; + if (newton_bond || i2 < nlocal) dbond[i2]++; } else { continue; } @@ -261,8 +261,8 @@ void BondRHEOShell::compute(int eflag, int vflag) if (fabs(e) > ecrit[type]) { bondlist[n][2] = 0; process_broken(i1, i2); - if (newton_bond || i1 < nlocal) dbond[i1] --; - if (newton_bond || i2 < nlocal) dbond[i2] --; + if (newton_bond || i1 < nlocal) dbond[i1]--; + if (newton_bond || i2 < nlocal) dbond[i2]--; continue; } @@ -388,9 +388,8 @@ void BondRHEOShell::settings(int narg, char **arg) for (std::size_t i = 0; i < leftover_iarg.size(); i++) { iarg = leftover_iarg[i]; if (strcmp(arg[iarg], "t/form") == 0) { - if (iarg + 1 > narg) error->all(FLERR, "Illegal bond rheo/shell command, missing option for t/form"); + if (iarg + 1 > narg) utils::missing_cmd_args(FLERR, "bond rheo/shell t/form", error); tform = utils::numeric(FLERR, arg[iarg + 1], false, lmp); - if (tform < 0.0) error->all(FLERR, "Illegal bond rheo/shell value for t/form, {}", tform); i += 1; } else { error->all(FLERR, "Illegal bond rheo/shell command, invalid argument {}", arg[iarg]); @@ -398,7 +397,7 @@ void BondRHEOShell::settings(int narg, char **arg) } if (tform < 0.0) - error->all(FLERR, "Illegal bond rheo/shell command, must specify formation time"); + error->all(FLERR, "Illegal bond rheo/shell command, must specify positive formation time"); } diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index d0f24850bd..cb9a42323b 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -57,7 +57,7 @@ ComputeRHEOKernel::ComputeRHEOKernel(LAMMPS *lmp, int narg, char **arg) : { if (narg != 4) error->all(FLERR,"Illegal compute rheo/kernel command"); - kernel_style = utils::inumeric(FLERR,arg[3],false,lmp); + kernel_style = utils::inumeric(FLERR, arg[3], false, lmp); if (kernel_style == QUINTIC || kernel_style == WENDLANDC4) { correction_order = -1; @@ -110,27 +110,27 @@ void ComputeRHEOKernel::init() compute_interface = fix_rheo->compute_interface; zmin = fix_rheo->zmin_kernel; - h = fix_rheo->h; - hsq = h * h; - hinv = 1.0 / h; - hsqinv = hinv * hinv; + cut = fix_rheo->cut; + cutsq = cut * cut; + cutinv = 1.0 / cut; + cutsqinv = cutinv * cutinv; if (kernel_style != WENDLANDC4) { if (dim == 3) { - pre_w = 1.0 / (120.0 * MY_PI) * 27.0 * hsqinv * hinv; - pre_wp = pre_w * 3.0 * hinv; + pre_w = 1.0 / (120.0 * MY_PI) * 27.0 * cutsqinv * cutinv; + pre_wp = pre_w * 3.0 * cutinv; } else { - pre_w = 7.0 / (478.0 * MY_PI) * 9 * hsqinv; - pre_wp = pre_w * 3.0 * hinv; + pre_w = 7.0 / (478.0 * MY_PI) * 9 * cutsqinv; + pre_wp = pre_w * 3.0 * cutinv; } } else { if (dim == 3) { - pre_w = 495.0 / (32.0 * MY_PI * hsq * h); - pre_wp = pre_w * hinv; + pre_w = 495.0 / (32.0 * MY_PI * cutsq * cut); + pre_wp = pre_w * cutinv; } else { - pre_w = 9.0 / (MY_PI * hsq); - pre_wp = pre_w * hinv; + pre_w = 9.0 / (MY_PI * cutsq); + pre_wp = pre_w * cutinv; } } @@ -193,7 +193,7 @@ double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double int corrections_i, corrections_j, corrections; if (kernel_style == WENDLANDC4) - return calc_w_wendlandc4(i,j,delx,dely,delz,r); + return calc_w_wendlandc4(i, j, delx, dely, delz, r); if (kernel_style != QUINTIC) { corrections_i = check_corrections(i); @@ -203,10 +203,10 @@ double ComputeRHEOKernel::calc_w(int i, int j, double delx, double dely, double corrections = 0; } - if (!corrections) w = calc_w_quintic(i,j,delx,dely,delz,r); - else if (kernel_style == RK0) w = calc_w_rk0(i,j,delx,dely,delz,r); - else if (kernel_style == RK1) w = calc_w_rk1(i,j,delx,dely,delz,r); - else if (kernel_style == RK2) w = calc_w_rk2(i,j,delx,dely,delz,r); + if (!corrections) w = calc_w_quintic(i, j, delx, dely, delz, r); + else if (kernel_style == RK0) w = calc_w_rk0(i, j, delx, dely, delz, r); + else if (kernel_style == RK1) w = calc_w_rk1(i, j, delx, dely, delz, r); + else if (kernel_style == RK2) w = calc_w_rk2(i, j, delx, dely, delz, r); return w; } @@ -219,7 +219,7 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double int corrections_i, corrections_j; if (kernel_style == WENDLANDC4) - return calc_dw_wendlandc4(i,j,delx,dely,delz,r,dWij,dWji); + return calc_dw_wendlandc4(i, j, delx, dely, delz, r, dWij, dWji); if (kernel_style != QUINTIC) { corrections_i = check_corrections(i); @@ -227,15 +227,15 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double } // Calc wp and default dW's, a bit inefficient but can redo later - wp = calc_dw_quintic(i,j,delx,dely,delz,r,dWij,dWji); + wp = calc_dw_quintic(i, j, delx, dely, delz, r, dWij, dWji); // Overwrite if there are corrections if (kernel_style == RK1) { - if (corrections_i) calc_dw_rk1(i,j,delx,dely,delz,r,dWij); - if (corrections_j) calc_dw_rk1(j,i,-delx,-dely,-delz,r,dWji); + if (corrections_i) calc_dw_rk1(i, j, delx, dely, delz, r, dWij); + if (corrections_j) calc_dw_rk1(j, i, -delx, -dely, -delz, r, dWji); } else if (kernel_style == RK2) { - if (corrections_i) calc_dw_rk2(i,j,delx,dely,delz,r,dWij); - if (corrections_j) calc_dw_rk2(j,i,-delx,-dely,-delz,r,dWji); + if (corrections_i) calc_dw_rk2(i, j, delx, dely, delz, r, dWij); + if (corrections_j) calc_dw_rk2(j, i, -delx, -dely, -delz, r, dWji); } return wp; @@ -246,7 +246,7 @@ double ComputeRHEOKernel::calc_dw(int i, int j, double delx, double dely, double double ComputeRHEOKernel::calc_w_quintic(int i, int j, double delx, double dely, double delz, double r) { double w, tmp1, tmp2, tmp3, tmp1sq, tmp2sq, tmp3sq, s; - s = r * 3.0 * hinv; + s = r * 3.0 * cutinv; if (s > 3.0) { w = 0.0; @@ -284,7 +284,7 @@ double ComputeRHEOKernel::calc_dw_quintic(int i, int j, double delx, double dely double *mass = atom->mass; int *type = atom->type; - s = r * 3.0 * hinv; + s = r * 3.0 * cutinv; if (s > 3.0) { wp = 0.0; @@ -323,7 +323,7 @@ double ComputeRHEOKernel::calc_dw_quintic(int i, int j, double delx, double dely double ComputeRHEOKernel::calc_w_wendlandc4(int i, int j, double delx, double dely, double delz, double r) { double w, tmp6, s; - s = r * hinv; + s = r * cutinv; if (s > 1.0) { w = 0.0; @@ -349,7 +349,7 @@ double ComputeRHEOKernel::calc_dw_wendlandc4(int i, int j, double delx, double d double *mass = atom->mass; int *type = atom->type; - s = r * hinv; + s = r * cutinv; if (s > 1.0) { wp = 0.0; @@ -381,7 +381,7 @@ double ComputeRHEOKernel::calc_w_rk0(int i, int j, double delx, double dely, dou { double w; - w = calc_w_quintic(i,j,delx,dely,delz,r); + w = calc_w_quintic(i, j, delx, dely, delz, r); Wij = C0[i] * w; Wji = C0[j] * w; @@ -399,17 +399,17 @@ double ComputeRHEOKernel::calc_w_rk1(int i, int j, double delx, double dely, dou dx[0] = delx; dx[1] = dely; dx[2] = delz; - w = calc_w_quintic(i,j,delx,dely,delz,r); + w = calc_w_quintic(i, j, delx, dely, delz, r); if (dim == 2) { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; } else { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; - H[3] = dx[2] * hinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; + H[3] = dx[2] * cutinv; } Wij = 0; for (b = 0; b < Mdim; b++) { @@ -440,26 +440,26 @@ double ComputeRHEOKernel::calc_w_rk2(int i, int j, double delx, double dely, dou dx[0] = delx; dx[1] = dely; dx[2] = delz; - w = calc_w_quintic(i,j,delx,dely,delz,r); + w = calc_w_quintic(i, j, delx, dely, delz, r); if (dim == 2) { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; - H[3] = 0.5 * dx[0] * dx[0] * hsqinv; - H[4] = 0.5 * dx[1] * dx[1] * hsqinv; - H[5] = dx[0] * dx[1] * hsqinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; + H[3] = 0.5 * dx[0] * dx[0] * cutsqinv; + H[4] = 0.5 * dx[1] * dx[1] * cutsqinv; + H[5] = dx[0] * dx[1] * cutsqinv; } else { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; - H[3] = dx[2] * hinv; - H[4] = 0.5 * dx[0] * dx[0] * hsqinv; - H[5] = 0.5 * dx[1] * dx[1] * hsqinv; - H[6] = 0.5 * dx[2] * dx[2] * hsqinv; - H[7] = dx[0] * dx[1] * hsqinv; - H[8] = dx[0] * dx[2] * hsqinv; - H[9] = dx[1] * dx[2] * hsqinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; + H[3] = dx[2] * cutinv; + H[4] = 0.5 * dx[0] * dx[0] * cutsqinv; + H[5] = 0.5 * dx[1] * dx[1] * cutsqinv; + H[6] = 0.5 * dx[2] * dx[2] * cutsqinv; + H[7] = dx[0] * dx[1] * cutsqinv; + H[8] = dx[0] * dx[2] * cutsqinv; + H[9] = dx[1] * dx[2] * cutsqinv; } Wij = 0; for (b = 0; b < Mdim; b++) { @@ -491,18 +491,18 @@ void ComputeRHEOKernel::calc_dw_rk1(int i, int j, double delx, double dely, doub dx[1] = dely; dx[2] = delz; - w = calc_w_quintic(i,j,delx,dely,delz,r); + w = calc_w_quintic(i, j, delx, dely, delz, r); //Populate correction basis if (dim == 2) { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; } else { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; - H[3] = dx[2] * hinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; + H[3] = dx[2] * cutinv; } // dWij[] = dWx dWy (dWz) @@ -528,27 +528,27 @@ void ComputeRHEOKernel::calc_dw_rk2(int i, int j, double delx, double dely, doub dx[1] = dely; dx[2] = delz; - w = calc_w_quintic(i,j,delx,dely,delz,r); + w = calc_w_quintic(i, j, delx, dely, delz, r); //Populate correction basis if (dim == 2) { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; - H[3] = 0.5 * dx[0] * dx[0] * hsqinv; - H[4] = 0.5 * dx[1] * dx[1] * hsqinv; - H[5] = dx[0] * dx[1] * hsqinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; + H[3] = 0.5 * dx[0] * dx[0] * cutsqinv; + H[4] = 0.5 * dx[1] * dx[1] * cutsqinv; + H[5] = dx[0] * dx[1] * cutsqinv; } else { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; - H[3] = dx[2] * hinv; - H[4] = 0.5 * dx[0] * dx[0] * hsqinv; - H[5] = 0.5 * dx[1] * dx[1] * hsqinv; - H[6] = 0.5 * dx[2] * dx[2] * hsqinv; - H[7] = dx[0] * dx[1] * hsqinv; - H[8] = dx[0] * dx[2] * hsqinv; - H[9] = dx[1] * dx[2] * hsqinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; + H[3] = dx[2] * cutinv; + H[4] = 0.5 * dx[0] * dx[0] * cutsqinv; + H[5] = 0.5 * dx[1] * dx[1] * cutsqinv; + H[6] = 0.5 * dx[2] * dx[2] * cutsqinv; + H[7] = dx[0] * dx[1] * cutsqinv; + H[8] = dx[0] * dx[2] * cutsqinv; + H[9] = dx[1] * dx[2] * cutsqinv; } // dWij[] = dWx dWy (dWz) @@ -621,7 +621,7 @@ void ComputeRHEOKernel::compute_peratom() dx[2] = ztmp - x[j][2]; rsq = lensq3(dx); - if (rsq < hsq) { + if (rsq < cutsq) { r = sqrt(rsq); w = calc_w_quintic(i, j, dx[0], dx[1], dx[2], r); rhoj = rho[j]; @@ -639,7 +639,7 @@ void ComputeRHEOKernel::compute_peratom() } } else if (correction_order > 0) { - // Moment matrix M and polynomial basis vector H (1d for gsl compatibility) + // Moment matrix M and polynomial basis vector cut (1d for gsl compatibility) double H[Mdim], M[Mdim * Mdim]; for (ii = 0; ii < inum; ii++) { @@ -652,7 +652,7 @@ void ComputeRHEOKernel::compute_peratom() jnum = numneigh[i]; itype = type[i]; - // Zero upper-triangle M and H (will be symmetric): + // Zero upper-triangle M and cut (will be symmetric): for (a = 0; a < Mdim; a++) { for (b = a; b < Mdim; b++) { M[a * Mdim + b] = 0; @@ -669,7 +669,7 @@ void ComputeRHEOKernel::compute_peratom() rsq = lensq3(dx); - if (rsq < hsq) { + if (rsq < cutsq) { r = sqrt(rsq); w = calc_w_quintic(i, j, dx[0], dx[1], dx[2], r); @@ -683,25 +683,25 @@ void ComputeRHEOKernel::compute_peratom() //Populate the H-vector of polynomials (2D) if (dim == 2) { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; if (kernel_style == RK2) { - H[3] = 0.5 * dx[0] * dx[0] * hsqinv; - H[4] = 0.5 * dx[1] * dx[1] * hsqinv; - H[5] = dx[0] * dx[1] * hsqinv; + H[3] = 0.5 * dx[0] * dx[0] * cutsqinv; + H[4] = 0.5 * dx[1] * dx[1] * cutsqinv; + H[5] = dx[0] * dx[1] * cutsqinv; } } else { H[0] = 1.0; - H[1] = dx[0] * hinv; - H[2] = dx[1] * hinv; - H[3] = dx[2] * hinv; + H[1] = dx[0] * cutinv; + H[2] = dx[1] * cutinv; + H[3] = dx[2] * cutinv; if (kernel_style == RK2) { - H[4] = 0.5 * dx[0] * dx[0] * hsqinv; - H[5] = 0.5 * dx[1] * dx[1] * hsqinv; - H[6] = 0.5 * dx[2] * dx[2] * hsqinv; - H[7] = dx[0] * dx[1] * hsqinv; - H[8] = dx[0] * dx[2] * hsqinv; - H[9] = dx[1] * dx[2] * hsqinv; + H[4] = 0.5 * dx[0] * dx[0] * cutsqinv; + H[5] = 0.5 * dx[1] * dx[1] * cutsqinv; + H[6] = 0.5 * dx[2] * dx[2] * cutsqinv; + H[7] = dx[0] * dx[1] * cutsqinv; + H[8] = dx[0] * dx[2] * cutsqinv; + H[9] = dx[1] * dx[2] * cutsqinv; } } @@ -765,12 +765,12 @@ void ComputeRHEOKernel::compute_peratom() C[i][0][a] = M[a * Mdim + 0]; // all rows of column 0 for (b = 0; b < dim; b++) { //First derivatives - C[i][1 + b][a] = -M[a * Mdim + b + 1] * hinv; + C[i][1 + b][a] = -M[a * Mdim + b + 1] * cutinv; // columns 1-2 (2D) or 1-3 (3D) //Second derivatives if (kernel_style == RK2) - C[i][1 + dim + b][a] = M[a * Mdim + b + 1 + dim] * hsqinv; + C[i][1 + dim + b][a] = M[a * Mdim + b + 1 + dim] * cutsqinv; // columns 3-4 (2D) or 4-6 (3D) } } @@ -822,7 +822,7 @@ void ComputeRHEOKernel::compute_coordination() dx[2] = ztmp - x[j][2]; rsq = lensq3(dx); - if (rsq < hsq) + if (rsq < cutsq) coordination[i] += 1; } } diff --git a/src/RHEO/compute_rheo_kernel.h b/src/RHEO/compute_rheo_kernel.h index 543e5d88c0..d15e8e210a 100644 --- a/src/RHEO/compute_rheo_kernel.h +++ b/src/RHEO/compute_rheo_kernel.h @@ -59,7 +59,7 @@ class ComputeRHEOKernel : public Compute { int corrections_calculated; int kernel_style, zmin, dim, Mdim, ncor; int nmax_store; - double h, hsq, hinv, hsqinv, pre_w, pre_wp; + double cut, cutsq, cutinv, cutsqinv, pre_w, pre_wp; double ***C; double *C0; diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index bf2f2a3297..284afcd992 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -181,7 +181,7 @@ void ComputeRHEOSurface::compute_peratom() gradC[i][a] += dWij[a] * Volj; } - if (j < nlocal || newton) { + if ((j < nlocal) || newton) { for (a = 0; a < dim; a++){ divr[j] += dWji[a] * dx[a] * Voli; gradC[j][a] += dWji[a] * Voli; @@ -287,7 +287,7 @@ void ComputeRHEOSurface::compute_peratom() } } - // clear normal vectors for non surface particles + // clear normal vectors for non-surface particles for (i = 0; i < nall; i++) { if (mask[i] & groupbit) { diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index c704677bec..f12d10b8c5 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -39,7 +39,12 @@ using namespace RHEO_NS; using namespace FixConst; static const char cite_rheo[] = - "TBD\n\n"; + "@article{PalermoInPrep,\n" + " journal = {in prep},\n" + " title = {RHEO: A Hybrid Mesh-Free Model Framework for Dynamic Multi-Phase Flows},\n" + " year = {2024},\n" + " author = {Eric T. Palermo and Ki T. Wolf and Joel T. Clemmer and Thomas C. O'Connor},\n" + "}\n\n"; /* ---------------------------------------------------------------------- */ @@ -84,10 +89,9 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR, "fix rheo command requires atom_style with status"); if (narg < 5) - error->all(FLERR, "Insufficient arguments for fix rheo command"); + utils::missing_cmd_args(FLERR, "fix rheo", error); - h = utils::numeric(FLERR, arg[3], false, lmp); - cut = h; + cut = utils::numeric(FLERR, arg[3], false, lmp); if (strcmp(arg[4], "quintic") == 0) { kernel_style = QUINTIC; } else if (strcmp(arg[4], "wendland/c4") == 0) { @@ -109,7 +113,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : thermal_flag = 1; } else if (strcmp(arg[iarg], "surface/detection") == 0) { surface_flag = 1; - if(iarg + 3 >= narg) error->all(FLERR, "Illegal surface/detection option in fix rheo"); + if(iarg + 3 >= narg) utils::missing_cmd_args(FLERR, "fix rheo surface/detection", error); if (strcmp(arg[iarg + 1], "coordination") == 0) { surface_style = COORDINATION; zmin_surface = utils::inumeric(FLERR, arg[iarg + 2], false, lmp); @@ -130,12 +134,12 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg], "self/mass") == 0) { self_mass_flag = 1; } else if (strcmp(arg[iarg], "density") == 0) { - if (iarg + n >= narg) error->all(FLERR, "Illegal rho0 option in fix rheo"); + if (iarg + n >= narg) utils::missing_cmd_args(FLERR, "fix rheo density", error); for (i = 1; i <= n; i++) rho0[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); iarg += n; } else if (strcmp(arg[iarg], "speed/sound") == 0) { - if (iarg + n >= narg) error->all(FLERR, "Illegal csq option in fix rheo"); + if (iarg + n >= narg) utils::missing_cmd_args(FLERR, "fix rheo speed/sound", error); for (i = 1; i <= n; i++) { csq[i] = utils::numeric(FLERR, arg[iarg + i], false, lmp); csq[i] *= csq[i]; @@ -281,7 +285,7 @@ void FixRHEO::setup(int /*vflag*/) if (!pressure_fix_defined) error->all(FLERR, "Missing fix rheo/pressure"); - if((!thermal_fix_defined) && thermal_flag) + if(thermal_flag && !thermal_fix_defined) error->all(FLERR, "Missing fix rheo/thermal"); // Reset to zero for future runs @@ -290,33 +294,6 @@ void FixRHEO::setup(int /*vflag*/) pressure_fix_defined = 0; oxidation_fix_defined = 0; - // Check fixes cover all atoms (may still fail if atoms are created) - // FixRHEOPressure currently requires group all - auto visc_fixes = modify->get_fix_by_style("rheo/viscosity"); - auto therm_fixes = modify->get_fix_by_style("rheo/thermal"); - - int *mask = atom->mask; - int v_coverage_flag = 1; - int t_coverage_flag = 1; - int covered; - for (int i = 0; i < atom->nlocal; i++) { - covered = 0; - for (auto fix : visc_fixes) - if (mask[i] & fix->groupbit) covered = 1; - if (!covered) v_coverage_flag = 0; - if (thermal_flag) { - covered = 0; - for (auto fix : therm_fixes) - if (mask[i] & fix->groupbit) covered = 1; - if (!covered) t_coverage_flag = 0; - } - } - - if (!v_coverage_flag) - error->one(FLERR, "Fix rheo/viscosity does not fully cover all atoms"); - if (!t_coverage_flag) - error->one(FLERR, "Fix rheo/thermal does not fully cover all atoms"); - if (rhosum_flag) compute_rhosum->compute_peratom(); } diff --git a/src/RHEO/fix_rheo.h b/src/RHEO/fix_rheo.h index 251f82a99a..8c62197fcd 100644 --- a/src/RHEO/fix_rheo.h +++ b/src/RHEO/fix_rheo.h @@ -39,7 +39,7 @@ class FixRHEO : public Fix { void reset_dt() override; // Model parameters - double h, cut; + double cut; double *rho0, *csq; int self_mass_flag; int zmin_kernel, zmin_surface, zmin_splash; diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index 5b0a50b4a5..acd833dfda 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -99,10 +99,10 @@ void FixRHEOOxidation::init() if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/oxidation"); fix_rheo = dynamic_cast(fixes[0]); - if (cut > fix_rheo->h) + if (cut > fix_rheo->cut) error->all(FLERR, "Bonding length exceeds kernel cutoff"); - if (rsurf >= fix_rheo->h) + if (rsurf >= fix_rheo->cut) error->all(FLERR, "Surface distance must be less than kernel cutoff"); if (!force->bond) error->all(FLERR, "Must define a bond style with fix rheo/oxidation"); @@ -233,7 +233,7 @@ void FixRHEOOxidation::post_integrate() // Add bonds to owned atoms // If newton bond off, add to both, otherwise add to whichever has a smaller tag - if (!newton_bond || tagi < tagj) { + if (!newton_bond || (tagi < tagj)) { if (num_bond[i] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/oxidation for atom {}", tagi); bond_type[i][num_bond[i]] = btype; diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index 321fee07e7..c1cda67500 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -71,6 +71,7 @@ FixRHEOThermal::FixRHEOThermal(LAMMPS *lmp, int narg, char **arg) : cut_bond = 0; comm_forward = 0; + // Currently can only have one instance of fix rheo/thermal if (igroup != 0) error->all(FLERR,"fix rheo/thermal command requires group all"); @@ -249,7 +250,7 @@ void FixRHEOThermal::init() auto fixes = modify->get_fix_by_style("^rheo$"); if (fixes.size() == 0) error->all(FLERR, "Need to define fix rheo to use fix rheo/viscosity"); fix_rheo = dynamic_cast(fixes[0]); - cut_kernel = fix_rheo->h; + cut_kernel = fix_rheo->cut; if (cut_bond > cut_kernel) error->all(FLERR, "Bonding length exceeds kernel cutoff"); @@ -263,16 +264,16 @@ void FixRHEOThermal::init() dth = 0.5 * update->dt; if (atom->esph_flag != 1) - error->all(FLERR,"fix rheo/thermal command requires atom property esph"); + error->all(FLERR, "fix rheo/thermal command requires atom property esph"); if (atom->temperature_flag != 1) - error->all(FLERR,"fix rheo/thermal command requires atom property temperature"); + error->all(FLERR, "fix rheo/thermal command requires atom property temperature"); if (atom->heatflow_flag != 1) - error->all(FLERR,"fix rheo/thermal command requires atom property heatflow"); + error->all(FLERR, "fix rheo/thermal command requires atom property heatflow"); if (atom->conductivity_flag != 1) - error->all(FLERR,"fix rheo/thermal command requires atom property conductivity"); + error->all(FLERR, "fix rheo/thermal command requires atom property conductivity"); if (cut_bond > 0.0) { - if (!force->bond) error->all(FLERR,"Must define a bond style to use reactive bond generation with fix rheo/thermal"); + if (!force->bond) error->all(FLERR, "Must define a bond style to use reactive bond generation with fix rheo/thermal"); if (!atom->avec->bonds_allow) error->all(FLERR, "Reactive bond generation in fix rheo/thermal requires atom bonds"); // all special weights must be 1.0 (no special neighbors) or there must be an instance of fix update/special/bonds @@ -561,7 +562,7 @@ void FixRHEOThermal::break_bonds() // Update special unless two owned atoms melt simultaneously then // only update for atom with lower tag if (fix_update_special_bonds) { - if (i < nlocal && j < nlocal && melti && meltj) { + if ((i < nlocal) && (j < nlocal) && melti && meltj) { if (tag[i] < tag[j]) { fix_update_special_bonds->add_broken_bond(i, j); } @@ -590,7 +591,7 @@ void FixRHEOThermal::break_bonds() // Delete bonds for non-melted local atoms (shifting) if (i < nlocal && !melti) { for (m = 0; m < num_bond[i]; m++) { - if (bond_atom[i][m] == tag[j] && bond_type[i][m] == btype) { + if ((bond_atom[i][m] == tag[j]) && (bond_type[i][m] == btype)) { nmax = num_bond[i] - 1; bond_type[i][m] = bond_type[i][nmax]; bond_atom[i][m] = bond_atom[i][nmax]; @@ -609,7 +610,7 @@ void FixRHEOThermal::break_bonds() if (j < nlocal && !meltj) { for (m = 0; m < num_bond[j]; m++) { - if (bond_atom[j][m] == tag[i] && bond_type[j][m] == btype) { + if ((bond_atom[j][m] == tag[i]) && (bond_type[j][m] == btype)) { nmax = num_bond[j] - 1; bond_type[j][m] = bond_type[j][nmax]; bond_atom[j][m] = bond_atom[j][nmax]; @@ -692,7 +693,7 @@ void FixRHEOThermal::create_bonds() // Add bonds to owned atoms // If newton bond off, add to both, otherwise add to whichever has a smaller tag - if (i < nlocal && (!newton_bond || tag[i] < tag[j])) { + if ((i < nlocal) && (!newton_bond || (tag[i] < tag[j]))) { if (num_bond[i] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); bond_type[i][num_bond[i]] = btype; @@ -700,7 +701,7 @@ void FixRHEOThermal::create_bonds() num_bond[i]++; } - if (j < nlocal && (!newton_bond || tag[j] < tag[i])) { + if ((j < nlocal) && (!newton_bond || (tag[j] < tag[i]))) { if (num_bond[j] == atom->bond_per_atom) error->one(FLERR,"New bond exceeded bonds per atom in fix rheo/thermal"); bond_type[j][num_bond[j]] = btype; diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 2d5d58d494..5cb1e7c4d0 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -46,6 +46,7 @@ FixRHEOViscosity::FixRHEOViscosity(LAMMPS *lmp, int narg, char **arg) : constant_flag = 0; evolve_flag = 0; + // Currently can only have one instance of fix rheo/viscosity if (igroup != 0) error->all(FLERR,"fix rheo/viscosity command requires group all"); diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index f206512950..731047201c 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -33,7 +33,6 @@ #include "modify.h" #include "neighbor.h" #include "neigh_list.h" -#include "update.h" #include "utils.h" #include @@ -81,7 +80,7 @@ void PairRHEO::compute(int eflag, int vflag) int pair_force_flag, pair_rho_flag, pair_avisc_flag; int fluidi, fluidj; double xtmp, ytmp, ztmp, w, wp, Ti, Tj, dT, csq_ave, cs_ave; - double rhoi, rhoj, rho0i, rho0j, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj, eta_ave, kappa_ave,dT_prefactor; + double rhoi, rhoj, rho0i, rho0j, voli, volj, Pi, Pj, etai, etaj, kappai, kappaj, eta_ave, kappa_ave, dT_prefactor; double mu, q, fp_prefactor, drho_damp, fmag, psi_ij, Fij; double *dWij, *dWji, *dW1ij, *dW1ji; double dx[3], du[3], dv[3], fv[3], dfp[3], fsolid[3], ft[3], vi[3], vj[3]; @@ -112,7 +111,6 @@ void PairRHEO::compute(int eflag, int vflag) int *type = atom->type; int *status = atom->status; tagint *tag = atom->tag; - double fnorm, ftang[3]; double **fp_store, *chi; if (compute_interface) { @@ -169,7 +167,7 @@ void PairRHEO::compute(int eflag, int vflag) rsq = lensq3(dx); jtype = type[j]; - if (rsq < hsq) { + if (rsq < cutksq) { r = sqrt(rsq); rinv = 1 / r; @@ -219,16 +217,16 @@ void PairRHEO::compute(int eflag, int vflag) rhoj = compute_interface->correct_rho(j, i); Pj = fix_pressure->calc_pressure(rhoj, jtype); - if ((chi[j] > 0.9) && (r < (h * 0.5))) - fmag = (chi[j] - 0.9) * (h * 0.5 - r) * rho0j * csq_ave * h * rinv; + if ((chi[j] > 0.9) && (r < (cutk * 0.5))) + fmag = (chi[j] - 0.9) * (cutk * 0.5 - r) * rho0j * csq_ave * cutk * rinv; } else if ((!fluidi) && fluidj) { compute_interface->correct_v(vi, vj, i, j); rhoi = compute_interface->correct_rho(i, j); Pi = fix_pressure->calc_pressure(rhoi, itype); - if (chi[i] > 0.9 && r < (h * 0.5)) - fmag = (chi[i] - 0.9) * (h * 0.5 - r) * rho0i * csq_ave * h * rinv; + if (chi[i] > 0.9 && r < (cutk * 0.5)) + fmag = (chi[i] - 0.9) * (cutk * 0.5 - r) * rho0i * csq_ave * cutk * rinv; } else if ((!fluidi) && (!fluidj)) { rhoi = rho0i; @@ -281,8 +279,8 @@ void PairRHEO::compute(int eflag, int vflag) for (b = 0; b < dim; b++) du[a] -= 0.5 * (gradv[i][a * dim + b] + gradv[j][a * dim + b]) * dx[b]; - mu = dot3(du, dx) * hinv3; - mu /= (rsq * hinv3 * hinv3 + EPSILON); + mu = dot3(du, dx) * cutkinv3; + mu /= (rsq * cutkinv3 * cutkinv3 + EPSILON); mu = MIN(0.0, mu); q = av * (-2.0 * cs_ave * mu + mu * mu); fp_prefactor += voli * volj * q * (rhoj + rhoi); @@ -406,17 +404,17 @@ void PairRHEO::settings(int narg, char **arg) { if (narg < 1) error->all(FLERR, "Illegal pair_style command"); - h = utils::numeric(FLERR, arg[0], false, lmp); + cutk = utils::numeric(FLERR, arg[0], false, lmp); int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg], "rho/damp") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_style command"); + if (iarg + 1 >= narg) utils::missing_cmd_args(FLERR, "pair rheo rho/damp", error); rho_damp_flag = 1; rho_damp = utils::numeric(FLERR, arg[iarg + 1], false, lmp); iarg++; } else if (strcmp(arg[iarg], "artificial/visc") == 0) { - if (iarg + 1 >= narg) error->all(FLERR, "Illegal pair_style command"); + if (iarg + 1 >= narg) utils::missing_cmd_args(FLERR, "pair rheo artificial/visc", error); artificial_visc_flag = 1; av = utils::numeric(FLERR, arg[iarg + 1], false, lmp); iarg++; @@ -477,12 +475,12 @@ void PairRHEO::setup() csq = fix_rheo->csq; rho0 = fix_rheo->rho0; - if (h != fix_rheo->h) - error->all(FLERR, "Pair rheo cutoff {} does not agree with fix rheo cutoff {}", h, fix_rheo->h); + if (cutk != fix_rheo->cut) + error->all(FLERR, "Pair rheo cutoff {} does not agree with fix rheo cutoff {}", cutk, fix_rheo->cut); - hsq = h * h; - hinv = 1.0 / h; - hinv3 = hinv * 3.0; + cutksq = cutk * cutk; + cutkinv = 1.0 / cutk; + cutkinv3 = cutkinv * 3.0; laplacian_order = -1; int n = atom->ntypes; @@ -512,7 +510,7 @@ double PairRHEO::init_one(int i, int j) if (setflag[i][j] == 0) error->all(FLERR, "All pair rheo coeffs are not set"); - return h; + return cutk; } /* ---------------------------------------------------------------------- */ diff --git a/src/RHEO/pair_rheo.h b/src/RHEO/pair_rheo.h index 7a47927962..eba3a70eea 100644 --- a/src/RHEO/pair_rheo.h +++ b/src/RHEO/pair_rheo.h @@ -37,8 +37,8 @@ class PairRHEO : public Pair { void unpack_reverse_comm(int, int *, double *) override; protected: - double h, *csq, *rho0; // From fix RHEO - double *cs, hsq, hinv, hinv3, av, rho_damp; + double cutk, *csq, *rho0; // From fix RHEO + double *cs, cutksq, cutkinv, cutkinv3, av, rho_damp; int laplacian_order; int artificial_visc_flag; From d5c90eebfd0b59c78b8588ab993dd2749f789e13 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Fri, 28 Jun 2024 17:27:13 -0600 Subject: [PATCH 133/385] Flipping doc reference name --- doc/src/bond_rheo_shell.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/bond_rheo_shell.rst b/doc/src/bond_rheo_shell.rst index 439f88ec8e..f83219b9f3 100644 --- a/doc/src/bond_rheo_shell.rst +++ b/doc/src/bond_rheo_shell.rst @@ -54,7 +54,7 @@ Before bonds are enabled, they are still treated as regular bonds by all other parts of LAMMPS. This means they are written to data files and counted in computes such as :doc:`nbond/atom `. To only count enabled bonds, use the *nbond/shell* attribute in -:doc:`compute property/atom/rheo `. +:doc:`compute rheo/property/atom `. When enabled, the bond then computes forces based on deviations from the initial reference state of the two atoms much like a BPM style From 246698d3c2b0c78a26a2e00a14004be4e8fb986e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 29 Jun 2024 03:43:26 -0400 Subject: [PATCH 134/385] Timer::_timeout should be double and it should be allowed to have fractions. --- src/timer.cpp | 6 +++--- src/timer.h | 12 ++++++------ src/utils.cpp | 2 +- unittest/utils/test_utils.cpp | 10 ++++++++++ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/timer.cpp b/src/timer.cpp index 288ac28f43..c6f6401799 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -28,8 +28,8 @@ Timer::Timer(LAMMPS *_lmp) : Pointers(_lmp) { _level = NORMAL; _sync = OFF; - _timeout = -1; - _s_timeout = -1; + _timeout = -1.0; + _s_timeout = -1.0; _checkfreq = 10; _nextcheck = -1; this->_stamp(RESET); @@ -251,7 +251,7 @@ void Timer::modify_params(int narg, char **arg) // format timeout setting std::string timeout = "off"; - if (_timeout >= 0) { + if (_timeout >= 0.0) { std::tm tv = fmt::gmtime((std::time_t) _timeout); timeout = fmt::format("{:02d}:{:%M:%S}", tv.tm_yday * 24 + tv.tm_hour, tv); } diff --git a/src/timer.h b/src/timer.h index f7efa5ac64..371a895d1f 100644 --- a/src/timer.h +++ b/src/timer.h @@ -110,12 +110,12 @@ class Timer : protected Pointers { double previous_cpu; double previous_wall; double timeout_start; - int _level; // level of detail: off=0,loop=1,normal=2,full=3 - int _sync; // if nonzero, synchronize tasks before setting the timer - int _timeout; // max allowed wall time in seconds. infinity if negative - int _s_timeout; // copy of timeout for restoring after a forced timeout - int _checkfreq; // frequency of timeout checking - int _nextcheck; // loop number of next timeout check + double _timeout; // max allowed wall time in seconds. infinity if negative + double _s_timeout; // copy of timeout for restoring after a forced timeout + int _level; // level of detail: off=0,loop=1,normal=2,full=3 + int _sync; // if nonzero, synchronize tasks before setting the timer + int _checkfreq; // frequency of timeout checking + int _nextcheck; // loop number of next timeout check // update one specific timer array void _stamp(enum ttype); diff --git a/src/utils.cpp b/src/utils.cpp index c760f9ffbf..87c46c47ab 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1677,7 +1677,7 @@ double utils::timespec2seconds(const std::string ×pec) try { for (i = 0; i < 3; i++) { if (!values.has_next()) break; - vals[i] = values.next_int(); + vals[i] = values.next_double(); } } catch (TokenizerException &) { return -1.0; diff --git a/unittest/utils/test_utils.cpp b/unittest/utils/test_utils.cpp index 58940f6600..c486d0cf3e 100644 --- a/unittest/utils/test_utils.cpp +++ b/unittest/utils/test_utils.cpp @@ -1061,6 +1061,16 @@ TEST(Utils, timespec2seconds_hhmmss) ASSERT_DOUBLE_EQ(utils::timespec2seconds("2:10:45"), 7845.0); } +TEST(Utils, timespec2seconds_ssfraction) +{ + ASSERT_DOUBLE_EQ(utils::timespec2seconds("5.2"), 5.2); +} + +TEST(Utils, timespec2seconds_mmfraction) +{ + ASSERT_DOUBLE_EQ(utils::timespec2seconds("2.5:10"), 160.0); +} + TEST(Utils, timespec2seconds_invalid) { ASSERT_DOUBLE_EQ(utils::timespec2seconds("2:aa:45"), -1.0); From 6ad01457097f06ea4c6d98e8c00f821b36479dd3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 29 Jun 2024 04:02:33 -0400 Subject: [PATCH 135/385] new special variable function is_timeout() --- doc/src/variable.rst | 18 ++++++++++++++++-- src/variable.cpp | 23 ++++++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/doc/src/variable.rst b/doc/src/variable.rst index d19f256451..330e44139e 100644 --- a/doc/src/variable.rst +++ b/doc/src/variable.rst @@ -67,7 +67,7 @@ Syntax bound(group,dir,region), gyration(group,region), ke(group,reigon), angmom(group,dim,region), torque(group,dim,region), inertia(group,dimdim,region), omega(group,dim,region) - special functions = sum(x), min(x), max(x), ave(x), trap(x), slope(x), sort(x), rsort(x), gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name), extract_setting(name), label2type(kind,label), is_typelabel(kind,label) + special functions = sum(x), min(x), max(x), ave(x), trap(x), slope(x), sort(x), rsort(x), gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name), extract_setting(name), label2type(kind,label), is_typelabel(kind,label), is_timeout() feature functions = is_available(category,feature), is_active(category,feature), is_defined(category,id) atom value = id[i], mass[i], type[i], mol[i], x[i], y[i], z[i], vx[i], vy[i], vz[i], fx[i], fy[i], fz[i], q[i] atom vector = id, mass, type, mol, radius, q, x, y, z, vx, vy, vz, fx, fy, fz @@ -547,7 +547,7 @@ variables. +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Region functions | count(ID,IDR), mass(ID,IDR), charge(ID,IDR), xcm(ID,dim,IDR), vcm(ID,dim,IDR), fcm(ID,dim,IDR), bound(ID,dir,IDR), gyration(ID,IDR), ke(ID,IDR), angmom(ID,dim,IDR), torque(ID,dim,IDR), inertia(ID,dimdim,IDR), omega(ID,dim,IDR) | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Special functions | sum(x), min(x), max(x), ave(x), trap(x), slope(x), sort(x), rsort(x), gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name), extract_setting(name), label2type(kind,label), is_typelabel(kind,label) | +| Special functions | sum(x), min(x), max(x), ave(x), trap(x), slope(x), sort(x), rsort(x), gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name), extract_setting(name), label2type(kind,label), is_typelabel(kind,label), is_timeout() | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Feature functions | is_available(category,feature), is_active(category,feature), is_defined(category,id) | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -1042,6 +1042,20 @@ label2type(), but returns 1 if the type label has been assigned, otherwise it returns 0. This function can be used to check if a particular type label already exists in the simulation. +.. versionadded:: TBD + +The is_timeout() function returns 1 when the :doc:`timer timeout +` has expired otherwise it returns 0. This function can be used +to check inputs in combination with the :doc:`if command ` to +execute commands after the timer has expired. Example: + +.. code-block:: LAMMPS + + variable timeout equal is_timeout() + timer timeout 0:10:00 every 10 + run 10000 + if ${timeout} then "print 'Timer has expired'" + ---------- Feature Functions diff --git a/src/variable.cpp b/src/variable.cpp index f381eecde6..823a68a506 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -34,6 +34,7 @@ #include "random_mars.h" #include "region.h" #include "thermo.h" +#include "timer.h" #include "tokenizer.h" #include "universe.h" #include "update.h" @@ -4276,8 +4277,9 @@ Region *Variable::region_function(char *id, int ivar) return 0 if not a match, 1 if successfully processed customize by adding a special function: sum(x),min(x),max(x),ave(x),trap(x),slope(x), - gmask(x),rmask(x),grmask(x,y),next(x),is_file(x),is_ox(x), - extract_setting(x),label2type(x,y),is_typelabel(x,y) + gmask(x),rmask(x),grmask(x,y),next(x),is_file(x),is_os(x), + extract_setting(x),label2type(x,y),is_tpelabel(x,y) + is_timeout() ------------------------------------------------------------------------- */ // to simplify finding matches and assigning constants for functions operating on vectors @@ -4286,7 +4288,7 @@ static const std::unordered_map special_function_map = { {"sum", SUM}, {"min", XMIN}, {"max", XMAX}, {"ave", AVE}, {"trap", TRAP}, {"slope", SLOPE}, {"sort", SORT}, {"rsort", RSORT}, {"gmask", NOVECTOR}, {"rmask", NOVECTOR}, {"grmask", NOVECTOR}, {"next", NOVECTOR}, {"is_file", NOVECTOR}, {"is_os", NOVECTOR}, {"extract_setting", NOVECTOR}, - {"label2type", NOVECTOR}, {"is_typelabel", NOVECTOR} }; + {"label2type", NOVECTOR}, {"is_typelabel", NOVECTOR}, {"is_timeout", NOVECTOR} }; int Variable::special_function(const std::string &word, char *contents, Tree **tree, Tree **treestack, int &ntreestack, double *argstack, @@ -4765,6 +4767,21 @@ int Variable::special_function(const std::string &word, char *contents, Tree **t newtree->value = value; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; + + } else if (word == "is_timeout") { + if ((narg != 1) || (std::string(args[0]).size() != 0)) + print_var_error(FLERR,"Invalid is_timeout() function in variable formula",ivar); + value = timer->is_timeout() ? 1.0 : 0.0; + + // save value in tree or on argstack + + if (tree) { + auto newtree = new Tree(); + newtree->type = VALUE; + newtree->value = value; + treestack[ntreestack++] = newtree; + } else argstack[nargstack++] = value; + } // delete stored args From f8a7fc787ccd949e5f0342a9b3070c2e254cd8b3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 29 Jun 2024 21:32:37 -0400 Subject: [PATCH 136/385] correct documentation and simplify extracting vector length --- src/library.cpp | 31 ++++++++++++++++++++----------- src/library.h | 6 +++--- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/library.cpp b/src/library.cpp index a289353075..bb58762563 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -2420,7 +2420,7 @@ use to avoid a memory leak. Example: .. code-block:: c - double *dptr = (double *) lammps_extract_variable(handle,name,NULL); + double *dptr = (double *) lammps_extract_variable(handle, name, NULL); double value = *dptr; lammps_free((void *)dptr); @@ -2431,16 +2431,25 @@ content will not be updated in case the variable is re-evaluated. To avoid a memory leak, this pointer needs to be freed after use in the calling program. -For *vector*\ -style variables, the returned pointer is to actual LAMMPS data. -The pointer should not be deallocated. Its length depends on the variable, -compute, or fix data used to construct the *vector*\ -style variable. -This length can be fetched by calling this function with *group* set to the -constant "LMP_SIZE_VECTOR", which returns a ``void *`` pointer that can be -dereferenced to an integer that is the length of the vector. This pointer -needs to be deallocated when finished with it to avoid memory leaks. +For *vector*\ -style variables, the returned pointer points to actual +LAMMPS data and thus it should **not** be deallocated. Its length +depends on the variable, compute, or fix data used to construct the +*vector*\ -style variable. This length can be fetched by calling this +function with *group* set to a non-NULL pointer (NULL returns the vector). +In that case it will return the vector length as an allocated int +pointer cast to a ``void *`` pointer. That pointer can be recast and +dereferenced to an integer yielding the length of the vector. This pointer +must be deallocated when finished with it to avoid memory leaks. Example: + +.. code-block:: c + + double *vectvals = (double *) lammps_extract_variable(handle, name, NULL); + int *intptr = (int *) lammps_extract_variable(handle, name, 1); + int vectlen = *intptr; + lammps_free((void *)intptr); For other variable styles the returned pointer needs to be cast to -a char pointer. It should not be deallocated. +a char pointer and it should **not** be deallocated. Example: .. code-block:: c @@ -2452,7 +2461,7 @@ a char pointer. It should not be deallocated. LAMMPS cannot easily check if it is valid to access the data referenced by the variables (e.g., computes, fixes, or thermodynamic info), so it may fail with an error. The caller has to make certain - that the data are extracted only when it safe to evaluate the variable + that the data is extracted only when it safe to evaluate the variable and thus an error or crash are avoided. \endverbatim @@ -2487,7 +2496,7 @@ void *lammps_extract_variable(void *handle, const char *name, const char *group) } else if (lmp->input->variable->vectorstyle(ivar)) { double *values = nullptr; int nvector = lmp->input->variable->compute_vector(ivar, &values); - if (group != nullptr && strcmp(group,"LMP_SIZE_VECTOR") == 0) { + if (group) { int* nvecptr = (int *) malloc(sizeof(int)); *nvecptr = nvector; return (void *) nvecptr; diff --git a/src/library.h b/src/library.h index 0e579de2e9..fa4a3bd0a5 100644 --- a/src/library.h +++ b/src/library.h @@ -175,9 +175,9 @@ void *lammps_extract_atom(void *handle, const char *name); * Library functions to access data from computes, fixes, variables in LAMMPS * ---------------------------------------------------------------------- */ -void *lammps_extract_compute(void *handle, const char *, int, int); -void *lammps_extract_fix(void *handle, const char *, int, int, int, int); -void *lammps_extract_variable(void *handle, const char *, const char *); +void *lammps_extract_compute(void *handle, const char *id, int style, int type); +void *lammps_extract_fix(void *handle, const char *id, int style, int type, int nrow, int ncol); +void *lammps_extract_variable(void *handle, const char *name, const char *group); int lammps_extract_variable_datatype(void *handle, const char *name); int lammps_set_variable(void *handle, const char *name, const char *str); int lammps_set_string_variable(void *handle, const char *name, const char *str); From d75e66dc7155e3f46316145d621b0a8fc5a99da2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 30 Jun 2024 18:32:37 -0400 Subject: [PATCH 137/385] add unit tests for lammps_extract_variable() --- unittest/c-library/CMakeLists.txt | 6 + unittest/c-library/test_library_objects.cpp | 215 ++++++++++++++++++++ unittest/commands/test_variables.cpp | 1 + 3 files changed, 222 insertions(+) create mode 100644 unittest/c-library/test_library_objects.cpp diff --git a/unittest/c-library/CMakeLists.txt b/unittest/c-library/CMakeLists.txt index 0ab216caf5..f5793a804e 100644 --- a/unittest/c-library/CMakeLists.txt +++ b/unittest/c-library/CMakeLists.txt @@ -18,6 +18,12 @@ target_compile_definitions(test_library_properties PRIVATE -DTEST_INPUT_FOLDER=$ add_test(NAME LibraryProperties COMMAND test_library_properties) set_tests_properties(LibraryProperties PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") +add_executable(test_library_objects test_library_objects.cpp test_main.cpp) +target_link_libraries(test_library_objects PRIVATE lammps GTest::GMock) +target_compile_definitions(test_library_objects PRIVATE -DTEST_INPUT_FOLDER=${CMAKE_CURRENT_SOURCE_DIR}) +add_test(NAME LibraryObjects COMMAND test_library_objects) +set_tests_properties(LibraryObjects PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") + add_executable(test_library_scatter_gather test_library_scatter_gather.cpp test_main.cpp) target_link_libraries(test_library_scatter_gather PRIVATE lammps GTest::GMock) target_compile_definitions(test_library_scatter_gather PRIVATE -DTEST_INPUT_FOLDER=${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/unittest/c-library/test_library_objects.cpp b/unittest/c-library/test_library_objects.cpp new file mode 100644 index 0000000000..a07872c16f --- /dev/null +++ b/unittest/c-library/test_library_objects.cpp @@ -0,0 +1,215 @@ +// unit tests for checking and changing simulation properties through the library interface + +#include "library.h" + +#include "atom.h" +#include "input.h" +#include "lammps.h" +#include "lmptype.h" +#include "platform.h" +#include "variable.h" + +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "test_main.h" + +#define STRINGIFY(val) XSTR(val) +#define XSTR(val) #val + +using ::LAMMPS_NS::Atom; +using ::LAMMPS_NS::bigint; +using ::LAMMPS_NS::Input; +using ::LAMMPS_NS::tagint; +using ::LAMMPS_NS::Variable; +using ::testing::HasSubstr; +using ::testing::StartsWith; +using ::testing::StrEq; + +class LibraryObjects : public ::testing::Test { +protected: + void *lmp; + Variable *variable; + std::string INPUT_DIR = STRINGIFY(TEST_INPUT_FOLDER); + + LibraryObjects() = default; + ~LibraryObjects() override = default; + + void SetUp() override + { + const char *args[] = {"LAMMPS_test", "-log", "none", + "-echo", "screen", "-nocite", + "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER), + nullptr}; + + char **argv = (char **)args; + int argc = (sizeof(args) / sizeof(char *)) - 1; + + ::testing::internal::CaptureStdout(); + lmp = lammps_open_no_mpi(argc, argv, nullptr); + variable = ((LAMMPS_NS::LAMMPS *)lmp)->input->variable; + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + EXPECT_THAT(output, StartsWith("LAMMPS (")); + } + + void TearDown() override + { + ::testing::internal::CaptureStdout(); + lammps_close(lmp); + std::string output = ::testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; + lmp = nullptr; + } +}; + +TEST_F(LibraryObjects, variables) +{ + FILE *fp = fopen("test_variable.file", "w"); + fputs("# test file for file style variable\n\n\none\n two \n\n" + "three # with comment\nfour ! with non-comment\n" + "# comments only\n five\n#END\n", + fp); + fclose(fp); + + ::testing::internal::CaptureStdout(); + lammps_command(lmp, "region box block 0 2 0 2 0 2"); + lammps_command(lmp, "create_box 1 box"); + lammps_command(lmp, "mass 1 3.0"); + lammps_command(lmp, "create_atoms 1 single 1.0 1.0 1.5"); + lammps_command(lmp, "create_atoms 1 single 0.2 0.1 0.1"); + lammps_command(lmp, "shell putenv TEST_VARIABLE=simpletest2"); + lammps_command(lmp, "shell putenv TEST_VARIABLE2=simpletest OTHER_VARIABLE=2"); + lammps_command(lmp, "variable one index 1 2 3 4"); + lammps_command(lmp, "variable two equal 1"); + lammps_command(lmp, "variable two equal 2"); + lammps_command(lmp, "variable three string four"); + lammps_command(lmp, "variable three string three"); + lammps_command(lmp, "variable four1 loop 4"); + lammps_command(lmp, "variable four2 loop 2 4"); + lammps_command(lmp, "variable five1 loop 100 pad"); + lammps_command(lmp, "variable five2 loop 10 200 pad"); + lammps_command(lmp, "variable six world one"); + lammps_command(lmp, "variable seven format two \"%5.2f\""); + lammps_command(lmp, "variable eight getenv TEST_VARIABLE2"); + lammps_command(lmp, "variable eight getenv XXX"); + lammps_command(lmp, "variable nine file test_variable.file"); + lammps_command(lmp, "variable ten internal 1.0"); + lammps_command(lmp, "variable ten internal 10.0"); + lammps_command(lmp, "variable ten1 universe 1 2 3 4"); + lammps_command(lmp, "variable ten2 uloop 4"); + lammps_command(lmp, "variable ten3 uloop 4 pad"); + lammps_command(lmp, "variable ten4 vector [0,1,2,3,5,7,11]"); + lammps_command(lmp, "variable ten5 vector [0.5,1.25]"); + lammps_command(lmp, "variable dummy index 0"); + lammps_command(lmp, "variable file equal is_file(MYFILE)"); + lammps_command(lmp, "variable iswin equal is_os(^Windows)"); + lammps_command(lmp, "variable islin equal is_os(^Linux)"); + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "unknown"), -1); + void *ptr = lammps_extract_variable(lmp, "unknown", NULL); + EXPECT_EQ(ptr, nullptr); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "one"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "one", NULL); + EXPECT_NE(ptr, nullptr); + EXPECT_THAT((char *)ptr, StrEq("1")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "two"), LMP_VAR_EQUAL); + ptr = lammps_extract_variable(lmp, "two", NULL); + EXPECT_NE(ptr, nullptr); + EXPECT_THAT(*(double *)ptr, 2.0); + lammps_free(ptr); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "three"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "three", NULL); + EXPECT_THAT((char *)ptr, StrEq("three")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "four1"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "four1", NULL); + EXPECT_THAT((char *)ptr, StrEq("1")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "four2"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "four2", NULL); + EXPECT_THAT((char *)ptr, StrEq("2")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "five1"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "five1", NULL); + EXPECT_THAT((char *)ptr, StrEq("001")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "five2"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "five2", NULL); + EXPECT_THAT((char *)ptr, StrEq("010")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "six"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "six", NULL); + EXPECT_THAT((char *)ptr, StrEq("one")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "seven"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "seven", NULL); + EXPECT_THAT((char *)ptr, StrEq(" 2.00")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "eight"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "eight", NULL); + EXPECT_THAT((char *)ptr, StrEq("")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "nine"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "nine", NULL); + EXPECT_THAT((char *)ptr, StrEq("one")); + + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten"), LMP_VAR_EQUAL); + ptr = lammps_extract_variable(lmp, "ten", NULL); + EXPECT_THAT(*(double *)ptr, 1.0); + lammps_free(ptr); + variable->internal_set(variable->find("ten"), 2.5); + ptr = lammps_extract_variable(lmp, "ten", NULL); + EXPECT_THAT(*(double *)ptr, 2.5); + lammps_free(ptr); + + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten1"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "ten1", NULL); + EXPECT_THAT((char *)ptr, StrEq("1")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten2"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "ten2", NULL); + EXPECT_THAT((char *)ptr, StrEq("1")); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten3"), LMP_VAR_STRING); + ptr = lammps_extract_variable(lmp, "ten3", NULL); + EXPECT_THAT((char *)ptr, StrEq("1")); + + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten4"), LMP_VAR_VECTOR); + ptr = lammps_extract_variable(lmp, "ten4", (const char *)1); + double *dptr = (double *)lammps_extract_variable(lmp, "ten4", NULL); + EXPECT_EQ((*(int *)ptr), 7); + lammps_free(ptr); + EXPECT_EQ(dptr[0], 0); + EXPECT_EQ(dptr[4], 5); + EXPECT_EQ(dptr[6], 11); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten5"), LMP_VAR_VECTOR); + ptr = lammps_extract_variable(lmp, "ten5", (const char *)1); + dptr = (double *)lammps_extract_variable(lmp, "ten5", NULL); + EXPECT_EQ((*(int *)ptr), 2); + lammps_free(ptr); + EXPECT_EQ(dptr[0], 0.5); + EXPECT_EQ(dptr[1], 1.25); + + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "iswin"), LMP_VAR_EQUAL); + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "islin"), LMP_VAR_EQUAL); +#if defined(_WIN32) + ptr = lammps_extract_variable(lmp, "iswin", NULL); + EXPECT_THAT(*(double *)ptr, 1.0); + lammps_free(ptr); + ptr = lammps_extract_variable(lmp, "islin", NULL); + EXPECT_THAT(*(double *)ptr, 0.0); + lammps_free(ptr); +#elif defined(__linux__) + ptr = lammps_extract_variable(lmp, "iswin", NULL); + EXPECT_THAT(*(double *)ptr, 0.0); + lammps_free(ptr); + ptr = lammps_extract_variable(lmp, "islin", NULL); + EXPECT_THAT(*(double *)ptr, 1.0); + lammps_free(ptr); +#else + ptr = lammps_extract_variable(lmp, "iswin", NULL); + EXPECT_THAT(*(double *)ptr, 0.0); + lammps_free(ptr); + ptr = lammps_extract_variable(lmp, "islin", NULL); + EXPECT_THAT(*(double *)ptr, 0.0); + lammps_free(ptr); +#endif + + LAMMPS_NS::platform::unlink("test_variable.file"); +} diff --git a/unittest/commands/test_variables.cpp b/unittest/commands/test_variables.cpp index 1aa13ecf49..1826263dea 100644 --- a/unittest/commands/test_variables.cpp +++ b/unittest/commands/test_variables.cpp @@ -157,6 +157,7 @@ TEST_F(VariableTest, CreateDelete) ASSERT_THAT(variable->retrieve("three"), StrEq("four")); ASSERT_THAT(variable->retrieve("four2"), StrEq("2")); ASSERT_THAT(variable->retrieve("five1"), StrEq("001")); + ASSERT_THAT(variable->retrieve("five2"), StrEq("010")); ASSERT_THAT(variable->retrieve("seven"), StrEq(" 2.00")); ASSERT_THAT(variable->retrieve("ten"), StrEq("1")); ASSERT_THAT(variable->retrieve("eight"), StrEq("")); From dc07a75011cd5a69995a19edde632a016b136fc2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 30 Jun 2024 18:36:18 -0400 Subject: [PATCH 138/385] whitespace --- unittest/c-library/test_library_objects.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unittest/c-library/test_library_objects.cpp b/unittest/c-library/test_library_objects.cpp index a07872c16f..d224c76225 100644 --- a/unittest/c-library/test_library_objects.cpp +++ b/unittest/c-library/test_library_objects.cpp @@ -71,7 +71,7 @@ TEST_F(LibraryObjects, variables) FILE *fp = fopen("test_variable.file", "w"); fputs("# test file for file style variable\n\n\none\n two \n\n" "three # with comment\nfour ! with non-comment\n" - "# comments only\n five\n#END\n", + "# comments only\n five\n#END\n", fp); fclose(fp); @@ -169,7 +169,7 @@ TEST_F(LibraryObjects, variables) EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten3"), LMP_VAR_STRING); ptr = lammps_extract_variable(lmp, "ten3", NULL); EXPECT_THAT((char *)ptr, StrEq("1")); - + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten4"), LMP_VAR_VECTOR); ptr = lammps_extract_variable(lmp, "ten4", (const char *)1); double *dptr = (double *)lammps_extract_variable(lmp, "ten4", NULL); @@ -185,7 +185,7 @@ TEST_F(LibraryObjects, variables) lammps_free(ptr); EXPECT_EQ(dptr[0], 0.5); EXPECT_EQ(dptr[1], 1.25); - + EXPECT_EQ(lammps_extract_variable_datatype(lmp, "iswin"), LMP_VAR_EQUAL); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "islin"), LMP_VAR_EQUAL); #if defined(_WIN32) From 49c84dbe1eb9f57c422f7d0e177df6031ba0d22e Mon Sep 17 00:00:00 2001 From: Ludwig Ahrens-Iwers Date: Mon, 1 Jul 2024 10:05:28 +0200 Subject: [PATCH 139/385] Bugfix virial with fix electrode --- .../PACKAGES/electrode/madelung/.gitignore | 1 + examples/PACKAGES/electrode/madelung/eval.py | 18 +++- .../PACKAGES/electrode/madelung/plate_cap.py | 98 +++++++++++++++-- .../PACKAGES/electrode/madelung/settings.mod | 6 +- src/ELECTRODE/fix_electrode_conp.cpp | 100 +++++++++++++++--- src/ELECTRODE/fix_electrode_conp.h | 3 +- 6 files changed, 197 insertions(+), 29 deletions(-) diff --git a/examples/PACKAGES/electrode/madelung/.gitignore b/examples/PACKAGES/electrode/madelung/.gitignore index 89d8d1a065..f222840fd6 100644 --- a/examples/PACKAGES/electrode/madelung/.gitignore +++ b/examples/PACKAGES/electrode/madelung/.gitignore @@ -1,2 +1,3 @@ *.csv *.txt +*.lammpstrj diff --git a/examples/PACKAGES/electrode/madelung/eval.py b/examples/PACKAGES/electrode/madelung/eval.py index feda0e384e..8f3675a741 100644 --- a/examples/PACKAGES/electrode/madelung/eval.py +++ b/examples/PACKAGES/electrode/madelung/eval.py @@ -17,14 +17,22 @@ q_ref = float(ref_line[3]) inv11_ref = float(ref_line[4]) inv12_ref = float(ref_line[5]) b1_ref = float(ref_line[6]) +felec1_ref = float(ref_line[8]) +felyt1_ref = float(ref_line[10]) +press_ref = float(ref_line[12]) # out.csv with open(sys.argv[2]) as f: out_line = f.readlines()[-1].split(", ") e_out = float(out_line[0]) q_out = float(out_line[1]) +press_out = float(out_line[2]) -out_lines = [("energy", e_ref, e_out), ("charge", q_ref, q_out)] +out_lines = [ + ("energy", e_ref, e_out), + ("charge", q_ref, q_out), + ("pressure", press_ref, press_out), +] # vec.csv vec_file = "vec.csv" @@ -44,6 +52,14 @@ if op.isfile(inv_file): inv12_out = float(inv_line[1]) out_lines.append(("inv11", inv11_ref, inv11_out)) +# forces.lammpstrj +force_file = "forces.lammpstrj" +with open(force_file) as f: + lines = f.readlines()[9:] + for name, i, f_ref in [("felec1", "1", felec1_ref), ("felyt1", "3", felyt1_ref)]: + f_out = next(float(y[3]) for x in lines if (y := x.split()) and y[0] == i) + out_lines.append((name, f_ref, f_out)) + lines = [] for label, ref, out in out_lines: error = rel_error(out, ref) diff --git a/examples/PACKAGES/electrode/madelung/plate_cap.py b/examples/PACKAGES/electrode/madelung/plate_cap.py index fcca166869..37aad47f51 100755 --- a/examples/PACKAGES/electrode/madelung/plate_cap.py +++ b/examples/PACKAGES/electrode/madelung/plate_cap.py @@ -1,12 +1,17 @@ #!/usr/bin/env python3 +import time + import numpy as np from scipy.special import erf SQRT2 = np.sqrt(2) +SQRTPI_INV = 1 / np.sqrt(np.pi) COULOMB = 332.06371 # Coulomb constant in Lammps 'real' units QE2F = 23.060549 +NKTV2P = 68568.415 # pressure in 'real' units LENGTH = 10000 # convergence parameter +LZ = 20 def lattice(length): @@ -26,6 +31,25 @@ def b_element(r, q, eta): return q * erf(eta * r) / r +def force_gauss(r, qq, eta): + etar = eta * r + return (qq / np.square(r)) * ( + erf(etar) - 2 * etar * SQRTPI_INV * np.exp(-np.square(etar)) + ) + + +def force_point(r, qq): + return qq / np.square(r) + + +def force_component(dx, d, qq, eta=None): + if eta: + return np.sum(dx / d * force_gauss(d, qq, eta)) + else: + return np.sum(dx / d * force_point(d, qq)) + + +time_start = time.perf_counter() a = 1 # nearest neighbor distance i.e. lattice constant / sqrt(2) x_elec = [-2, 2] x_elyt = [-1, 1] @@ -36,8 +60,20 @@ v = np.array([-0.5, 0.5]) * (QE2F / COULOMB) # distances to images within electrode and to opposite electrode distances = a * np.linalg.norm(lattice(LENGTH), axis=1) opposite_distances = np.sqrt(np.square(distances) + distance_plates**2) +image_distances = [] +for x in x_elec: + image_distances.append([]) + for y in x_elyt: + image_distances[-1].append(np.sqrt(np.square(distances) + np.abs(y - x) ** 2)) +image_elyt_distances = [[None for _ in range(len(x_elyt))] for _ in range(len(x_elyt))] +for i, (xi, qi) in enumerate(zip(x_elyt, q_elyt)): + for j, (xj, qj) in list(enumerate(zip(x_elyt, q_elyt)))[i + 1 :]: + image_elyt_distances[i][j] = np.sqrt( + np.square(distances) + np.abs(xj - xi) ** 2 + ) for name, eta_elec in [("", [2.0, 2.0]), ("_eta_mix", [0.5, 3.0])]: + # for name, eta_elec in [("", [2.0, 2.0])]: eta_mix = np.prod(eta_elec) / np.sqrt(np.sum(np.square(eta_elec))) # self interaction and within original box A_11 = np.sqrt(2 / np.pi) * eta_elec[0] @@ -55,22 +91,18 @@ for name, eta_elec in [("", [2.0, 2.0]), ("_eta_mix", [0.5, 3.0])]: # electrode-electrolyte interaction b = [] - for x, eta in zip(x_elec, eta_elec): + for i, (x, eta) in enumerate(zip(x_elec, eta_elec)): bi = 0 - for y, q in zip(x_elyt, q_elyt): - d = abs(y - x) - bi += b_element(d, q, eta) - image_distances = np.sqrt(np.square(distances) + d**2) - bi += 4 * np.sum(b_element(image_distances, q, eta)) + for j, (y, q) in enumerate(zip(x_elyt, q_elyt)): + bi += b_element(np.abs(y - x), q, eta) + bi += 4 * np.sum(b_element(image_distances[i][j], q, eta)) b.append(bi) b = np.array(b) # electrolyte-electrolyte energy elyt_11 = 4 * np.sum(1 / distances) distance_elyt = x_elyt[1] - x_elyt[0] - elyt_12 = 1 / distance_elyt + 4 * np.sum( - 1 / np.sqrt(np.square(distances) + distance_elyt**2) - ) + elyt_12 = 1 / distance_elyt + 4 * np.sum(1 / image_elyt_distances[0][1]) elyt = np.array([[elyt_11, elyt_12], [elyt_12, elyt_11]]) energy_elyt = 0.5 * np.dot(q_elyt, np.dot(elyt, q_elyt)) @@ -78,9 +110,48 @@ for name, eta_elec in [("", [2.0, 2.0]), ("_eta_mix", [0.5, 3.0])]: q = np.dot(inv, v - b) energy = COULOMB * (0.5 * np.dot(q, np.dot(A, q)) + np.dot(b, q) + energy_elyt) + # forces in out-of-plane direction + f_elec = np.zeros(len(x_elec)) + f_elyt = np.zeros(len(x_elyt)) + # electrode-electrode + dx = x_elec[1] - x_elec[0] + fij_box = force_component(dx, np.abs(dx), q[0] * q[1], eta_mix) + fij_img = 4 * force_component(dx, opposite_distances, q[0] * q[1], eta_mix) + f_elec[0] -= fij_box + fij_img + f_elec[1] += fij_box + fij_img + # electrode-electrolyte + for i, (xi, qi, etai) in enumerate(zip(x_elec, q, eta_elec)): + for j, (xj, qj) in enumerate(zip(x_elyt, q_elyt)): + dx = xj - xi + fij_box = force_component(dx, np.abs(dx), qi * qj, etai) + fij_img = 4 * force_component(dx, image_distances[i][j], qi * qj, etai) + f_elec[i] -= fij_box + fij_img + f_elyt[j] += fij_box + fij_img + # electrolyte-electrolyte + for i, (xi, qi) in enumerate(zip(x_elyt, q_elyt)): + for j, (xj, qj) in list(enumerate(zip(x_elyt, q_elyt)))[i + 1 :]: + dx = xj - xi + fij_box = force_component(dx, np.abs(dx), qi * qj) + fij_img = 4 * force_component(dx, image_elyt_distances[i][j], qi * qj) + f_elyt[i] -= fij_img + fij_box + f_elyt[j] += fij_img + fij_box + # force units + assert np.abs(np.sum(f_elec) + np.sum(f_elyt)) < 1e-8 + f_elec *= COULOMB + f_elyt *= COULOMB + + # Virial + volume = a**2 * LZ + virial = 0.0 + for x, f in [(x_elec, f_elec), (x_elyt, f_elyt)]: + virial += np.dot(x, f) + pressure = NKTV2P * virial / volume + with open(f"plate_cap{name}.csv", "w") as f: f.write( - "length, energy / kcal/mol, q1 / e, q2 / e, inv11 / A, inv12 / A, b1 / e/A, b2 / e/A\n" + "length, energy / kcal/mol, q1 / e, q2 / e, inv11 / A, inv12 / A" + + ", b1 / e/A, b2 / e/A, felec1 / kcal/mol/A, felec2 / kcal/mol/A" + + ", felyt1 / kcal/mol/A, felyt2 / kcal/mol/A, press\n" ) f.write( ", ".join( @@ -93,7 +164,14 @@ for name, eta_elec in [("", [2.0, 2.0]), ("_eta_mix", [0.5, 3.0])]: f"{inv[0, 1]:.10f}", f"{b[0]:.8f}", f"{b[1]:.8f}", + f"{f_elec[0]:.5f}", + f"{f_elec[1]:.5f}", + f"{f_elyt[0]:.5f}", + f"{f_elyt[1]:.5f}", + f"{pressure:.2f}", ] ) + "\n" ) +time_end = time.perf_counter() +print(f"{time_end - time_start:0.4f} seconds") diff --git a/examples/PACKAGES/electrode/madelung/settings.mod b/examples/PACKAGES/electrode/madelung/settings.mod index aa1096ea81..bb5c8e42ae 100644 --- a/examples/PACKAGES/electrode/madelung/settings.mod +++ b/examples/PACKAGES/electrode/madelung/settings.mod @@ -19,4 +19,8 @@ compute qtop top reduce sum v_q compute compute_pe all pe variable vpe equal c_compute_pe variable charge equal c_qtop -fix fxprint all print 1 "${vpe}, ${charge}" file "out.csv" +compute press all pressure NULL virial +variable p3 equal c_press[3] +fix fxprint all print 1 "${vpe}, ${charge}, ${p3}" file "out.csv" + +dump dump_forces all custom 1 forces.lammpstrj id fx fy fz diff --git a/src/ELECTRODE/fix_electrode_conp.cpp b/src/ELECTRODE/fix_electrode_conp.cpp index a4b9d5b3b9..aaa7f2fb99 100644 --- a/src/ELECTRODE/fix_electrode_conp.cpp +++ b/src/ELECTRODE/fix_electrode_conp.cpp @@ -89,6 +89,9 @@ FixElectrodeConp::FixElectrodeConp(LAMMPS *lmp, int narg, char **arg) : extvector = 0; extarray = 0; + virial_global_flag = 1; // use virials of this fix + thermo_virial = 1; // set vflags for v_tally + bool default_algo = true; algo = Algo::MATRIX_INV; matrix_algo = true; @@ -642,13 +645,15 @@ void FixElectrodeConp::setup_post_neighbor() /* ---------------------------------------------------------------------- */ -void FixElectrodeConp::setup_pre_reverse(int eflag, int /*vflag*/) +void FixElectrodeConp::setup_pre_reverse(int eflag, int vflag) { + if (pair->did_tally_callback()) + error->warning(FLERR, + "Computation of Virials in fix electrode is incompatible with TALLY package"); // correct forces for initial timestep - gausscorr(eflag, true); + ev_init(eflag, vflag); + gausscorr(eflag, vflag, true); self_energy(eflag); - // potential_energy(eflag); // not always part of the energy, depending on ensemble, therefore - // removed } /* ---------------------------------------------------------------------- */ @@ -775,12 +780,11 @@ void FixElectrodeConp::pre_force(int) /* ---------------------------------------------------------------------- */ -void FixElectrodeConp::pre_reverse(int eflag, int /*vflag*/) +void FixElectrodeConp::pre_reverse(int eflag, int vflag) { - gausscorr(eflag, true); + ev_init(eflag, vflag); + gausscorr(eflag, vflag, true); self_energy(eflag); - //potential_energy(eflag); // not always part of the energy, depending on ensemble, therefore - // removed } /* ---------------------------------------------------------------------- */ @@ -1228,11 +1232,10 @@ double FixElectrodeConp::self_energy(int eflag) /* ---------------------------------------------------------------------- */ -double FixElectrodeConp::gausscorr(int eflag, bool fflag) +double FixElectrodeConp::gausscorr(int eflag, int vflag, bool fflag) { // correction to short range interaction due to eta - int evflag = pair->evflag; double const qqrd2e = force->qqrd2e; int const nlocal = atom->nlocal; int *mask = atom->mask; @@ -1298,13 +1301,11 @@ double FixElectrodeConp::gausscorr(int eflag, bool fflag) f[j][2] -= delz * fpair; } } - - double ecoul = 0.; - if (eflag) ecoul = -prefactor * erfc_etar; - - if (evflag) { - force->pair->ev_tally(i, j, nlocal, newton_pair, 0., ecoul, fpair, delx, dely, delz); + if (eflag) { + double ecoul = -prefactor * erfc_etar; + force->pair->ev_tally(i, j, nlocal, newton_pair, 0., ecoul, 0., 0., 0., 0.); } + if (vflag) v_tally(i, j, nlocal, newton_pair, fpair, delx, dely, delz); } } } @@ -1625,3 +1626,70 @@ void FixElectrodeConp::unpack_forward_comm(int n, int first, double *buf) int const last = first + n; for (int i = first, m = 0; i < last; i++) atom->q[i] = buf[m++]; } + +/* ---------------------------------------------------------------------- + Tally virial of pair interactions in pre_reverse. This cannot be done with pair->ev_tally() + because compute_fdotr is called before pre_reverse, i.e. Virials need to be tallied even if fdotr + is used. +------------------------------------------------------------------------- */ + +void FixElectrodeConp::v_tally(int i, int j, int nlocal, int newton_pair, double fpair, double delx, + double dely, double delz) +{ + double v[6]; + if (vflag_either) { + v[0] = delx * delx * fpair; + v[1] = dely * dely * fpair; + v[2] = delz * delz * fpair; + v[3] = delx * dely * fpair; + v[4] = delx * delz * fpair; + v[5] = dely * delz * fpair; + + if (vflag_global) { + if (newton_pair) { + virial[0] += v[0]; + virial[1] += v[1]; + virial[2] += v[2]; + virial[3] += v[3]; + virial[4] += v[4]; + virial[5] += v[5]; + } else { + if (i < nlocal) { + virial[0] += 0.5 * v[0]; + virial[1] += 0.5 * v[1]; + virial[2] += 0.5 * v[2]; + virial[3] += 0.5 * v[3]; + virial[4] += 0.5 * v[4]; + virial[5] += 0.5 * v[5]; + } + if (j < nlocal) { + virial[0] += 0.5 * v[0]; + virial[1] += 0.5 * v[1]; + virial[2] += 0.5 * v[2]; + virial[3] += 0.5 * v[3]; + virial[4] += 0.5 * v[4]; + virial[5] += 0.5 * v[5]; + } + } + } + + if (vflag_atom) { + if (newton_pair || i < nlocal) { + vatom[i][0] += 0.5 * v[0]; + vatom[i][1] += 0.5 * v[1]; + vatom[i][2] += 0.5 * v[2]; + vatom[i][3] += 0.5 * v[3]; + vatom[i][4] += 0.5 * v[4]; + vatom[i][5] += 0.5 * v[5]; + } + if (newton_pair || j < nlocal) { + vatom[j][0] += 0.5 * v[0]; + vatom[j][1] += 0.5 * v[1]; + vatom[j][2] += 0.5 * v[2]; + vatom[j][3] += 0.5 * v[3]; + vatom[j][4] += 0.5 * v[4]; + vatom[j][5] += 0.5 * v[5]; + } + } + } +} diff --git a/src/ELECTRODE/fix_electrode_conp.h b/src/ELECTRODE/fix_electrode_conp.h index a1d7530bd1..b0b4a1fd46 100644 --- a/src/ELECTRODE/fix_electrode_conp.h +++ b/src/ELECTRODE/fix_electrode_conp.h @@ -119,10 +119,11 @@ class FixElectrodeConp : public Fix { void create_taglist(); void invert(); void symmetrize(); - double gausscorr(int, bool); + double gausscorr(int, int, bool); void update_charges(); double potential_energy(); double self_energy(int); + void v_tally(int, int, int, int, double, double, double, double); void write_to_file(FILE *, const std::vector &, const std::vector> &); void read_from_file(const std::string &input_file, double **, const std::string &); void compute_sd_vectors(); From b8360631e1448f109195d3242e2d9136bf16dde3 Mon Sep 17 00:00:00 2001 From: Shern Tee Date: Mon, 1 Jul 2024 10:35:54 +0200 Subject: [PATCH 140/385] Fix typos and add TF definitions to fix_electrode.rst --- doc/src/fix_electrode.rst | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/doc/src/fix_electrode.rst b/doc/src/fix_electrode.rst index 1a28f88bc1..99e098db31 100644 --- a/doc/src/fix_electrode.rst +++ b/doc/src/fix_electrode.rst @@ -110,7 +110,7 @@ electrostatic configurations: :ref:`(Deissenbeck)` between two electrodes * (resulting in changing charges and potentials with appropriate - average potential difference and thermal variance) + average potential difference and thermal variance) The first group-ID provided to each fix specifies the first electrode group, and more group(s) are added using the *couple* keyword for each @@ -284,8 +284,18 @@ The *fix_modify tf* option enables the Thomas-Fermi metallicity model fix_modify ID tf type length voronoi -If this option is used parameters must be set for all atom types of the -electrode. +If this option is used, these two parameters must be set for +all atom types of the electrode: + +* `tf` is the Thomas-Fermi length :math:`l_{TF}` +* `voronoi` is the Voronoi volume per atom in units of length cubed + +Different types may have different `tf` and `voronoi` values. +The following self-energy term is then added for all electrode atoms: + +.. math:: + + A_{ii} += \frac{1}{4 \pi \epsilon_0} \times \frac{4 \pi l_{TF}^2}{\mathrm{Voronoi volume}} The *fix_modify timer* option turns on (off) additional timer outputs in the log file, for code developers to track optimization. @@ -318,9 +328,11 @@ The global array has *N* rows and *2N+1* columns, where the fix manages array, the elements are: * array[I][1] = total charge that group *I* would have had *if it were - at 0 V applied potential* * array[I][2 to *N* + 1] = the *N* entries + at 0 V applied potential* +* array[I][2 to *N* + 1] = the *N* entries of the *I*-th row of the electrode capacitance matrix (definition - follows) * array[I][*N* + 2 to *2N* + 1] = the *N* entries of the + follows) +* array[I][*N* + 2 to *2N* + 1] = the *N* entries of the *I*-th row of the electrode elastance matrix (the inverse of the electrode capacitance matrix) From f633b0360285254c44cfd580093269906e411e5a Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 1 Jul 2024 09:33:20 -0600 Subject: [PATCH 141/385] ensure atom map is reset by fix pour and fix deposit --- src/GRANULAR/fix_pour.cpp | 2 +- src/fix_deposit.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GRANULAR/fix_pour.cpp b/src/GRANULAR/fix_pour.cpp index 2dcaf9069f..a4e76aa87a 100644 --- a/src/GRANULAR/fix_pour.cpp +++ b/src/GRANULAR/fix_pour.cpp @@ -703,7 +703,7 @@ void FixPour::pre_exchange() // rebuild atom map if (atom->map_style != Atom::MAP_NONE) { - if (success) atom->map_init(); + atom->map_init(); atom->map_set(); } diff --git a/src/fix_deposit.cpp b/src/fix_deposit.cpp index 62ff530033..d6630bcbf0 100644 --- a/src/fix_deposit.cpp +++ b/src/fix_deposit.cpp @@ -630,7 +630,7 @@ void FixDeposit::pre_exchange() // rebuild atom map if (atom->map_style != Atom::MAP_NONE) { - if (success) atom->map_init(); + atom->map_init(); atom->map_set(); } From edebab9a5c2e3c5bd18594676a864448aca06c95 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 1 Jul 2024 14:57:26 -0600 Subject: [PATCH 142/385] clarify possible map styles on atom_modify doc page --- doc/src/atom_modify.rst | 99 ++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/doc/src/atom_modify.rst b/doc/src/atom_modify.rst index 21590e6680..0d750f1755 100644 --- a/doc/src/atom_modify.rst +++ b/doc/src/atom_modify.rst @@ -71,11 +71,11 @@ all atoms, e.g. in a data or restart file. atom IDs are required, due to how neighbor lists are built. The *map* keyword determines how atoms with specific IDs are found -when required. An example are the bond (angle, etc) methods which -need to find the local index of an atom with a specific global ID -which is a bond (angle, etc) partner. LAMMPS performs this operation -efficiently by creating a "map", which is either an *array* or *hash* -table, as described below. +when required. For example, the bond (angle, etc) methods need to +find the local index of an atom with a specific global ID which is a +bond (angle, etc) partner. LAMMPS performs this operation efficiently +by creating a "map", which is either an *array* or *hash* table, as +described below. When the *map* keyword is not specified in your input script, LAMMPS only creates a map for :doc:`atom_styles ` for molecular @@ -83,34 +83,39 @@ systems which have permanent bonds (angles, etc). No map is created for atomic systems, since it is normally not needed. However some LAMMPS commands require a map, even for atomic systems, and will generate an error if one does not exist. The *map* keyword thus -allows you to force the creation of a map. The *yes* value will -create either an *array* or *hash* style map, as explained in the next -paragraph. The *array* and *hash* values create an array-style or -hash-style map respectively. +allows you to force the creation of a map. -For an *array*\ -style map, each processor stores a lookup table of -length N, where N is the largest atom ID in the system. This is a -fast, simple method for many simulations, but requires too much memory -for large simulations. For a *hash*\ -style map, a hash table is -created on each processor, which finds an atom ID in constant time -(independent of the global number of atom IDs). It can be slightly -slower than the *array* map, but its memory cost is proportional to -the number of atoms owned by a processor, i.e. N/P when N is the total -number of atoms in the system and P is the number of processors. +Specifying a value of *yes* will create either an array-style or +hash-style map, depending on the size of the system. If no atom ID is +larger than 1 million, then an array-style map is used, otherwise a +hash-style map is used. Specifying a value of *array* or *hash* +creates an array-style or hash-style map respectively, regardless of +the size of the system. -The *first* keyword allows a :doc:`group ` to be specified whose -atoms will be maintained as the first atoms in each processor's list -of owned atoms. This in only useful when the specified group is a -small fraction of all the atoms, and there are other operations LAMMPS -is performing that will be sped-up significantly by being able to loop -over the smaller set of atoms. Otherwise the reordering required by -this option will be a net slow-down. The :doc:`neigh_modify include ` and :doc:`comm_modify group ` -commands are two examples of commands that require this setting to -work efficiently. Several :doc:`fixes `, most notably time -integration fixes like :doc:`fix nve `, also take advantage of -this setting if the group they operate on is the group specified by -this command. Note that specifying "all" as the group-ID effectively -turns off the *first* option. +For an array-style map, each processor stores a lookup table of length +N, where N is the largest atom ID in the system. This is a fast, +simple method for many simulations, but requires too much memory for +large simulations. For a hash-style map, a hash table is created on +each processor, which finds an atom ID in constant time (independent +of the global number of atom IDs). It can be slightly slower than the +*array* map, but its memory cost is proportional to the number of +atoms owned by a processor, i.e. N/P when N is the total number of +atoms in the system and P is the number of processors. + +The *first* keyword allows a :doc:`group ` to be specified +whose atoms will be maintained as the first atoms in each processor's +list of owned atoms. This in only useful when the specified group is +a small fraction of all the atoms, and there are other operations +LAMMPS is performing that will be sped-up significantly by being able +to loop over the smaller set of atoms. Otherwise the reordering +required by this option will be a net slow-down. The +:doc:`neigh_modify include ` and :doc:`comm_modify group +` commands are two examples of commands that require this +setting to work efficiently. Several :doc:`fixes `, most notably +time integration fixes like :doc:`fix nve `, also take +advantage of this setting if the group they operate on is the group +specified by this command. Note that specifying "all" as the group-ID +effectively turns off the *first* option. It is OK to use the *first* keyword with a group that has not yet been defined, e.g. to use the atom_modify first command at the beginning of @@ -148,15 +153,16 @@ cache locality will be undermined. .. note:: - Running a simulation with sorting on versus off should not - change the simulation results in a statistical sense. However, a - different ordering will induce round-off differences, which will lead - to diverging trajectories over time when comparing two simulations. - Various commands, particularly those which use random numbers - (e.g. :doc:`velocity create `, and :doc:`fix langevin `), may generate (statistically identical) - results which depend on the order in which atoms are processed. The - order of atoms in a :doc:`dump ` file will also typically change - if sorting is enabled. + Running a simulation with sorting on versus off should not change + the simulation results in a statistical sense. However, a + different ordering will induce round-off differences, which will + lead to diverging trajectories over time when comparing two + simulations. Various commands, particularly those which use random + numbers (e.g. :doc:`velocity create `, and :doc:`fix + langevin `), may generate (statistically identical) + results which depend on the order in which atoms are processed. + The order of atoms in a :doc:`dump ` file will also typically + change if sorting is enabled. .. note:: @@ -183,12 +189,13 @@ Default By default, *id* is yes. By default, atomic systems (no bond topology info) do not use a map. For molecular systems (with bond topology -info), a map is used. The default map style is array if no atom ID is -larger than 1 million, otherwise the default is hash. By default, a -"first" group is not defined. By default, sorting is enabled with a -frequency of 1000 and a binsize of 0.0, which means the neighbor -cutoff will be used to set the bin size. If no neighbor cutoff is -defined, sorting will be turned off. +info), the default is to use a map of either *array* or *hash* style +depending on the size of the sustem, as explained above for the *map +yes* keyword/value option. By default, a *first* group is not +defined. By default, sorting is enabled with a frequency of 1000 and +a binsize of 0.0, which means the neighbor cutoff will be used to set +the bin size. If no neighbor cutoff is defined, sorting will be turned +off. ---------- From ad4573e4f629a5950eb184c6bef820bf1a8e280d Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Tue, 2 Jul 2024 11:08:05 -0600 Subject: [PATCH 143/385] add fourth term --- src/KOKKOS/angle_hybrid_kokkos.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/KOKKOS/angle_hybrid_kokkos.cpp b/src/KOKKOS/angle_hybrid_kokkos.cpp index a3ec21a5c5..8293e31b91 100644 --- a/src/KOKKOS/angle_hybrid_kokkos.cpp +++ b/src/KOKKOS/angle_hybrid_kokkos.cpp @@ -100,6 +100,7 @@ void AngleHybridKokkos::compute(int eflag, int vflag) d_anglelist(m,n,0) = d_anglelist_orig(i,0); d_anglelist(m,n,1) = d_anglelist_orig(i,1); d_anglelist(m,n,2) = d_anglelist_orig(i,2); + d_anglelist(m,n,3) = d_anglelist_orig(i,3); }); } From 4b8f961098102120e6dc41322e9df66932f73e95 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 2 Jul 2024 14:00:37 -0600 Subject: [PATCH 144/385] Updating headers --- src/GRANULAR/fix_add_heat.cpp | 2 +- src/RHEO/atom_vec_rheo.cpp | 19 ++++++++++--------- src/RHEO/atom_vec_rheo_thermal.cpp | 19 ++++++++++--------- src/RHEO/bond_rheo_shell.cpp | 1 + src/RHEO/compute_rheo_grad.cpp | 1 + src/RHEO/compute_rheo_interface.cpp | 19 ++++++++++--------- src/RHEO/compute_rheo_kernel.cpp | 19 ++++++++++--------- src/RHEO/compute_rheo_rho_sum.cpp | 5 +++-- src/RHEO/compute_rheo_surface.cpp | 19 ++++++++++--------- src/RHEO/compute_rheo_vshift.cpp | 19 ++++++++++--------- src/RHEO/fix_rheo.cpp | 19 ++++++++++--------- src/RHEO/fix_rheo_oxidation.cpp | 19 ++++++++++--------- src/RHEO/fix_rheo_pressure.cpp | 19 ++++++++++--------- src/RHEO/fix_rheo_thermal.cpp | 19 ++++++++++--------- src/RHEO/fix_rheo_viscosity.cpp | 19 ++++++++++--------- src/RHEO/pair_rheo.cpp | 19 ++++++++++--------- src/RHEO/pair_rheo_solid.cpp | 1 + 17 files changed, 127 insertions(+), 111 deletions(-) diff --git a/src/GRANULAR/fix_add_heat.cpp b/src/GRANULAR/fix_add_heat.cpp index a68c9c2b95..01bc22cdf4 100644 --- a/src/GRANULAR/fix_add_heat.cpp +++ b/src/GRANULAR/fix_add_heat.cpp @@ -1,4 +1,4 @@ -/* -*- c++ -*- ---------------------------------------------------------- +/* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories LAMMPS development team: developers@lammps.org diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp index 843269a717..92f5ca05a4 100644 --- a/src/RHEO/atom_vec_rheo.cpp +++ b/src/RHEO/atom_vec_rheo.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/atom_vec_rheo_thermal.cpp b/src/RHEO/atom_vec_rheo_thermal.cpp index 7174d4cb66..f541e2a0cb 100644 --- a/src/RHEO/atom_vec_rheo_thermal.cpp +++ b/src/RHEO/atom_vec_rheo_thermal.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index 9c198364d6..81e5ba02d1 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -1,3 +1,4 @@ +// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 8b618e6e04..216fcb1978 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -1,3 +1,4 @@ +// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index 672c63ba29..ec8c10f276 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index cb9a42323b..77733f9716 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/compute_rheo_rho_sum.cpp b/src/RHEO/compute_rheo_rho_sum.cpp index d7f432a03d..6e25b35374 100644 --- a/src/RHEO/compute_rheo_rho_sum.cpp +++ b/src/RHEO/compute_rheo_rho_sum.cpp @@ -1,7 +1,8 @@ +// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov + 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 diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 284afcd992..69b0ebd108 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index 6e858ca207..b01912111f 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index f12d10b8c5..cd0ca1069a 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index acd833dfda..74d1bbab57 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/fix_rheo_pressure.cpp b/src/RHEO/fix_rheo_pressure.cpp index d6dea8aa1a..82adf52012 100644 --- a/src/RHEO/fix_rheo_pressure.cpp +++ b/src/RHEO/fix_rheo_pressure.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index c1cda67500..dbb59f12f7 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/fix_rheo_viscosity.cpp b/src/RHEO/fix_rheo_viscosity.cpp index 5cb1e7c4d0..3ca7fd8d13 100644 --- a/src/RHEO/fix_rheo_viscosity.cpp +++ b/src/RHEO/fix_rheo_viscosity.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index 731047201c..b9beaf8383 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -1,15 +1,16 @@ +// clang-format off /* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org + 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. + 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. - ------------------------------------------------------------------------- */ + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: diff --git a/src/RHEO/pair_rheo_solid.cpp b/src/RHEO/pair_rheo_solid.cpp index 9b358420d2..1c8654b3c4 100644 --- a/src/RHEO/pair_rheo_solid.cpp +++ b/src/RHEO/pair_rheo_solid.cpp @@ -1,3 +1,4 @@ +// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories From 3385198b51b5555a9565b2844aa0ee95e504582c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 00:51:32 -0400 Subject: [PATCH 145/385] fix typo --- doc/src/atom_modify.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/atom_modify.rst b/doc/src/atom_modify.rst index 0d750f1755..9091626feb 100644 --- a/doc/src/atom_modify.rst +++ b/doc/src/atom_modify.rst @@ -190,7 +190,7 @@ Default By default, *id* is yes. By default, atomic systems (no bond topology info) do not use a map. For molecular systems (with bond topology info), the default is to use a map of either *array* or *hash* style -depending on the size of the sustem, as explained above for the *map +depending on the size of the system, as explained above for the *map yes* keyword/value option. By default, a *first* group is not defined. By default, sorting is enabled with a frequency of 1000 and a binsize of 0.0, which means the neighbor cutoff will be used to set From 0a6fd5b097b7f9ad372ac7ac7afb7ba6c9c52205 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 03:41:57 -0400 Subject: [PATCH 146/385] get rid of some evil tabs --- src/RHEO/compute_rheo_kernel.cpp | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index 77733f9716..a5865b894a 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -249,25 +249,25 @@ double ComputeRHEOKernel::calc_w_quintic(int i, int j, double delx, double dely, double w, tmp1, tmp2, tmp3, tmp1sq, tmp2sq, tmp3sq, s; s = r * 3.0 * cutinv; - if (s > 3.0) { - w = 0.0; - } + if (s > 3.0) { + w = 0.0; + } - if (s <= 3.0) { - tmp3 = 3.0 - s; - tmp3sq = tmp3 * tmp3; - w = tmp3sq * tmp3sq * tmp3; - } - if (s <= 2.0) { + if (s <= 3.0) { + tmp3 = 3.0 - s; + tmp3sq = tmp3 * tmp3; + w = tmp3sq * tmp3sq * tmp3; + } + if (s <= 2.0) { tmp2 = 2.0 - s; tmp2sq = tmp2 * tmp2; w -= 6.0 * tmp2sq * tmp2sq * tmp2; - } - if (s <= 1.0) { - tmp1 = 1.0 - s; - tmp1sq = tmp1 * tmp1; - w += 15.0 * tmp1sq * tmp1sq * tmp1; - } + } + if (s <= 1.0) { + tmp1 = 1.0 - s; + tmp1sq = tmp1 * tmp1; + w += 15.0 * tmp1sq * tmp1sq * tmp1; + } w *= pre_w; @@ -326,9 +326,9 @@ double ComputeRHEOKernel::calc_w_wendlandc4(int i, int j, double delx, double de double w, tmp6, s; s = r * cutinv; - if (s > 1.0) { - w = 0.0; - } else { + if (s > 1.0) { + w = 0.0; + } else { tmp6 = (1.0 - s) * (1.0 - s); tmp6 *= tmp6 * tmp6; w = tmp6 * (1.0 + 6.0 * s + 35.0 * THIRD * s * s); @@ -352,9 +352,9 @@ double ComputeRHEOKernel::calc_dw_wendlandc4(int i, int j, double delx, double d s = r * cutinv; - if (s > 1.0) { - wp = 0.0; - } else { + if (s > 1.0) { + wp = 0.0; + } else { tmp1 = 1.0 - s; tmp5 = tmp1 * tmp1; tmp5 = tmp5 * tmp5 * tmp1; From 1f021782634e3ce346bb54f37346cbcccf9daba6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 09:32:37 -0400 Subject: [PATCH 147/385] make exclusion more specific --- src/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/.gitignore b/src/.gitignore index 39c5de7555..5b13a7d55a 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -245,7 +245,8 @@ /pair_tdpd.cpp /pair_tdpd.h -/*rheo* +/*rheo*.cpp +/*rheo*.h /compute_grid.cpp /compute_grid.h From 33490fc402ee0c8637c9ccd9b1ba06226031e13f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 15:09:25 -0400 Subject: [PATCH 148/385] align with other similar tests in LAMMPS --- src/ELECTRODE/fix_electrode_conp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ELECTRODE/fix_electrode_conp.cpp b/src/ELECTRODE/fix_electrode_conp.cpp index aaa7f2fb99..6fa3722320 100644 --- a/src/ELECTRODE/fix_electrode_conp.cpp +++ b/src/ELECTRODE/fix_electrode_conp.cpp @@ -79,9 +79,9 @@ FixElectrodeConp::FixElectrodeConp(LAMMPS *lmp, int narg, char **arg) : potential_i(nullptr), potential_iele(nullptr) { if (lmp->citeme) lmp->citeme->add(cite_fix_electrode); - if (!atom->map_style) - error->all(FLERR, - "Atom style does not have an atom map. Use 'atom_modify map yes' to activate it."); + if (atom->map_style == Atom::MAP_NONE) + error->all(FLERR, "Fix {} requires an atom map, see atom_modify", style); + // fix.h output flags scalar_flag = 1; vector_flag = 1; From 01502f70a45ff903c3306df569df511e53fdf641 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 15:16:08 -0400 Subject: [PATCH 149/385] print warnings only on MPI rank 0 --- src/ELECTRODE/fix_electrode_conp.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/ELECTRODE/fix_electrode_conp.cpp b/src/ELECTRODE/fix_electrode_conp.cpp index 6fa3722320..18e65b2baf 100644 --- a/src/ELECTRODE/fix_electrode_conp.cpp +++ b/src/ELECTRODE/fix_electrode_conp.cpp @@ -354,7 +354,7 @@ int FixElectrodeConp::modify_param(int narg, char **arg) MPI_Allreduce(MPI_IN_PLACE, &in_ele, 1, MPI_INT, MPI_SUM, world); if (in_ele == 0) error->all(FLERR, "No atoms of type in electrode"); MPI_Allreduce(MPI_IN_PLACE, ¬_in_ele, 1, MPI_INT, MPI_SUM, world); - if (not_in_ele) + if (not_in_ele && (comm->me == 0)) error->warning(FLERR, "Not all atoms of type in electrode; Thomas-Fermi parameters will be ignored " "for electrolyte"); @@ -485,7 +485,7 @@ void FixElectrodeConp::post_constructor() input->variable->set(fmt::format("{} equal f_{}[{}]", var_vtop, fixname, 1 + top_group)); input->variable->set(fmt::format("{} equal (v_{}-v_{})/lz", var_efield, var_vbot, var_vtop)); // check for other efields and warn if found - if (modify->get_fix_by_style("^efield").size() > 0 && comm->me == 0) + if ((modify->get_fix_by_style("^efield").size() > 0) && (comm->me == 0)) error->warning(FLERR, "Other efield fixes found -- please make sure this is intended!"); // call fix command: // fix [varstem]_efield all efield 0.0 0.0 [var_vdiff]/lz @@ -647,9 +647,8 @@ void FixElectrodeConp::setup_post_neighbor() void FixElectrodeConp::setup_pre_reverse(int eflag, int vflag) { - if (pair->did_tally_callback()) - error->warning(FLERR, - "Computation of Virials in fix electrode is incompatible with TALLY package"); + if (pair->did_tally_callback() && (comm->me == 0)) + error->warning(FLERR, "Computation of virials in fix {} is incompatible with TALLY package", style); // correct forces for initial timestep ev_init(eflag, vflag); gausscorr(eflag, vflag, true); @@ -683,7 +682,7 @@ void FixElectrodeConp::invert() void FixElectrodeConp::symmetrize() { // S matrix to enforce charge neutrality constraint - if (read_inv && comm->me == 0) + if (read_inv && (comm->me == 0)) error->warning(FLERR, "Symmetrizing matrix from file. Make sure the provided matrix has not been " "symmetrized yet."); @@ -764,11 +763,11 @@ void FixElectrodeConp::setup_pre_exchange() // create_taglist // if memory_usage > 0.5 GiB, warn with expected usage double mem_needed = memory_usage(); mem_needed /= (1024 * 1024 * 1024); // convert to GiB - if (mem_needed > 0.5 && comm->me == 0) + if ((mem_needed > 0.5) && (comm->me == 0)) error->warning(FLERR, - "Please ensure there is sufficient memory for fix electrode " + "Please ensure there is sufficient memory for fix {} " "(anticipated usage is at least {:.1f} GiB per proc)", - mem_needed); + style, mem_needed); } /* ---------------------------------------------------------------------- */ @@ -932,7 +931,7 @@ void FixElectrodeConp::update_charges() dot_old = dot_new; } recompute_potential(b, q_local); - if (delta > cg_threshold && comm->me == 0) error->warning(FLERR, "CG threshold not reached"); + if ((delta > cg_threshold) && (comm->me == 0)) error->warning(FLERR, "CG threshold not reached"); } else { error->all(FLERR, "This algorithm is not implemented, yet"); } From ece17cf56fc3e238d7d5944ce2b00abbea7f9a88 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 3 Jul 2024 15:30:33 -0600 Subject: [PATCH 150/385] Adding rheo make support --- lib/rheo/Makefile.lammps | 7 +++ lib/rheo/README | 5 ++ src/Depend.sh | 4 ++ src/Makefile | 3 ++ src/RHEO/Install.sh | 103 +++++++++++++++++++++++++++++++++++++++ src/RHEO/README | 2 + 6 files changed, 124 insertions(+) create mode 100644 lib/rheo/Makefile.lammps create mode 100644 lib/rheo/README create mode 100644 src/RHEO/Install.sh diff --git a/lib/rheo/Makefile.lammps b/lib/rheo/Makefile.lammps new file mode 100644 index 0000000000..46f6dc7b96 --- /dev/null +++ b/lib/rheo/Makefile.lammps @@ -0,0 +1,7 @@ +# Settings that the LAMMPS build will import when this package is installed + +# change this to -I/path/to/your/lib/gsl/include/ +rheo_SYSINC = -I../../lib/rheo/gsl/include/ + +# change this to -L/path/to/your/lib/gsl/lib/ +rheo_SYSLIB = -L../../lib/rheo/gsl/lib/ -lgslcblas diff --git a/lib/rheo/README b/lib/rheo/README new file mode 100644 index 0000000000..8219d6e21a --- /dev/null +++ b/lib/rheo/README @@ -0,0 +1,5 @@ +This directory has a Makefile.lammps file with settings that allows +LAMMPS to dynamically link to the GSL library. This is +required to use the RHEO package in a LAMMPS input script. + +See the header of Makefile.lammps for more info. diff --git a/src/Depend.sh b/src/Depend.sh index e55b100975..fcd4a20d6f 100755 --- a/src/Depend.sh +++ b/src/Depend.sh @@ -56,6 +56,10 @@ if (test $1 = "ASPHERE") then depend INTEL fi +if (test $1 = "BPM") then + depend RHEO +fi + if (test $1 = "CLASS2") then depend GPU depend KOKKOS diff --git a/src/Makefile b/src/Makefile index 805b950112..4d8b02458a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -124,6 +124,7 @@ PACKAGE = \ reaction \ reaxff \ replica \ + rheo \ rigid \ scafacos \ shock \ @@ -233,6 +234,7 @@ PACKLIB = \ plumed \ qmmm \ ml-quip \ + rheo \ scafacos \ machdyn \ vtk \ @@ -254,6 +256,7 @@ PACKEXT = \ netcdf \ plumed \ qmmm \ + rheo \ scafacos \ voronoi \ vtk \ diff --git a/src/RHEO/Install.sh b/src/RHEO/Install.sh new file mode 100644 index 0000000000..3e3ba75e32 --- /dev/null +++ b/src/RHEO/Install.sh @@ -0,0 +1,103 @@ +# Install/unInstall package files in LAMMPS +# mode = 0/1/2 for uninstall/install/update + +mode=$1 + +# enforce using portable C locale +LC_ALL=C +export LC_ALL + +# arg1 = file, arg2 = file it depends on + +action () { + if (test $mode = 0) then + rm -f ../$1 + elif (! cmp -s $1 ../$1) then + if (test -z "$2" || test -e ../$2) then + cp $1 .. + if (test $mode = 2) then + echo " updating src/$1" + fi + fi + elif (test -n "$2") then + if (test ! -e ../$2) then + rm -f ../$1 + fi + fi +} + +# package files without dependencies +action atom_vec_rheo_thermal.h +action atom_vec_rheo_thermal.cpp +action atom_vec_rheo.h +action atom_vec_rheo.cpp +action compute_rheo_grad.h +action compute_rheo_grad.cpp +action compute_rheo_interface.h +action compute_rheo_interface.cpp +action compute_rheo_kernel.h +action compute_rheo_kernel.cpp +action compute_rheo_rho_sum.h +action compute_rheo_rho_sum.cpp +action compute_rheo_surface.h +action compute_rheo_surface.cpp +action compute_rheo_vshift.h +action compute_rheo_vshift.cpp +action fix_rheo_oxidation.h +action fix_rheo_oxidation.cpp +action fix_rheo_pressure.h +action fix_rheo_pressure.cpp +action fix_rheo_viscosity.h +action fix_rheo_viscosity.cpp +action fix_rheo.h +action fix_rheo.cpp +action pair_rheo.h +action pair_rheo.cpp +action pair_rheo_solid.h +action pair_rheo_solid.cpp + +# package files with dependencies +action bond_rheo_shell.h bond_bpm.h +action bond_rheo_shell.cpp bond_bpm.h +action compute_rheo_property_atom.h fix_update_special_bonds.h +action compute_rheo_property_atom.cpp fix_update_special_bonds.h +action fix_rheo_thermal.h fix_update_special_bonds.h +action fix_rheo_thermal.cpp fix_update_special_bonds.h + +# Warn that some styles in RHEO have base classes in BPM + +if (test $1 = 1) then + if (test ! -e ../bond_bpm.cpp) then + echo "Must install BPM package to use all features of RHEO package" + fi +fi + +# edit 2 Makefile.package files to include/exclude package info + +if (test $1 = 1) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*rheo[^ \t]* //' ../Makefile.package + sed -i -e 's|^PKG_SYSINC =[ \t]*|&$(rheo_SYSINC) |' ../Makefile.package + sed -i -e 's|^PKG_SYSLIB =[ \t]*|&$(rheo_SYSLIB) |' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^[ \t]*include.*rheo.*$/d' ../Makefile.package.settings + # multiline form needed for BSD sed on Macs + sed -i -e '4 i \ +include ..\/..\/lib\/rheo\/Makefile.lammps +' ../Makefile.package.settings + fi + +elif (test $1 = 0) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*rheo[^ \t]* //' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^[ \t]*include.*rheo.*$/d' ../Makefile.package.settings + fi + +fi diff --git a/src/RHEO/README b/src/RHEO/README index 7090fc828c..6e8dcfb856 100644 --- a/src/RHEO/README +++ b/src/RHEO/README @@ -2,6 +2,8 @@ RHEO or Reproducing Hydrodynamics and Elastic Objects is a package to model mult systems. The authors include Joel Clemmer (Sandia), Thomas O'Connor (Carnegie Mellon), and Eric Palermo (Carnegie Mellon). +Bond style rheo/shell, compute style rheo/property/atom, and fix style rheo/temperature all depend on the BPM package. + This package requires the GNU scientific library (GSL). We recommend version 2.7 or later. To build this package, one must first separately install GSL in a location that can be found by your environment. From 9b52888e531c09c4e8deef707d06039ec31d554b Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 3 Jul 2024 15:53:38 -0600 Subject: [PATCH 151/385] Adding RHEO dependency to cmake --- cmake/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index e66b6b17a7..77f1610064 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -411,6 +411,7 @@ pkg_depends(CG-DNA ASPHERE) pkg_depends(ELECTRODE KSPACE) pkg_depends(EXTRA-MOLECULE MOLECULE) pkg_depends(MESONT MOLECULE) +pkg_depends(RHEO BPM) # detect if we may enable OpenMP support by default set(BUILD_OMP_DEFAULT OFF) From e1232af8677e78b116506e26b23093d2ac1f4640 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 3 Jul 2024 16:12:17 -0600 Subject: [PATCH 152/385] Missing flag and changing dependencies --- lib/rheo/Makefile.lammps | 2 +- src/RHEO/Install.sh | 47 ++++++---------------------------------- 2 files changed, 8 insertions(+), 41 deletions(-) diff --git a/lib/rheo/Makefile.lammps b/lib/rheo/Makefile.lammps index 46f6dc7b96..3372e9463c 100644 --- a/lib/rheo/Makefile.lammps +++ b/lib/rheo/Makefile.lammps @@ -4,4 +4,4 @@ rheo_SYSINC = -I../../lib/rheo/gsl/include/ # change this to -L/path/to/your/lib/gsl/lib/ -rheo_SYSLIB = -L../../lib/rheo/gsl/lib/ -lgslcblas +rheo_SYSLIB = -L../../lib/rheo/gsl/lib/ -lgsl -lgslcblas diff --git a/src/RHEO/Install.sh b/src/RHEO/Install.sh index 3e3ba75e32..e34ca3a555 100644 --- a/src/RHEO/Install.sh +++ b/src/RHEO/Install.sh @@ -26,52 +26,19 @@ action () { fi } -# package files without dependencies -action atom_vec_rheo_thermal.h -action atom_vec_rheo_thermal.cpp -action atom_vec_rheo.h -action atom_vec_rheo.cpp -action compute_rheo_grad.h -action compute_rheo_grad.cpp -action compute_rheo_interface.h -action compute_rheo_interface.cpp -action compute_rheo_kernel.h -action compute_rheo_kernel.cpp -action compute_rheo_rho_sum.h -action compute_rheo_rho_sum.cpp -action compute_rheo_surface.h -action compute_rheo_surface.cpp -action compute_rheo_vshift.h -action compute_rheo_vshift.cpp -action fix_rheo_oxidation.h -action fix_rheo_oxidation.cpp -action fix_rheo_pressure.h -action fix_rheo_pressure.cpp -action fix_rheo_viscosity.h -action fix_rheo_viscosity.cpp -action fix_rheo.h -action fix_rheo.cpp -action pair_rheo.h -action pair_rheo.cpp -action pair_rheo_solid.h -action pair_rheo_solid.cpp - -# package files with dependencies -action bond_rheo_shell.h bond_bpm.h -action bond_rheo_shell.cpp bond_bpm.h -action compute_rheo_property_atom.h fix_update_special_bonds.h -action compute_rheo_property_atom.cpp fix_update_special_bonds.h -action fix_rheo_thermal.h fix_update_special_bonds.h -action fix_rheo_thermal.cpp fix_update_special_bonds.h - -# Warn that some styles in RHEO have base classes in BPM +# some styles in RHEO have base classes in BPM if (test $1 = 1) then if (test ! -e ../bond_bpm.cpp) then - echo "Must install BPM package to use all features of RHEO package" + echo "Must install BPM package with RHEO" + exit 1 fi fi +for file in *.cpp *.h; do + action ${file} +done + # edit 2 Makefile.package files to include/exclude package info if (test $1 = 1) then From feba9640afc74b2a95b2d9e3c9bbe470d013f707 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 18:22:27 -0400 Subject: [PATCH 153/385] not needed anymore --- src/Depend.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Depend.sh b/src/Depend.sh index fcd4a20d6f..e55b100975 100755 --- a/src/Depend.sh +++ b/src/Depend.sh @@ -56,10 +56,6 @@ if (test $1 = "ASPHERE") then depend INTEL fi -if (test $1 = "BPM") then - depend RHEO -fi - if (test $1 = "CLASS2") then depend GPU depend KOKKOS From 96d58bb03e0fc87d0ca6c4b299347143c5f7f3a8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 18:32:42 -0400 Subject: [PATCH 154/385] automatically set include/libs flags for GSL, if pkg-config is available --- lib/rheo/Makefile.lammps | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/rheo/Makefile.lammps b/lib/rheo/Makefile.lammps index 3372e9463c..ec58740370 100644 --- a/lib/rheo/Makefile.lammps +++ b/lib/rheo/Makefile.lammps @@ -1,7 +1,14 @@ # Settings that the LAMMPS build will import when this package is installed -# change this to -I/path/to/your/lib/gsl/include/ -rheo_SYSINC = -I../../lib/rheo/gsl/include/ +ifeq ($(strip $(shell pkg-config --version)),) + # manual configuration w/o pkg-config/pkgconf + # change this to -I/path/to/your/lib/gsl/include/ + rheo_SYSINC = -I../../lib/rheo/gsl/include/ -# change this to -L/path/to/your/lib/gsl/lib/ -rheo_SYSLIB = -L../../lib/rheo/gsl/lib/ -lgsl -lgslcblas + # change this to -L/path/to/your/lib/gsl/lib/ + rheo_SYSLIB = -L../../lib/rheo/gsl/lib/ -lgsl -lgslcblas +else + # autodetect GSL settings from pkg-config/pkgconf + rheo_SYSINC = $(shell pkg-config --cflags gsl) + rheo_SYSLIB = $(shell pkg-config --libs gsl) +endif From b6d11b5902e3d4357d52aa2c8358ce4086551027 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 19:07:19 -0400 Subject: [PATCH 155/385] document GSL dependency and provide build instructions for RHEO package --- cmake/Modules/Packages/RHEO.cmake | 2 +- doc/src/Build_extras.rst | 40 +++++++++++++++++++++++++++---- doc/src/Packages_details.rst | 20 +++++++++------- lib/rheo/README | 8 ++++--- src/RHEO/README | 15 ++++++------ 5 files changed, 62 insertions(+), 23 deletions(-) diff --git a/cmake/Modules/Packages/RHEO.cmake b/cmake/Modules/Packages/RHEO.cmake index 970a141bbd..be8c22877b 100644 --- a/cmake/Modules/Packages/RHEO.cmake +++ b/cmake/Modules/Packages/RHEO.cmake @@ -1,2 +1,2 @@ -find_package(GSL REQUIRED) +find_package(GSL 2.7 REQUIRED) target_link_libraries(lammps PRIVATE GSL::gsl) diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index f66238c3c9..4802c67420 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -59,6 +59,7 @@ This is the list of packages that may require additional steps. * :ref:`POEMS ` * :ref:`PYTHON ` * :ref:`QMMM ` + * :ref:`RHEO ` * :ref:`SCAFACOS ` * :ref:`VORONOI ` * :ref:`VTK ` @@ -1566,10 +1567,11 @@ LAMMPS build. .. tab:: CMake build When the ``-D PKG_PLUMED=yes`` flag is included in the cmake - command you must ensure that GSL is installed in locations that - are specified in your environment. There are then two additional - variables that control the manner in which PLUMED is obtained and - linked into LAMMPS. + command you must ensure that `the GNU Scientific Library (GSL) + ` is installed in locations + that are accessible in your environment. There are then two + additional variables that control the manner in which PLUMED is + obtained and linked into LAMMPS. .. code-block:: bash @@ -2040,6 +2042,36 @@ verified to work in February 2020 with Quantum Espresso versions 6.3 to ---------- +.. _rheo: + +RHEO package +------------ + +To build with this package you must have the `GNU Scientific Library +(GSL) ` installed in locations that +are accessible in your environment. The GSL library should be at least +version 2.7. + +.. tabs:: + + .. tab:: CMake build + + If CMake cannot find the GSL library or include files, you can set: + + .. code-block:: bash + + -D GSL_ROOT_DIR=path # path to root of GSL installation + + .. tab:: Traditional make + + LAMMPS will try to auto-detect the GSL compiler and linker flags + from the corresponding ``pkg-config`` file (``gsl.pc``), otherwise + you can edit the file ``lib/rheo/Makefile.lammps`` + to specify the paths and library names where indicated by comments. + This must be done **before** the package is installed. + +---------- + .. _scafacos: SCAFACOS package diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index 860ae24489..f3cf086d88 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -8,12 +8,12 @@ info on how to download or build any extra library it requires. It also gives links to documentation, example scripts, and pictures/movies (if available) that illustrate use of the package. -The majority of packages can be included in a LAMMPS build with a -single setting (``-D PKG_=on`` for CMake) or command -(``make yes-`` for make). See the :doc:`Build package ` -page for more info. A few packages may require additional steps; -this is indicated in the descriptions below. The :doc:`Build extras ` -page gives those details. +The majority of packages can be included in a LAMMPS build with a single +setting (``-D PKG_=on`` for CMake) or command (``make yes-`` +for make). See the :doc:`Build package ` page for more +info. A few packages may require additional steps; this is indicated in +the descriptions below. The :doc:`Build extras ` page +gives those details. .. note:: @@ -2630,8 +2630,12 @@ RHEO package **Contents:** Pair styles, bond styles, fixes, and computes for reproducing -hydrodynamics and elastic objects. See the -:doc:`Howto rheo ` page for an overview. +hydrodynamics and elastic objects. See the :doc:`Howto rheo +` page for an overview. + +**Install:** + +This package has :ref:`specific installation instructions ` on the :doc:`Build extras ` page. **Authors:** Joel T. Clemmer (Sandia National Labs), Thomas C. O'Connor (Carnegie Mellon University) diff --git a/lib/rheo/README b/lib/rheo/README index 8219d6e21a..ae421b6e80 100644 --- a/lib/rheo/README +++ b/lib/rheo/README @@ -1,5 +1,7 @@ -This directory has a Makefile.lammps file with settings that allows -LAMMPS to dynamically link to the GSL library. This is -required to use the RHEO package in a LAMMPS input script. +This directory has a Makefile.lammps file with settings that allows LAMMPS to +dynamically link to the GSL library. This is required to use the RHEO package +in a LAMMPS input script. If you have the pkg-config command available, it +will automatically import the GSL settings. Otherwise they will have to be +added manually. See the header of Makefile.lammps for more info. diff --git a/src/RHEO/README b/src/RHEO/README index 6e8dcfb856..4b6f2a162a 100644 --- a/src/RHEO/README +++ b/src/RHEO/README @@ -1,9 +1,10 @@ -RHEO or Reproducing Hydrodynamics and Elastic Objects is a package to model multiphase fluid -systems. The authors include Joel Clemmer (Sandia), Thomas O'Connor (Carnegie Mellon), and -Eric Palermo (Carnegie Mellon). +RHEO or Reproducing Hydrodynamics and Elastic Objects is a package to model +multiphase fluid systems. The authors include Joel Clemmer (Sandia), Thomas +O'Connor (Carnegie Mellon), and Eric Palermo (Carnegie Mellon). -Bond style rheo/shell, compute style rheo/property/atom, and fix style rheo/temperature all depend on the BPM package. +Bond style rheo/shell, compute style rheo/property/atom, and fix style +rheo/temperature all depend on the BPM package. -This package requires the GNU scientific library (GSL). We recommend version 2.7 or later. To -build this package, one must first separately install GSL in a location that can be found by -your environment. +This package requires the GNU scientific library (GSL). We recommend version +2.7 or later. To build this package, one must first separately install GSL in +a location that can be found by your environment. From 0fb74936582fe6ac14e417d50f106d0ba351e3e7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 19:10:37 -0400 Subject: [PATCH 156/385] spelling fixes --- doc/src/Howto_rheo.rst | 10 +++++----- doc/src/atom_modify.rst | 2 +- doc/src/fix_rheo.rst | 4 ++-- doc/src/fix_rheo_pressure.rst | 2 +- doc/src/fix_rheo_thermal.rst | 4 ++-- doc/src/fix_rheo_viscosity.rst | 2 +- doc/utils/sphinx-config/false_positives.txt | 12 ++++++++++++ 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index 4c0f069d92..7c62d09ab1 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -4,7 +4,7 @@ Reproducing hydrodynamics and elastic objects (RHEO) The RHEO package is a hybrid implementation of smoothed particle hydrodynamics (SPH) for fluid flow, coupled to the :doc:`BPM package ` to model solid elements. RHEO combines these methods to enable mesh-free modeling -of multiphase material systems. The SPH solver supports many advanced options +of multi-phase material systems. The SPH solver supports many advanced options including reproducing kernels, particle shifting, free surface identification, and solid surface reconstruction. To model fluid-solid systems, the status of particles can dynamically change between a fluid and solid state, e.g. during @@ -30,7 +30,7 @@ of reproducing kernels). In conjunction to fix rheo, one must specify an instance of :doc:`fix rheo/pressure ` and :doc:`fix rheo/viscosity ` to define a pressure equation of state and viscosity model, respectively. Optionally, one can model -a heat equation with :doc:`fix rheo/thermal `, which also +a heat equation with :doc:`fix rheo/thermal `, which also allows the user to specify equations for a particle's thermal conductivity, specific heat, latent heat, and melting temperature. The ordering of these fixes in an an input script matters. Fix rheo must be defined prior to all @@ -44,7 +44,7 @@ conductivity. Note that the temperature is always derived from the energy. This implies the *temperature* attribute of :doc:`the set command ` does not affect particles. Instead, one should use the *sph/e* attribute. -The status variable uses bitmasking to track various properties of a particle +The status variable uses bit-masking to track various properties of a particle such as its current state of matter (fluid or solid) and its location relative to a surface. Some of these properties (and others) can be accessed using :doc:`compute rheo/property/atom `. The *status* @@ -88,8 +88,8 @@ as bonds are created/broken. The other option for elastic objects is an elastic shell that is nominally much thinner than a particle diameter, e.g. a oxide skin which gradually forms over time on the surface of a fluid. Currently, this is implemented using -:doc:`fix rheo/oxidaton ` and bond style -:doc:`rheo/shell `. Essentially, fix rheo/oxidaton creates candidate +:doc:`fix rheo/oxidation ` and bond style +:doc:`rheo/shell `. Essentially, fix rheo/oxidation creates candidate bonds of a specified type between surface fluid particles within a specified distance. a newly created rheo/shell bond will then start a timer. While the timer is counting down, the bond will delete itself if particles move too far apart or move away from the diff --git a/doc/src/atom_modify.rst b/doc/src/atom_modify.rst index 0d750f1755..9091626feb 100644 --- a/doc/src/atom_modify.rst +++ b/doc/src/atom_modify.rst @@ -190,7 +190,7 @@ Default By default, *id* is yes. By default, atomic systems (no bond topology info) do not use a map. For molecular systems (with bond topology info), the default is to use a map of either *array* or *hash* style -depending on the size of the sustem, as explained above for the *map +depending on the size of the system, as explained above for the *map yes* keyword/value option. By default, a *first* group is not defined. By default, sorting is enabled with a frequency of 1000 and a binsize of 0.0, which means the neighbor cutoff will be used to set diff --git a/doc/src/fix_rheo.rst b/doc/src/fix_rheo.rst index d69b52d751..c9bf0a7aa0 100644 --- a/doc/src/fix_rheo.rst +++ b/doc/src/fix_rheo.rst @@ -90,7 +90,7 @@ In systems with free surfaces, the *surface/detection* keyword can be used to classify the location of particles as being within the bulk fluid, on a free surface, or isolated from other particles in a splash or droplet. Shifting is then disabled in the normal direction away from the free surface -to prevent particles from difusing away. Surface detection can also be used +to prevent particles from diffusing away. Surface detection can also be used to control surface-nucleated effects like oxidation when used in combination with :doc:`fix rheo/oxidation `. Surface detection is not performed on solid bodies. @@ -145,7 +145,7 @@ Restrictions """""""""""" This fix must be used with atom style rheo or rheo/thermal. This fix must -be used in conjuction with :doc:`fix rheo/pressure `. +be used in conjunction with :doc:`fix rheo/pressure `. and :doc:`fix rheo/viscosity `. If the *thermal* setting is used, there must also be an instance of :doc:`fix rheo/thermal `. The fix group must be set to all. diff --git a/doc/src/fix_rheo_pressure.rst b/doc/src/fix_rheo_pressure.rst index e01aebf90f..40d623ae07 100644 --- a/doc/src/fix_rheo_pressure.rst +++ b/doc/src/fix_rheo_pressure.rst @@ -86,7 +86,7 @@ Restrictions This fix must be used with an atom style that includes density such as atom_style rheo or rheo/thermal. This fix must be used in -conjuction with :doc:`fix rheo `. The fix group must be +conjunction with :doc:`fix rheo `. The fix group must be set to all. Only one instance of fix rheo/pressure can be defined. This fix is part of the RHEO package. It is only enabled if diff --git a/doc/src/fix_rheo_thermal.rst b/doc/src/fix_rheo_thermal.rst index e116325091..cf245cbdca 100644 --- a/doc/src/fix_rheo_thermal.rst +++ b/doc/src/fix_rheo_thermal.rst @@ -105,8 +105,8 @@ Restrictions """""""""""" This fix must be used with an atom style that includes temperature, -heatflow, and conductivity such as atom_tyle rheo/thermal This fix -must be used in conjuction with :doc:`fix rheo ` with the +heatflow, and conductivity such as atom_style rheo/thermal This fix +must be used in conjunction with :doc:`fix rheo ` with the *thermal* setting. The fix group must be set to all. Only one instance of fix rheo/pressure can be defined. diff --git a/doc/src/fix_rheo_viscosity.rst b/doc/src/fix_rheo_viscosity.rst index 912de584c2..5eca39dcdd 100644 --- a/doc/src/fix_rheo_viscosity.rst +++ b/doc/src/fix_rheo_viscosity.rst @@ -91,7 +91,7 @@ Restrictions This fix must be used with an atom style that includes viscosity such as atom_style rheo or rheo/thermal. This fix must be used in -conjuction with :doc:`fix rheo `. The fix group must be +conjunction with :doc:`fix rheo `. The fix group must be set to all. Only one instance of fix rheo/viscosity can be defined. This fix is part of the RHEO package. It is only enabled if diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index c300cf608d..babe66d27d 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -393,6 +393,7 @@ buf builtin Bulacu Bulatov +Bulkley Bureekaew burlywood Bussi @@ -564,6 +565,7 @@ cond conda Conda Condens +conductivities conf config configfile @@ -1440,6 +1442,7 @@ henrich Henrich Hermitian Herrmann +Hershchel Hertizian hertzian Hertzsch @@ -1831,6 +1834,7 @@ Kspace KSpace KSpaceStyle Kspring +kstyle kT kTequil kth @@ -2271,6 +2275,7 @@ modelled modelling Modelling Modine +modularity moduli mofff MOFFF @@ -2488,6 +2493,7 @@ Neumann Nevent nevery Nevery +Nevins newfile Newns newtype @@ -3067,6 +3073,7 @@ quatw queryargs Queteschiner quickmin +quintic qw qx qy @@ -3078,6 +3085,7 @@ radialscreenedspin radialspin radian radians +radiative radj Rafferty rahman @@ -3181,6 +3189,7 @@ rg Rg Rhaphson Rhe +rheo rheological rheology rhodo @@ -3268,6 +3277,7 @@ rsort rsq rst rstyle +rsurf Rubensson Rubia Rud @@ -3651,6 +3661,7 @@ Telsa tempCorrCoeff templated Templeton +Tencer Tequil ters tersoff @@ -3997,6 +4008,7 @@ Vries Vsevolod Vsmall Vstream +vstyle vtarget vtk VTK From f94b0789364daf9e7fd5bebf39a436ad642fba19 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 21:21:35 -0400 Subject: [PATCH 157/385] use pkg-config instead of pkgconf consistently, since the latter comes with compatibility to the former --- doc/src/Build_link.rst | 8 ++++---- doc/src/Tools.rst | 6 +++--- lib/qmmm/Makefile.gfortran-cmake | 4 ++-- lib/qmmm/README | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/src/Build_link.rst b/doc/src/Build_link.rst index 3800e41e21..efd6691d30 100644 --- a/doc/src/Build_link.rst +++ b/doc/src/Build_link.rst @@ -45,8 +45,8 @@ executable code from the library is copied into the calling executable. .. code-block:: bash - mpicc -c -O $(pkgconf liblammps --cflags) caller.c - mpicxx -o caller caller.o -$(pkgconf liblammps --libs) + mpicc -c -O $(pkg-config --cflags liblammps) caller.c + mpicxx -o caller caller.o -$(pkg-config --libs liblammps) .. tab:: Traditional make @@ -155,8 +155,8 @@ POEMS package installed becomes: .. code-block:: bash - mpicc -c -O $(pkgconf liblammps --cflags) caller.c - mpicxx -o caller caller.o -$(pkgconf --libs) + mpicc -c -O $(pkg-config --cflags liblammps) caller.c + mpicxx -o caller caller.o -$(pkg-config --libs liblammps) .. tab:: Traditional make diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index 0732398e53..9bc9c935a7 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -1329,7 +1329,7 @@ for Tcl with: .. code-block:: bash swig -tcl -module tcllammps lammps.i - gcc -fPIC -shared $(pkgconf --cflags tcl) -o tcllammps.so \ + gcc -fPIC -shared $(pkg-config tcl --cflags) -o tcllammps.so \ lammps_wrap.c -L ../src/ -llammps tclsh @@ -1340,8 +1340,8 @@ functions included with: swig -tcl -module tcllmps lammps_shell.i gcc -o tcllmpsh lammps_wrap.c -Xlinker -export-dynamic \ - -DHAVE_CONFIG_H $(pkgconf --cflags tcl) \ - $(pkgconf --libs tcl) -L ../src -llammps + -DHAVE_CONFIG_H $(pkg-config tcl --cflags) \ + $(pkg-config tcl --libs) -L ../src -llammps In both cases it is assumed that the LAMMPS library was compiled as a shared library in the ``src`` folder. Otherwise the last diff --git a/lib/qmmm/Makefile.gfortran-cmake b/lib/qmmm/Makefile.gfortran-cmake index 7a467a5e1c..36cb04617b 100644 --- a/lib/qmmm/Makefile.gfortran-cmake +++ b/lib/qmmm/Makefile.gfortran-cmake @@ -46,8 +46,8 @@ QELIBS += -lgfortran -lmpi_mpifh # part 3: add-on libraries and main library for LAMMPS sinclude ../../src/Makefile.package -LAMMPSFLAGS = $(shell pkgconf liblammps --cflags) -LAMMPSLIB = $(shell pkgconf liblammps --libs) +LAMMPSFLAGS = $(shell pkg-config --cflags liblammps) +LAMMPSLIB = $(shell pkg-config --libs liblammps) # part 4: local QM/MM library and progams SRC=pwqmmm.c libqmmm.c diff --git a/lib/qmmm/README b/lib/qmmm/README index 02401e3293..9e2b7e72f5 100644 --- a/lib/qmmm/README +++ b/lib/qmmm/README @@ -101,7 +101,7 @@ Makefile.gfortran-cmake and make adjustments to the makefile variables according to the comments in the file. You probably need to adjust the QETOPDIR variable to point to the location of your QE compilation/installation. -Please also check that the command "pkgconf liblammps --libs" works. +Please also check that the command "pkg-config --libs liblammps" works. Then you should be able to compile the QM/MM executable with: make -f Makefile.gfortran-cmake pwqmmm.x From a4d69878fa58ba59a1bc913bfaf37bf5c9f47524 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 22:00:26 -0400 Subject: [PATCH 158/385] update list of available sanitizers for Fedora 40 and GCC 14 --- cmake/Modules/Testing.cmake | 4 ++-- doc/src/Build_development.rst | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/Modules/Testing.cmake b/cmake/Modules/Testing.cmake index ff595d3c8f..a72ce17e1b 100644 --- a/cmake/Modules/Testing.cmake +++ b/cmake/Modules/Testing.cmake @@ -102,9 +102,9 @@ endif() ####################################### # select code sanitizer options ####################################### -set(ENABLE_SANITIZER "none" CACHE STRING "Select a code sanitizer option (none (default), address, leak, thread, undefined)") +set(ENABLE_SANITIZER "none" CACHE STRING "Select a code sanitizer option (none (default), address, hwaddress, leak, thread, undefined)") mark_as_advanced(ENABLE_SANITIZER) -set(ENABLE_SANITIZER_VALUES none address leak thread undefined) +set(ENABLE_SANITIZER_VALUES none address hwaddress leak thread undefined) set_property(CACHE ENABLE_SANITIZER PROPERTY STRINGS ${ENABLE_SANITIZER_VALUES}) validate_option(ENABLE_SANITIZER ENABLE_SANITIZER_VALUES) string(TOLOWER ${ENABLE_SANITIZER} ENABLE_SANITIZER) diff --git a/doc/src/Build_development.rst b/doc/src/Build_development.rst index 4d8bf0d07f..8e103b089a 100644 --- a/doc/src/Build_development.rst +++ b/doc/src/Build_development.rst @@ -88,8 +88,8 @@ on recording all commands required to do the compilation. .. _sanitizer: -Address, Undefined Behavior, and Thread Sanitizer Support (CMake only) ----------------------------------------------------------------------- +Address, Leak, Undefined Behavior, and Thread Sanitizer Support (CMake only) +---------------------------------------------------------------------------- Compilers such as GCC and Clang support generating instrumented binaries which use different sanitizer libraries to detect problems in the code @@ -110,6 +110,7 @@ compilation and linking stages. This is done through setting the -D ENABLE_SANITIZER=none # no sanitizer active (default) -D ENABLE_SANITIZER=address # enable address sanitizer / memory leak checker + -D ENABLE_SANITIZER=hwaddress # enable hardware assisted address sanitizer / memory leak checker -D ENABLE_SANITIZER=leak # enable memory leak checker (only) -D ENABLE_SANITIZER=undefined # enable undefined behavior sanitizer -D ENABLE_SANITIZER=thread # enable thread sanitizer From 10e3595b5798e42bcace44a7d6197410bbbde4fe Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 3 Jul 2024 22:20:06 -0400 Subject: [PATCH 159/385] separately catch exceptions thrown by new --- src/main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index caf1d4d53c..da80d66b52 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ #include #include +#include #if defined(LAMMPS_TRAP_FPE) && defined(_GNU_SOURCE) #include @@ -89,6 +90,11 @@ int main(int argc, char **argv) finalize(); MPI_Abort(MPI_COMM_WORLD, 1); exit(1); + } catch (std::bad_alloc &ae) { + fprintf(stderr, "C++ memory allocation failed: %s\n", ae.what()); + finalize(); + MPI_Abort(MPI_COMM_WORLD, 1); + exit(1); } catch (std::exception &e) { fprintf(stderr, "Exception: %s\n", e.what()); finalize(); From cefe76919c76bff3d6a52786fd6a12297e5bb8cf Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 4 Jul 2024 11:12:40 -0400 Subject: [PATCH 160/385] make more use of auto and thus avoid having to specify the same type twice --- tools/lammps-gui/chartviewer.cpp | 2 +- tools/lammps-gui/codeeditor.cpp | 20 ++++++++++---------- tools/lammps-gui/helpers.cpp | 2 +- tools/lammps-gui/imageviewer.cpp | 22 +++++++++++----------- tools/lammps-gui/lammpsgui.cpp | 12 ++++++------ tools/lammps-gui/logwindow.cpp | 6 +++--- tools/lammps-gui/preferences.cpp | 26 +++++++++++++------------- tools/lammps-gui/slideshow.cpp | 4 ++-- 8 files changed, 47 insertions(+), 47 deletions(-) diff --git a/tools/lammps-gui/chartviewer.cpp b/tools/lammps-gui/chartviewer.cpp index 0150133954..919a3bf5fe 100644 --- a/tools/lammps-gui/chartviewer.cpp +++ b/tools/lammps-gui/chartviewer.cpp @@ -253,7 +253,7 @@ void ChartWindow::closeEvent(QCloseEvent *event) bool ChartWindow::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::ShortcutOverride) { - QKeyEvent *keyEvent = dynamic_cast(event); + auto *keyEvent = dynamic_cast(event); if (!keyEvent) return QWidget::eventFilter(watched, event); if (keyEvent->modifiers().testFlag(Qt::ControlModifier) && keyEvent->key() == '/') { stop_run(); diff --git a/tools/lammps-gui/codeeditor.cpp b/tools/lammps-gui/codeeditor.cpp index ab8007805a..1762b0e496 100644 --- a/tools/lammps-gui/codeeditor.cpp +++ b/tools/lammps-gui/codeeditor.cpp @@ -620,7 +620,7 @@ void CodeEditor::dropEvent(QDropEvent *event) if (event->mimeData()->hasUrls()) { event->accept(); auto file = event->mimeData()->urls()[0].toLocalFile(); - auto gui = dynamic_cast(parent()); + auto *gui = dynamic_cast(parent()); if (gui) { moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor); gui->open_file(file); @@ -687,17 +687,17 @@ void CodeEditor::contextMenuEvent(QContextMenuEvent *event) auto *menu = createStandardContextMenu(); menu->addSeparator(); if (textCursor().hasSelection()) { - auto action1 = menu->addAction("Comment out selection"); + auto *action1 = menu->addAction("Comment out selection"); action1->setIcon(QIcon(":/icons/expand-text.png")); connect(action1, &QAction::triggered, this, &CodeEditor::comment_selection); - auto action2 = menu->addAction("Uncomment selection"); + auto *action2 = menu->addAction("Uncomment selection"); action2->setIcon(QIcon(":/icons/expand-text.png")); connect(action2, &QAction::triggered, this, &CodeEditor::uncomment_selection); } else { - auto action1 = menu->addAction("Comment out line"); + auto *action1 = menu->addAction("Comment out line"); action1->setIcon(QIcon(":/icons/expand-text.png")); connect(action1, &QAction::triggered, this, &CodeEditor::comment_line); - auto action2 = menu->addAction("Uncomment line"); + auto *action2 = menu->addAction("Uncomment line"); action2->setIcon(QIcon(":/icons/expand-text.png")); connect(action2, &QAction::triggered, this, &CodeEditor::uncomment_line); } @@ -705,14 +705,14 @@ void CodeEditor::contextMenuEvent(QContextMenuEvent *event) // print augmented context menu if an entry was found if (!help.isEmpty()) { - auto action = menu->addAction(QString("Display available completions for '%1'").arg(help)); + auto *action = menu->addAction(QString("Display available completions for '%1'").arg(help)); action->setIcon(QIcon(":/icons/expand-text.png")); connect(action, &QAction::triggered, this, &CodeEditor::runCompletion); menu->addSeparator(); } if (!page.isEmpty()) { - auto action = menu->addAction(QString("Reformat '%1' command").arg(help)); + auto *action = menu->addAction(QString("Reformat '%1' command").arg(help)); action->setIcon(QIcon(":/icons/format-indent-less-3.png")); connect(action, &QAction::triggered, this, &CodeEditor::reformatCurrentLine); @@ -728,13 +728,13 @@ void CodeEditor::contextMenuEvent(QContextMenuEvent *event) help = words.at(0); page = words.at(0); page += ".html"; - auto action2 = menu->addAction(QString("View Documentation for '%1'").arg(help)); + auto *action2 = menu->addAction(QString("View Documentation for '%1'").arg(help)); action2->setIcon(QIcon(":/icons/system-help.png")); action2->setData(page); connect(action2, &QAction::triggered, this, &CodeEditor::open_help); } } - auto action = menu->addAction(QString("LAMMPS Manual")); + auto *action = menu->addAction(QString("LAMMPS Manual")); action->setIcon(QIcon(":/icons/help-browser.png")); action->setData(QString()); connect(action, &QAction::triggered, this, &CodeEditor::open_help); @@ -1166,7 +1166,7 @@ void CodeEditor::find_help(QString &page, QString &help) void CodeEditor::open_help() { - QAction *act = qobject_cast(sender()); + auto *act = qobject_cast(sender()); QDesktopServices::openUrl( QUrl(QString("https://docs.lammps.org/%1").arg(act->data().toString()))); } diff --git a/tools/lammps-gui/helpers.cpp b/tools/lammps-gui/helpers.cpp index 8db7cd0d68..bc158f3bb5 100644 --- a/tools/lammps-gui/helpers.cpp +++ b/tools/lammps-gui/helpers.cpp @@ -21,7 +21,7 @@ // duplicate string, STL version char *mystrdup(const std::string &text) { - auto tmp = new char[text.size() + 1]; + auto *tmp = new char[text.size() + 1]; memcpy(tmp, text.c_str(), text.size() + 1); return tmp; } diff --git a/tools/lammps-gui/imageviewer.cpp b/tools/lammps-gui/imageviewer.cpp index 1d00dd7c1d..faa18d7faf 100644 --- a/tools/lammps-gui/imageviewer.cpp +++ b/tools/lammps-gui/imageviewer.cpp @@ -143,7 +143,7 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge scrollArea->setWidget(imageLabel); scrollArea->setVisible(false); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; QSettings settings; @@ -223,7 +223,7 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge combo->addItem(gname); } - QHBoxLayout *menuLayout = new QHBoxLayout; + auto *menuLayout = new QHBoxLayout; menuLayout->addWidget(menuBar); menuLayout->addWidget(renderstatus); menuLayout->addWidget(new QLabel(" Width: ")); @@ -324,7 +324,7 @@ void ImageViewer::reset_view() void ImageViewer::edit_size() { - QSpinBox *field = qobject_cast(sender()); + auto *field = qobject_cast(sender()); if (field->objectName() == "xsize") { xsize = field->value(); } else if (field->objectName() == "ysize") { @@ -335,7 +335,7 @@ void ImageViewer::edit_size() void ImageViewer::toggle_ssao() { - QPushButton *button = qobject_cast(sender()); + auto *button = qobject_cast(sender()); usessao = !usessao; button->setChecked(usessao); createImage(); @@ -343,7 +343,7 @@ void ImageViewer::toggle_ssao() void ImageViewer::toggle_anti() { - QPushButton *button = qobject_cast(sender()); + auto *button = qobject_cast(sender()); antialias = !antialias; button->setChecked(antialias); createImage(); @@ -351,7 +351,7 @@ void ImageViewer::toggle_anti() void ImageViewer::toggle_vdw() { - QPushButton *button = qobject_cast(sender()); + auto *button = qobject_cast(sender()); if (vdwfactor > 1.0) vdwfactor = 0.5; else @@ -362,7 +362,7 @@ void ImageViewer::toggle_vdw() void ImageViewer::toggle_box() { - QPushButton *button = qobject_cast(sender()); + auto *button = qobject_cast(sender()); showbox = !showbox; button->setChecked(showbox); createImage(); @@ -370,7 +370,7 @@ void ImageViewer::toggle_box() void ImageViewer::toggle_axes() { - QPushButton *button = qobject_cast(sender()); + auto *button = qobject_cast(sender()); showaxes = !showaxes; button->setChecked(showaxes); createImage(); @@ -420,14 +420,14 @@ void ImageViewer::do_rot_up() void ImageViewer::change_group(int) { - QComboBox *box = findChild("group"); + auto *box = findChild("group"); if (box) group = box->currentText(); createImage(); } void ImageViewer::createImage() { - QLabel *renderstatus = findChild("renderstatus"); + auto *renderstatus = findChild("renderstatus"); if (renderstatus) renderstatus->setEnabled(true); repaint(); @@ -443,7 +443,7 @@ void ImageViewer::createImage() // determine elements from masses and set their covalent radii int ntypes = lammps->extract_setting("ntypes"); int nbondtypes = lammps->extract_setting("nbondtypes"); - double *masses = (double *)lammps->extract_atom("mass"); + auto *masses = (double *)lammps->extract_atom("mass"); QString units = (const char *)lammps->extract_global("units"); QString elements = "element "; QString adiams; diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index a78d891318..1d132003b2 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -300,14 +300,14 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) : const char *varstyles[] = {"delete", "atomfile", "file", "format", "getenv", "index", "internal", "loop", "python", "string", "timer", "uloop", "universe", "world", "equal", "vector", "atom"}; - for (const auto var : varstyles) + for (const auto *const var : varstyles) style_list << var; style_list.sort(); ui->textEdit->setVariableList(style_list); style_list.clear(); const char *unitstyles[] = {"lj", "real", "metal", "si", "cgs", "electron", "micro", "nano"}; - for (const auto unit : unitstyles) + for (const auto *const unit : unitstyles) style_list << unit; style_list.sort(); ui->textEdit->setUnitsList(style_list); @@ -392,14 +392,14 @@ void LammpsGui::open() void LammpsGui::open_recent() { - QAction *act = qobject_cast(sender()); + auto *act = qobject_cast(sender()); if (act) open_file(act->data().toString()); } void LammpsGui::start_exe() { if (!lammps.extract_setting("box_exists")) return; - QAction *act = qobject_cast(sender()); + auto *act = qobject_cast(sender()); if (act) { auto exe = act->data().toString(); QString datacmd = "write_data '"; @@ -1052,7 +1052,7 @@ void LammpsGui::do_run(bool use_buffer) logwindow->document()->setDefaultFont(text_font); logwindow->setLineWrapMode(LogWindow::NoWrap); logwindow->setMinimumSize(400, 300); - QShortcut *shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), logwindow); + auto *shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), logwindow); QObject::connect(shortcut, &QShortcut::activated, logwindow, &LogWindow::close); shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), logwindow); QObject::connect(shortcut, &QShortcut::activated, this, &LammpsGui::stop_run); @@ -1244,7 +1244,7 @@ void LammpsGui::about() msg.setFont(font); auto *minwidth = new QSpacerItem(700, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); - QGridLayout *layout = (QGridLayout *)msg.layout(); + auto *layout = (QGridLayout *)msg.layout(); layout->addItem(minwidth, layout->rowCount(), 0, 1, layout->columnCount()); msg.exec(); diff --git a/tools/lammps-gui/logwindow.cpp b/tools/lammps-gui/logwindow.cpp index 73ec81d06c..05887c329c 100644 --- a/tools/lammps-gui/logwindow.cpp +++ b/tools/lammps-gui/logwindow.cpp @@ -35,7 +35,7 @@ LogWindow::LogWindow(const QString &_filename, QWidget *parent) : QSettings settings; resize(settings.value("logx", 500).toInt(), settings.value("logy", 320).toInt()); - auto action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_S), this); + auto *action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_S), this); connect(action, &QShortcut::activated, this, &LogWindow::save_as); action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this); connect(action, &QShortcut::activated, this, &LogWindow::quit); @@ -99,7 +99,7 @@ void LogWindow::contextMenuEvent(QContextMenuEvent *event) // show augmented context menu auto *menu = createStandardContextMenu(); menu->addSeparator(); - auto action = menu->addAction(QString("Save Log to File ...")); + auto *action = menu->addAction(QString("Save Log to File ...")); action->setIcon(QIcon(":/icons/document-save-as.png")); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S)); connect(action, &QAction::triggered, this, &LogWindow::save_as); @@ -114,7 +114,7 @@ void LogWindow::contextMenuEvent(QContextMenuEvent *event) bool LogWindow::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::ShortcutOverride) { - QKeyEvent *keyEvent = dynamic_cast(event); + auto *keyEvent = dynamic_cast(event); if (!keyEvent) return QWidget::eventFilter(watched, event); if (keyEvent->modifiers().testFlag(Qt::ControlModifier) && keyEvent->key() == '/') { stop_run(); diff --git a/tools/lammps-gui/preferences.cpp b/tools/lammps-gui/preferences.cpp index 27cc106008..71910346fb 100644 --- a/tools/lammps-gui/preferences.cpp +++ b/tools/lammps-gui/preferences.cpp @@ -93,25 +93,25 @@ void Preferences::accept() // store selected accelerator QList allButtons = tabWidget->findChildren(); - for (int i = 0; i < allButtons.size(); ++i) { - if (allButtons[i]->isChecked()) { - if (allButtons[i]->objectName() == "none") + for (auto & allButton : allButtons) { + if (allButton->isChecked()) { + if (allButton->objectName() == "none") settings->setValue("accelerator", QString::number(AcceleratorTab::None)); - if (allButtons[i]->objectName() == "opt") + if (allButton->objectName() == "opt") settings->setValue("accelerator", QString::number(AcceleratorTab::Opt)); - if (allButtons[i]->objectName() == "openmp") + if (allButton->objectName() == "openmp") settings->setValue("accelerator", QString::number(AcceleratorTab::OpenMP)); - if (allButtons[i]->objectName() == "intel") + if (allButton->objectName() == "intel") settings->setValue("accelerator", QString::number(AcceleratorTab::Intel)); - if (allButtons[i]->objectName() == "kokkos") + if (allButton->objectName() == "kokkos") settings->setValue("accelerator", QString::number(AcceleratorTab::Kokkos)); - if (allButtons[i]->objectName() == "gpu") + if (allButton->objectName() == "gpu") settings->setValue("accelerator", QString::number(AcceleratorTab::Gpu)); } } // store number of threads, reset to 1 for "None" and "Opt" settings - QLineEdit *field = tabWidget->findChild("nthreads"); + auto *field = tabWidget->findChild("nthreads"); if (field) { int accel = settings->value("accelerator", AcceleratorTab::None).toInt(); if ((accel == AcceleratorTab::None) || (accel == AcceleratorTab::Opt)) @@ -132,7 +132,7 @@ void Preferences::accept() field = tabWidget->findChild("zoom"); if (field) if (field->hasAcceptableInput()) settings->setValue("zoom", field->text()); - QCheckBox *box = tabWidget->findChild("anti"); + auto *box = tabWidget->findChild("anti"); if (box) settings->setValue("antialias", box->isChecked()); box = tabWidget->findChild("ssao"); if (box) settings->setValue("ssao", box->isChecked()); @@ -142,7 +142,7 @@ void Preferences::accept() if (box) settings->setValue("axes", box->isChecked()); box = tabWidget->findChild("vdwstyle"); if (box) settings->setValue("vdwstyle", box->isChecked()); - QComboBox *combo = tabWidget->findChild("background"); + auto *combo = tabWidget->findChild("background"); if (combo) settings->setValue("background", combo->currentText()); combo = tabWidget->findChild("boxcolor"); if (combo) settings->setValue("boxcolor", combo->currentText()); @@ -166,7 +166,7 @@ void Preferences::accept() box = tabWidget->findChild("viewslide"); if (box) settings->setValue("viewslide", box->isChecked()); - auto spin = tabWidget->findChild("updfreq"); + auto *spin = tabWidget->findChild("updfreq"); if (spin) settings->setValue("updfreq", spin->value()); if (need_relaunch) { @@ -324,7 +324,7 @@ void GeneralTab::newtextfont() void GeneralTab::pluginpath() { - QLineEdit *field = findChild("pluginedit"); + auto *field = findChild("pluginedit"); QString pluginfile = QFileDialog::getOpenFileName(this, "Select Shared LAMMPS Library to Load", field->text(), "Shared Objects (*.so *.dll *.dylib)"); diff --git a/tools/lammps-gui/slideshow.cpp b/tools/lammps-gui/slideshow.cpp index 140c703ca3..9275842b78 100644 --- a/tools/lammps-gui/slideshow.cpp +++ b/tools/lammps-gui/slideshow.cpp @@ -281,7 +281,7 @@ void SlideShow::play() } // reset push button state. use findChild() if not triggered from button. - QPushButton *button = qobject_cast(sender()); + auto *button = qobject_cast(sender()); if (!button) button = findChild("play"); if (button) button->setChecked(playtimer); } @@ -315,7 +315,7 @@ void SlideShow::prev() void SlideShow::loop() { - QPushButton *button = qobject_cast(sender()); + auto *button = qobject_cast(sender()); do_loop = !do_loop; button->setChecked(do_loop); } From da2bd44b73684ce2eac70218db8f11a750b63542 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 4 Jul 2024 11:17:54 -0400 Subject: [PATCH 161/385] modernize and reformat with clang-tidy and clang-format --- unittest/c-library/test_library_commands.cpp | 5 +- unittest/c-library/test_library_external.cpp | 14 +- unittest/c-library/test_library_mpi.cpp | 28 +-- unittest/c-library/test_library_objects.cpp | 46 ++-- unittest/c-library/test_library_open.cpp | 17 +- .../c-library/test_library_properties.cpp | 24 +- .../c-library/test_library_scatter_gather.cpp | 16 +- unittest/commands/test_compute_chunk.cpp | 60 ++--- unittest/commands/test_compute_global.cpp | 52 ++--- unittest/commands/test_groups.cpp | 6 +- unittest/commands/test_labelmap.cpp | 4 +- unittest/commands/test_lattice_region.cpp | 24 +- unittest/commands/test_regions.cpp | 24 +- unittest/commands/test_reset_atoms.cpp | 20 +- unittest/commands/test_set_property.cpp | 6 +- unittest/commands/test_variables.cpp | 5 +- unittest/cplusplus/test_input_class.cpp | 6 +- unittest/cplusplus/test_lammps_class.cpp | 24 +- unittest/force-styles/test_angle_style.cpp | 36 +-- unittest/force-styles/test_bond_style.cpp | 39 ++-- unittest/force-styles/test_config.h | 2 +- unittest/force-styles/test_config_reader.h | 4 +- unittest/force-styles/test_dihedral_style.cpp | 33 ++- unittest/force-styles/test_fix_timestep.cpp | 34 +-- unittest/force-styles/test_improper_style.cpp | 30 +-- unittest/force-styles/test_main.cpp | 2 +- unittest/force-styles/test_main.h | 16 +- unittest/force-styles/test_pair_style.cpp | 36 +-- unittest/force-styles/yaml_writer.h | 6 +- unittest/formats/compressed_dump_test.h | 4 +- unittest/formats/test_atom_styles.cpp | 206 +++++++++--------- .../formats/test_dump_atom_compressed.cpp | 102 ++++----- unittest/formats/test_dump_cfg.cpp | 24 +- unittest/formats/test_dump_cfg_compressed.cpp | 114 +++++----- unittest/formats/test_dump_custom.cpp | 50 +++-- .../formats/test_dump_custom_compressed.cpp | 119 +++++----- unittest/formats/test_dump_local.cpp | 20 +- .../formats/test_dump_local_compressed.cpp | 148 ++++++------- unittest/formats/test_dump_netcdf.cpp | 8 +- unittest/formats/test_dump_xyz_compressed.cpp | 90 ++++---- unittest/formats/test_file_operations.cpp | 8 +- unittest/formats/test_image_flags.cpp | 16 +- .../formats/test_potential_file_reader.cpp | 26 +-- unittest/formats/test_text_file_reader.cpp | 16 +- unittest/fortran/wrap_configuration.cpp | 4 +- unittest/fortran/wrap_create.cpp | 16 +- unittest/fortran/wrap_create_atoms.cpp | 158 +++++++------- unittest/fortran/wrap_extract_fix.cpp | 8 +- unittest/fortran/wrap_fixexternal.cpp | 77 +++---- unittest/fortran/wrap_gather_scatter.cpp | 22 +- unittest/fortran/wrap_neighlist.cpp | 63 +++--- unittest/testing/core.h | 2 +- unittest/utils/test_lepton.cpp | 5 +- unittest/utils/test_lmptype.cpp | 10 +- unittest/utils/test_math_eigen_impl.cpp | 16 +- 55 files changed, 980 insertions(+), 971 deletions(-) diff --git a/unittest/c-library/test_library_commands.cpp b/unittest/c-library/test_library_commands.cpp index 31f8268a8f..4abb42cae2 100644 --- a/unittest/c-library/test_library_commands.cpp +++ b/unittest/c-library/test_library_commands.cpp @@ -25,9 +25,8 @@ protected: void SetUp() override { - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", - "-var", "x", "2", "-var", "zpos", "1.5", - nullptr}; + const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", "-var", + "x", "2", "-var", "zpos", "1.5", nullptr}; char **argv = (char **)args; int argc = (sizeof(args) / sizeof(char *)) - 1; diff --git a/unittest/c-library/test_library_external.cpp b/unittest/c-library/test_library_external.cpp index 9011ac19a8..606d53d38b 100644 --- a/unittest/c-library/test_library_external.cpp +++ b/unittest/c-library/test_library_external.cpp @@ -18,8 +18,8 @@ extern "C" { typedef int32_t step_t; typedef int32_t tag_t; #elif LAMMPS_SMALLBIG -typedef int64_t step_t; -typedef int32_t tag_t; +using step_t = int64_t; +using tag_t = int32_t; #else typedef int64_t step_t; typedef int64_t tag_t; @@ -42,10 +42,10 @@ static void callback(void *handle, step_t timestep, int nlocal, tag_t *, double lammps_fix_external_set_vector(handle, "ext", 5, -1.0); lammps_fix_external_set_vector(handle, "ext", 6, 0.25); } - double *eatom = new double[nlocal]; - double **vatom = new double *[nlocal]; - vatom[0] = new double[nlocal * 6]; - eatom[0] = 0.0; + auto *eatom = new double[nlocal]; + auto **vatom = new double *[nlocal]; + vatom[0] = new double[nlocal * 6]; + eatom[0] = 0.0; vatom[0][0] = vatom[0][1] = vatom[0][2] = vatom[0][3] = vatom[0][4] = vatom[0][5] = 0.0; for (int i = 1; i < nlocal; ++i) { @@ -107,7 +107,7 @@ TEST(lammps_external, callback) val += *valp; lammps_free(valp); } - double *reduce = + auto *reduce = (double *)lammps_extract_compute(handle, "sum", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR); output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; diff --git a/unittest/c-library/test_library_mpi.cpp b/unittest/c-library/test_library_mpi.cpp index f60105a229..f2e8ba1c8c 100644 --- a/unittest/c-library/test_library_mpi.cpp +++ b/unittest/c-library/test_library_mpi.cpp @@ -97,8 +97,8 @@ TEST(MPI, sub_box) EXPECT_EQ(boxhi[1], 2.0); EXPECT_EQ(boxhi[2], 2.0); - double *sublo = (double *)lammps_extract_global(lmp, "sublo"); - double *subhi = (double *)lammps_extract_global(lmp, "subhi"); + auto *sublo = (double *)lammps_extract_global(lmp, "sublo"); + auto *subhi = (double *)lammps_extract_global(lmp, "subhi"); ASSERT_NE(sublo, nullptr); ASSERT_NE(subhi, nullptr); @@ -172,8 +172,8 @@ TEST(MPI, multi_partition) MPI_Comm_size(MPI_COMM_WORLD, &nprocs); MPI_Comm_rank(MPI_COMM_WORLD, &me); - const char *args[] = {"LAMMPS_test", "-log", "none", "-partition", "4x1", - "-echo", "screen", "-nocite", "-in", "none", nullptr}; + const char *args[] = {"LAMMPS_test", "-log", "none", "-partition", "4x1", "-echo", + "screen", "-nocite", "-in", "none", nullptr}; char **argv = (char **)args; int argc = (sizeof(args) / sizeof(char *)) - 1; void *lmp = lammps_open(argc, argv, MPI_COMM_WORLD, nullptr); @@ -258,7 +258,7 @@ TEST_F(MPITest, size_rank) TEST_F(MPITest, gather) { - int64_t natoms = (int64_t)lammps_get_natoms(lmp); + auto natoms = (int64_t)lammps_get_natoms(lmp); ASSERT_EQ(natoms, 32); int *p_nlocal = (int *)lammps_extract_global(lmp, "nlocal"); int nlocal = *p_nlocal; @@ -266,11 +266,11 @@ TEST_F(MPITest, gather) EXPECT_EQ(nlocal, 8); // get the entire x on all procs - double *x = new double[natoms * 3]; + auto *x = new double[natoms * 3]; lammps_gather(lmp, (char *)"x", 1, 3, x); - int *tag = (int *)lammps_extract_atom(lmp, "id"); - double **x_local = (double **)lammps_extract_atom(lmp, "x"); + int *tag = (int *)lammps_extract_atom(lmp, "id"); + auto **x_local = (double **)lammps_extract_atom(lmp, "x"); // each proc checks its local atoms for (int i = 0; i < nlocal; i++) { @@ -287,10 +287,10 @@ TEST_F(MPITest, gather) TEST_F(MPITest, scatter) { - int *p_nlocal = (int *)lammps_extract_global(lmp, "nlocal"); - int nlocal = *p_nlocal; - double *x_orig = new double[3 * nlocal]; - double **x_local = (double **)lammps_extract_atom(lmp, "x"); + int *p_nlocal = (int *)lammps_extract_global(lmp, "nlocal"); + int nlocal = *p_nlocal; + auto *x_orig = new double[3 * nlocal]; + auto **x_local = (double **)lammps_extract_atom(lmp, "x"); // make copy of original local x vector for (int i = 0; i < nlocal; i++) { @@ -301,8 +301,8 @@ TEST_F(MPITest, scatter) } // get the entire x on all procs - int64_t natoms = (int64_t)lammps_get_natoms(lmp); - double *x = new double[natoms * 3]; + auto natoms = (int64_t)lammps_get_natoms(lmp); + auto *x = new double[natoms * 3]; lammps_gather(lmp, (char *)"x", 1, 3, x); // shift all coordinates by 0.001 diff --git a/unittest/c-library/test_library_objects.cpp b/unittest/c-library/test_library_objects.cpp index d224c76225..9d30492be3 100644 --- a/unittest/c-library/test_library_objects.cpp +++ b/unittest/c-library/test_library_objects.cpp @@ -112,75 +112,75 @@ TEST_F(LibraryObjects, variables) if (verbose) std::cout << output; EXPECT_EQ(lammps_extract_variable_datatype(lmp, "unknown"), -1); - void *ptr = lammps_extract_variable(lmp, "unknown", NULL); + void *ptr = lammps_extract_variable(lmp, "unknown", nullptr); EXPECT_EQ(ptr, nullptr); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "one"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "one", NULL); + ptr = lammps_extract_variable(lmp, "one", nullptr); EXPECT_NE(ptr, nullptr); EXPECT_THAT((char *)ptr, StrEq("1")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "two"), LMP_VAR_EQUAL); - ptr = lammps_extract_variable(lmp, "two", NULL); + ptr = lammps_extract_variable(lmp, "two", nullptr); EXPECT_NE(ptr, nullptr); EXPECT_THAT(*(double *)ptr, 2.0); lammps_free(ptr); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "three"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "three", NULL); + ptr = lammps_extract_variable(lmp, "three", nullptr); EXPECT_THAT((char *)ptr, StrEq("three")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "four1"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "four1", NULL); + ptr = lammps_extract_variable(lmp, "four1", nullptr); EXPECT_THAT((char *)ptr, StrEq("1")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "four2"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "four2", NULL); + ptr = lammps_extract_variable(lmp, "four2", nullptr); EXPECT_THAT((char *)ptr, StrEq("2")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "five1"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "five1", NULL); + ptr = lammps_extract_variable(lmp, "five1", nullptr); EXPECT_THAT((char *)ptr, StrEq("001")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "five2"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "five2", NULL); + ptr = lammps_extract_variable(lmp, "five2", nullptr); EXPECT_THAT((char *)ptr, StrEq("010")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "six"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "six", NULL); + ptr = lammps_extract_variable(lmp, "six", nullptr); EXPECT_THAT((char *)ptr, StrEq("one")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "seven"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "seven", NULL); + ptr = lammps_extract_variable(lmp, "seven", nullptr); EXPECT_THAT((char *)ptr, StrEq(" 2.00")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "eight"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "eight", NULL); + ptr = lammps_extract_variable(lmp, "eight", nullptr); EXPECT_THAT((char *)ptr, StrEq("")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "nine"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "nine", NULL); + ptr = lammps_extract_variable(lmp, "nine", nullptr); EXPECT_THAT((char *)ptr, StrEq("one")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten"), LMP_VAR_EQUAL); - ptr = lammps_extract_variable(lmp, "ten", NULL); + ptr = lammps_extract_variable(lmp, "ten", nullptr); EXPECT_THAT(*(double *)ptr, 1.0); lammps_free(ptr); variable->internal_set(variable->find("ten"), 2.5); - ptr = lammps_extract_variable(lmp, "ten", NULL); + ptr = lammps_extract_variable(lmp, "ten", nullptr); EXPECT_THAT(*(double *)ptr, 2.5); lammps_free(ptr); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten1"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "ten1", NULL); + ptr = lammps_extract_variable(lmp, "ten1", nullptr); EXPECT_THAT((char *)ptr, StrEq("1")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten2"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "ten2", NULL); + ptr = lammps_extract_variable(lmp, "ten2", nullptr); EXPECT_THAT((char *)ptr, StrEq("1")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten3"), LMP_VAR_STRING); - ptr = lammps_extract_variable(lmp, "ten3", NULL); + ptr = lammps_extract_variable(lmp, "ten3", nullptr); EXPECT_THAT((char *)ptr, StrEq("1")); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten4"), LMP_VAR_VECTOR); - ptr = lammps_extract_variable(lmp, "ten4", (const char *)1); - double *dptr = (double *)lammps_extract_variable(lmp, "ten4", NULL); + ptr = lammps_extract_variable(lmp, "ten4", (const char *)1); + auto *dptr = (double *)lammps_extract_variable(lmp, "ten4", nullptr); EXPECT_EQ((*(int *)ptr), 7); lammps_free(ptr); EXPECT_EQ(dptr[0], 0); EXPECT_EQ(dptr[4], 5); EXPECT_EQ(dptr[6], 11); EXPECT_EQ(lammps_extract_variable_datatype(lmp, "ten5"), LMP_VAR_VECTOR); - ptr = lammps_extract_variable(lmp, "ten5", (const char *)1); - dptr = (double *)lammps_extract_variable(lmp, "ten5", NULL); + ptr = lammps_extract_variable(lmp, "ten5", (const char *)1); + dptr = (double *)lammps_extract_variable(lmp, "ten5", nullptr); EXPECT_EQ((*(int *)ptr), 2); lammps_free(ptr); EXPECT_EQ(dptr[0], 0.5); @@ -196,10 +196,10 @@ TEST_F(LibraryObjects, variables) EXPECT_THAT(*(double *)ptr, 0.0); lammps_free(ptr); #elif defined(__linux__) - ptr = lammps_extract_variable(lmp, "iswin", NULL); + ptr = lammps_extract_variable(lmp, "iswin", nullptr); EXPECT_THAT(*(double *)ptr, 0.0); lammps_free(ptr); - ptr = lammps_extract_variable(lmp, "islin", NULL); + ptr = lammps_extract_variable(lmp, "islin", nullptr); EXPECT_THAT(*(double *)ptr, 1.0); lammps_free(ptr); #else diff --git a/unittest/c-library/test_library_open.cpp b/unittest/c-library/test_library_open.cpp index 267f8e0978..426b2adaa7 100644 --- a/unittest/c-library/test_library_open.cpp +++ b/unittest/c-library/test_library_open.cpp @@ -25,7 +25,7 @@ TEST(lammps_open, null_args) int mpi_init = 0; MPI_Initialized(&mpi_init); EXPECT_GT(mpi_init, 0); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); EXPECT_EQ(lmp->infile, stdin); EXPECT_EQ(lmp->screen, stdout); @@ -53,7 +53,7 @@ TEST(lammps_open, with_args) EXPECT_THAT(output, StartsWith("LAMMPS (")); if (verbose) std::cout << output; EXPECT_EQ(handle, alt_ptr); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; // MPI STUBS uses no real communicators #if !defined(MPI_STUBS) @@ -89,7 +89,7 @@ TEST(lammps_open, with_kokkos) EXPECT_THAT(output, StartsWith("LAMMPS (")); if (verbose) std::cout << output; EXPECT_EQ(handle, alt_ptr); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); EXPECT_EQ(lmp->infile, stdin); @@ -118,7 +118,7 @@ TEST(lammps_open_no_mpi, no_screen) std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.c_str(), ""); EXPECT_EQ(handle, alt_ptr); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); EXPECT_EQ(lmp->infile, stdin); @@ -138,7 +138,7 @@ TEST(lammps_open_no_mpi, no_screen) TEST(lammps_open_no_mpi, with_omp) { if (!LAMMPS_NS::LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); - const char *args[] = {"liblammps", "-pk", "omp", "2", "neigh", "no", + const char *args[] = {"liblammps", "-pk", "omp", "2", "neigh", "no", "-sf", "omp", "-log", "none", "-nocite", nullptr}; char **argv = (char **)args; int argc = (sizeof(args) / sizeof(char *)) - 1; @@ -150,7 +150,7 @@ TEST(lammps_open_no_mpi, with_omp) EXPECT_THAT(output, StartsWith("LAMMPS (")); if (verbose) std::cout << output; EXPECT_EQ(handle, alt_ptr); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); EXPECT_EQ(lmp->infile, stdin); @@ -179,7 +179,7 @@ TEST(lammps_open_fortran, no_args) std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, StartsWith("LAMMPS (")); if (verbose) std::cout << output; - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; // MPI STUBS uses no real communicators #if !defined(MPI_STUBS) @@ -210,7 +210,7 @@ TEST(lammps_open_no_mpi, lammps_error) void *handle = lammps_open_no_mpi(argc, argv, &alt_ptr); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_EQ(handle, alt_ptr); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); EXPECT_EQ(lmp->infile, stdin); @@ -226,4 +226,3 @@ TEST(lammps_open_no_mpi, lammps_error) output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, HasSubstr("WARNING: test_warning")); } - diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index 804853194b..043b6c08d9 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -376,18 +376,18 @@ TEST_F(LibraryProperties, global) EXPECT_EQ((*i_ptr), 2); #else EXPECT_EQ(lammps_extract_global_datatype(lmp, "ntimestep"), LAMMPS_INT64); - int64_t *b_ptr = (int64_t *)lammps_extract_global(lmp, "ntimestep"); + auto *b_ptr = (int64_t *)lammps_extract_global(lmp, "ntimestep"); EXPECT_EQ((*b_ptr), 2); #endif EXPECT_EQ(lammps_extract_global_datatype(lmp, "dt"), LAMMPS_DOUBLE); - double *d_ptr = (double *)lammps_extract_global(lmp, "dt"); + auto *d_ptr = (double *)lammps_extract_global(lmp, "dt"); EXPECT_DOUBLE_EQ((*d_ptr), 0.1); EXPECT_EQ(lammps_extract_global_datatype(lmp, "special_lj"), LAMMPS_DOUBLE); EXPECT_EQ(lammps_extract_global_datatype(lmp, "special_coul"), LAMMPS_DOUBLE); - double *special_lj = (double *)lammps_extract_global(lmp, "special_lj"); - double *special_coul = (double *)lammps_extract_global(lmp, "special_coul"); + auto *special_lj = (double *)lammps_extract_global(lmp, "special_lj"); + auto *special_coul = (double *)lammps_extract_global(lmp, "special_coul"); EXPECT_DOUBLE_EQ(special_lj[0], 1.0); EXPECT_DOUBLE_EQ(special_lj[1], 0.0); EXPECT_DOUBLE_EQ(special_lj[2], 0.5); @@ -418,14 +418,14 @@ TEST_F(LibraryProperties, global) EXPECT_EQ(map_style, Atom::MAP_ARRAY); EXPECT_NE(sametag, nullptr); - tagint *tags = (tagint *)lammps_extract_atom(lmp, "id"); + auto *tags = (tagint *)lammps_extract_atom(lmp, "id"); tagint sometags[] = {1, 5, 10, 15, 20}; - for (int i = 0; i < 5; ++i) { - int idx = lammps_map_atom(lmp, (const void *)&sometags[i]); - EXPECT_EQ(sometags[i], tags[idx]); + for (int &sometag : sometags) { + int idx = lammps_map_atom(lmp, (const void *)&sometag); + EXPECT_EQ(sometag, tags[idx]); int nextidx = sametag[idx]; if (nextidx >= 0) { - EXPECT_EQ(sometags[i], tags[nextidx]); + EXPECT_EQ(sometag, tags[nextidx]); } } @@ -655,7 +655,7 @@ TEST_F(AtomProperties, invalid) TEST_F(AtomProperties, mass) { EXPECT_EQ(lammps_extract_atom_datatype(lmp, "mass"), LAMMPS_DOUBLE); - double *mass = (double *)lammps_extract_atom(lmp, "mass"); + auto *mass = (double *)lammps_extract_atom(lmp, "mass"); ASSERT_NE(mass, nullptr); ASSERT_DOUBLE_EQ(mass[1], 3.0); } @@ -663,7 +663,7 @@ TEST_F(AtomProperties, mass) TEST_F(AtomProperties, id) { EXPECT_EQ(lammps_extract_atom_datatype(lmp, "id"), LAMMPS_TAGINT); - tagint *id = (tagint *)lammps_extract_atom(lmp, "id"); + auto *id = (tagint *)lammps_extract_atom(lmp, "id"); ASSERT_NE(id, nullptr); ASSERT_EQ(id[0], 1); ASSERT_EQ(id[1], 2); @@ -681,7 +681,7 @@ TEST_F(AtomProperties, type) TEST_F(AtomProperties, position) { EXPECT_EQ(lammps_extract_atom_datatype(lmp, "x"), LAMMPS_DOUBLE_2D); - double **x = (double **)lammps_extract_atom(lmp, "x"); + auto **x = (double **)lammps_extract_atom(lmp, "x"); ASSERT_NE(x, nullptr); EXPECT_DOUBLE_EQ(x[0][0], 1.0); EXPECT_DOUBLE_EQ(x[0][1], 1.0); diff --git a/unittest/c-library/test_library_scatter_gather.cpp b/unittest/c-library/test_library_scatter_gather.cpp index 0303a47337..62a7ed1d3a 100644 --- a/unittest/c-library/test_library_scatter_gather.cpp +++ b/unittest/c-library/test_library_scatter_gather.cpp @@ -67,7 +67,7 @@ TEST_F(GatherProperties, gather_bonds_newton_on) bigint nbonds = *(bigint *)lammps_extract_global(lmp, "nbonds"); EXPECT_EQ(nbonds, 24); - tagint *bonds = new tagint[3 * nbonds]; + auto *bonds = new tagint[3 * nbonds]; lammps_gather_bonds(lmp, bonds); #define CHECK_BOND(idx, type, atom1, atom2) \ @@ -108,7 +108,7 @@ TEST_F(GatherProperties, gather_bonds_newton_off) bigint nbonds = *(bigint *)lammps_extract_global(lmp, "nbonds"); EXPECT_EQ(nbonds, 24); - tagint *bonds = new tagint[3 * nbonds]; + auto *bonds = new tagint[3 * nbonds]; lammps_gather_bonds(lmp, bonds); #define CHECK_BOND(idx, type, atom1, atom2) \ @@ -149,7 +149,7 @@ TEST_F(GatherProperties, gather_angles_newton_on) bigint nangles = *(bigint *)lammps_extract_global(lmp, "nangles"); EXPECT_EQ(nangles, 30); - tagint *angles = new tagint[4 * nangles]; + auto *angles = new tagint[4 * nangles]; lammps_gather_angles(lmp, angles); #define CHECK_ANGLE(idx, type, atom1, atom2, atom3) \ @@ -192,7 +192,7 @@ TEST_F(GatherProperties, gather_angles_newton_off) bigint nangles = *(bigint *)lammps_extract_global(lmp, "nangles"); EXPECT_EQ(nangles, 30); - tagint *angles = new tagint[4 * nangles]; + auto *angles = new tagint[4 * nangles]; lammps_gather_angles(lmp, angles); #define CHECK_ANGLE(idx, type, atom1, atom2, atom3) \ @@ -235,7 +235,7 @@ TEST_F(GatherProperties, gather_dihedrals_newton_on) bigint ndihedrals = *(bigint *)lammps_extract_global(lmp, "ndihedrals"); EXPECT_EQ(ndihedrals, 31); - tagint *dihedrals = new tagint[5 * ndihedrals]; + auto *dihedrals = new tagint[5 * ndihedrals]; lammps_gather_dihedrals(lmp, dihedrals); #define CHECK_DIHEDRAL(idx, type, atom1, atom2, atom3, atom4) \ @@ -276,7 +276,7 @@ TEST_F(GatherProperties, gather_dihedrals_newton_off) bigint ndihedrals = *(bigint *)lammps_extract_global(lmp, "ndihedrals"); EXPECT_EQ(ndihedrals, 31); - tagint *dihedrals = new tagint[5 * ndihedrals]; + auto *dihedrals = new tagint[5 * ndihedrals]; lammps_gather_dihedrals(lmp, dihedrals); #define CHECK_DIHEDRAL(idx, type, atom1, atom2, atom3, atom4) \ @@ -316,7 +316,7 @@ TEST_F(GatherProperties, gather_impropers_newton_on) bigint nimpropers = *(bigint *)lammps_extract_global(lmp, "nimpropers"); EXPECT_EQ(nimpropers, 2); - tagint *impropers = new tagint[5 * nimpropers]; + auto *impropers = new tagint[5 * nimpropers]; lammps_gather_impropers(lmp, impropers); #define CHECK_IMPROPER(idx, type, atom1, atom2, atom3, atom4) \ @@ -349,7 +349,7 @@ TEST_F(GatherProperties, gather_impropers_newton_off) bigint nimpropers = *(bigint *)lammps_extract_global(lmp, "nimpropers"); EXPECT_EQ(nimpropers, 2); - tagint *impropers = new tagint[5 * nimpropers]; + auto *impropers = new tagint[5 * nimpropers]; lammps_gather_impropers(lmp, impropers); #define CHECK_IMPROPER(idx, type, atom1, atom2, atom3, atom4) \ diff --git a/unittest/commands/test_compute_chunk.cpp b/unittest/commands/test_compute_chunk.cpp index 8e919c0612..2a7f18e706 100644 --- a/unittest/commands/test_compute_chunk.cpp +++ b/unittest/commands/test_compute_chunk.cpp @@ -120,14 +120,14 @@ TEST_F(ComputeChunkTest, ChunkAtom) EXPECT_EQ(get_scalar("mols"), 6); EXPECT_EQ(get_scalar("types"), 5); - auto cbin1d = get_peratom("bin1d"); - auto cbin2d = get_peratom("bin2d"); - auto cbin3d = get_peratom("bin3d"); - auto cbinsph = get_peratom("binsph"); - auto cbincyl = get_peratom("bincyl"); - auto cmols = get_peratom("mols"); - auto ctypes = get_peratom("types"); - auto tag = get_peratom("tags"); + auto *cbin1d = get_peratom("bin1d"); + auto *cbin2d = get_peratom("bin2d"); + auto *cbin3d = get_peratom("bin3d"); + auto *cbinsph = get_peratom("binsph"); + auto *cbincyl = get_peratom("bincyl"); + auto *cmols = get_peratom("mols"); + auto *ctypes = get_peratom("types"); + auto *tag = get_peratom("tags"); for (int i = 0; i < natoms; ++i) { EXPECT_EQ(cbin1d[i], chunk1d[(int)tag[i]]); @@ -180,16 +180,16 @@ TEST_F(ComputeChunkTest, PropertyChunk) command("run 0 post no"); END_HIDE_OUTPUT(); - auto cprop1 = get_vector("prop1"); + auto *cprop1 = get_vector("prop1"); EXPECT_EQ(cprop1[0], 0); EXPECT_EQ(cprop1[1], 7); EXPECT_EQ(cprop1[2], 16); EXPECT_EQ(cprop1[3], 6); EXPECT_EQ(cprop1[4], 0); - auto cprop2 = get_vector("prop2"); - int nempty = 0; - int ncount = 0; + auto *cprop2 = get_vector("prop2"); + int nempty = 0; + int ncount = 0; for (int i = 0; i < 25; ++i) { if (cprop2[i] == 0) ++nempty; @@ -199,7 +199,7 @@ TEST_F(ComputeChunkTest, PropertyChunk) EXPECT_EQ(nempty, 17); EXPECT_EQ(ncount, 29); - auto cprop3 = get_array("prop3"); + auto *cprop3 = get_array("prop3"); EXPECT_EQ(cprop3[0][0], 34); EXPECT_EQ(cprop3[1][0], 38); EXPECT_EQ(cprop3[2][0], 43); @@ -250,15 +250,15 @@ TEST_F(ComputeChunkTest, ChunkComputes) command("fix hist2 all ave/time 1 1 1 c_tmp mode vector"); command("run 0 post no"); END_HIDE_OUTPUT(); - auto cang = get_array("ang"); - auto ccom = get_array("com"); - auto cdip = get_array("dip"); - auto cgyr = get_vector("gyr"); - auto cmom = get_array("mom"); - auto comg = get_array("omg"); - auto ctmp = get_vector("tmp"); - auto ctrq = get_array("trq"); - auto cvcm = get_array("vcm"); + auto *cang = get_array("ang"); + auto *ccom = get_array("com"); + auto *cdip = get_array("dip"); + auto *cgyr = get_vector("gyr"); + auto *cmom = get_array("mom"); + auto *comg = get_array("omg"); + auto *ctmp = get_vector("tmp"); + auto *ctrq = get_array("trq"); + auto *cvcm = get_array("vcm"); EXPECT_NEAR(cang[0][0], -0.01906982, EPSILON); EXPECT_NEAR(cang[0][1], -0.02814532, EPSILON); EXPECT_NEAR(cang[0][2], -0.03357393, EPSILON); @@ -329,7 +329,7 @@ TEST_F(ComputeChunkTest, ChunkTIP4PComputes) command("fix hist1 all ave/time 1 1 1 c_dip[*] mode vector"); command("run 0 post no"); END_HIDE_OUTPUT(); - auto cdip = get_array("dip"); + auto *cdip = get_array("dip"); EXPECT_NEAR(cdip[0][3], 0.35912150, EPSILON); EXPECT_NEAR(cdip[1][3], 0.68453713, EPSILON); EXPECT_NEAR(cdip[2][3], 0.50272643, EPSILON); @@ -358,11 +358,11 @@ TEST_F(ComputeChunkTest, ChunkSpreadGlobal) const int natoms = lammps_get_natoms(lmp); - auto cgyr = get_vector("gyr"); - auto cspr = get_peratom("spr"); - auto cglb = get_peratom("glb"); - auto codd = get_peratom("odd"); - auto ctag = get_peratom("tags"); + auto *cgyr = get_vector("gyr"); + auto *cspr = get_peratom("spr"); + auto *cglb = get_peratom("glb"); + auto *codd = get_peratom("odd"); + auto *ctag = get_peratom("tags"); for (int i = 0; i < natoms; ++i) { EXPECT_EQ(cspr[i], cgyr[chunkmol[(int)ctag[i]] - 1]); @@ -389,8 +389,8 @@ TEST_F(ComputeChunkTest, ChunkReduce) const int nchunks = get_scalar("mols"); - auto cprp = get_vector("prp"); - auto cred = get_vector("red"); + auto *cprp = get_vector("prp"); + auto *cred = get_vector("red"); for (int i = 0; i < nchunks; ++i) EXPECT_EQ(cprp[i], cred[i]); diff --git a/unittest/commands/test_compute_global.cpp b/unittest/commands/test_compute_global.cpp index d3d883a73e..282d1641bf 100644 --- a/unittest/commands/test_compute_global.cpp +++ b/unittest/commands/test_compute_global.cpp @@ -103,9 +103,9 @@ TEST_F(ComputeGlobalTest, Energy) EXPECT_NEAR(get_scalar("pr1"), 1956948.4735454607, 0.000000005); EXPECT_NEAR(get_scalar("pr2"), 1956916.7725807722, 0.000000005); EXPECT_DOUBLE_EQ(get_scalar("pr3"), 0.0); - auto pr1 = get_vector("pr1"); - auto pr2 = get_vector("pr2"); - auto pr3 = get_vector("pr3"); + auto *pr1 = get_vector("pr1"); + auto *pr2 = get_vector("pr2"); + auto *pr3 = get_vector("pr3"); EXPECT_NEAR(pr1[0], 2150600.9207200543, 0.000000005); EXPECT_NEAR(pr1[1], 1466949.7512112649, 0.000000005); EXPECT_NEAR(pr1[2], 2253294.7487050635, 0.000000005); @@ -127,7 +127,7 @@ TEST_F(ComputeGlobalTest, Energy) if (has_tally) { EXPECT_NEAR(get_scalar("pe4"), 15425.840923850392, 0.000000005); - auto pe5 = get_vector("pe5"); + auto *pe5 = get_vector("pe5"); EXPECT_NEAR(pe5[0], 23803.966677151559, 0.000000005); EXPECT_NEAR(pe5[1], -94.210004432380643, 0.000000005); EXPECT_NEAR(pe5[2], 115.58040355478101, 0.000000005); @@ -177,12 +177,12 @@ TEST_F(ComputeGlobalTest, Geometry) command("run 0 post no"); END_HIDE_OUTPUT(); - auto com1 = get_vector("com1"); - auto com2 = get_vector("com2"); - auto mu1 = get_vector("mu1"); - auto mu2 = get_vector("mu2"); - auto rg1 = get_vector("rg1"); - auto rg2 = get_vector("rg2"); + auto *com1 = get_vector("com1"); + auto *com2 = get_vector("com2"); + auto *mu1 = get_vector("mu1"); + auto *mu2 = get_vector("mu2"); + auto *rg1 = get_vector("rg1"); + auto *rg2 = get_vector("rg2"); EXPECT_NEAR(com1[0], 1.4300952724948282, 0.0000000005); EXPECT_NEAR(com1[1], -0.29759806705328351, 0.0000000005); @@ -215,10 +215,10 @@ TEST_F(ComputeGlobalTest, Geometry) EXPECT_NEAR(rg2[4], -5.0315240817290841, 0.0000000005); EXPECT_NEAR(rg2[5], 1.1103378503822141, 0.0000000005); if (has_extra) { - auto mom1 = get_vector("mom1"); - auto mom2 = get_vector("mom2"); - auto mop1 = get_vector("mop1"); - auto mop2 = get_array("mop2"); + auto *mom1 = get_vector("mom1"); + auto *mom2 = get_vector("mom2"); + auto *mop1 = get_vector("mop1"); + auto *mop2 = get_array("mop2"); EXPECT_DOUBLE_EQ(mom1[0], 0.0054219056685341164); EXPECT_DOUBLE_EQ(mom1[1], -0.054897225112275558); EXPECT_DOUBLE_EQ(mom1[2], 0.059097392692385661); @@ -263,11 +263,11 @@ TEST_F(ComputeGlobalTest, Reduction) command("run 0 post no"); END_HIDE_OUTPUT(); - auto min = get_vector("min"); - auto max = get_vector("max"); - auto sum = get_vector("sum"); - auto ave = get_vector("ave"); - auto rep = get_vector("rep"); + auto *min = get_vector("min"); + auto *max = get_vector("max"); + auto *sum = get_vector("sum"); + auto *ave = get_vector("ave"); + auto *rep = get_vector("rep"); EXPECT_DOUBLE_EQ(get_scalar("chg"), 0.51000000000000001); @@ -318,13 +318,13 @@ TEST_F(ComputeGlobalTest, Counts) command("run 0 post no"); END_HIDE_OUTPUT(); - auto tsum = get_vector("tsum"); - auto tcnt = get_vector("tcnt"); - auto bcnt = get_vector("bcnt"); - auto bbrk = get_scalar("bcnt"); - auto acnt = get_vector("acnt"); - auto dcnt = get_vector("dcnt"); - auto icnt = get_vector("icnt"); + auto *tsum = get_vector("tsum"); + auto *tcnt = get_vector("tcnt"); + auto *bcnt = get_vector("bcnt"); + auto bbrk = get_scalar("bcnt"); + auto *acnt = get_vector("acnt"); + auto *dcnt = get_vector("dcnt"); + auto *icnt = get_vector("icnt"); EXPECT_DOUBLE_EQ(tsum[0], tcnt[0]); EXPECT_DOUBLE_EQ(tsum[1], tcnt[1]); diff --git a/unittest/commands/test_groups.cpp b/unittest/commands/test_groups.cpp index 7f0a054c40..efeb00f685 100644 --- a/unittest/commands/test_groups.cpp +++ b/unittest/commands/test_groups.cpp @@ -341,9 +341,9 @@ TEST_F(GroupTest, VariableFunctions) int three = group->find("three"); int four = group->find("four"); - auto right = domain->get_region_by_id("right"); - auto left = domain->get_region_by_id("left"); - auto top = domain->get_region_by_id("top"); + auto *right = domain->get_region_by_id("right"); + auto *left = domain->get_region_by_id("left"); + auto *top = domain->get_region_by_id("top"); EXPECT_EQ(group->count_all(), 64); EXPECT_EQ(group->count(one), 16); diff --git a/unittest/commands/test_labelmap.cpp b/unittest/commands/test_labelmap.cpp index ebdab08ad3..f570facbe8 100644 --- a/unittest/commands/test_labelmap.cpp +++ b/unittest/commands/test_labelmap.cpp @@ -106,7 +106,7 @@ TEST_F(LabelMapTest, Atoms) EXPECT_EQ(utils::expand_type(FLERR, "**", Atom::ATOM, lmp), nullptr); EXPECT_EQ(utils::expand_type(FLERR, "1*2*", Atom::ATOM, lmp), nullptr); - auto expanded = utils::expand_type(FLERR, "C1", Atom::ATOM, lmp); + auto *expanded = utils::expand_type(FLERR, "C1", Atom::ATOM, lmp); EXPECT_THAT(expanded, StrEq("1")); delete[] expanded; expanded = utils::expand_type(FLERR, "O#", Atom::ATOM, lmp); @@ -268,7 +268,7 @@ TEST_F(LabelMapTest, Topology) EXPECT_EQ(atom->lmap->find("N2'-C1\"-N2'", Atom::BOND), -1); platform::unlink("labelmap_topology.inc"); - auto expanded = utils::expand_type(FLERR, "N2'", Atom::ATOM, lmp); + auto *expanded = utils::expand_type(FLERR, "N2'", Atom::ATOM, lmp); EXPECT_THAT(expanded, StrEq("2")); delete[] expanded; expanded = utils::expand_type(FLERR, "[C1][C1]", Atom::BOND, lmp); diff --git a/unittest/commands/test_lattice_region.cpp b/unittest/commands/test_lattice_region.cpp index 6eac1f45df..a76ec3ca1a 100644 --- a/unittest/commands/test_lattice_region.cpp +++ b/unittest/commands/test_lattice_region.cpp @@ -54,7 +54,7 @@ TEST_F(LatticeRegionTest, lattice_none) BEGIN_HIDE_OUTPUT(); command("lattice none 2.0"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::NONE); ASSERT_EQ(lattice->xlattice, 2.0); ASSERT_EQ(lattice->ylattice, 2.0); @@ -84,7 +84,7 @@ TEST_F(LatticeRegionTest, lattice_sc) auto output = END_CAPTURE_OUTPUT(); ASSERT_THAT(output, ContainsRegex(".*Lattice spacing in x,y,z = 1.5.* 2.* 3.*")); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->xlattice, 1.5); ASSERT_EQ(lattice->ylattice, 2.0); ASSERT_EQ(lattice->zlattice, 3.0); @@ -152,7 +152,7 @@ TEST_F(LatticeRegionTest, lattice_bcc) BEGIN_HIDE_OUTPUT(); command("lattice bcc 4.2 orient x 1 1 0 orient y -1 1 0"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::BCC); ASSERT_DOUBLE_EQ(lattice->xlattice, sqrt(2.0) * 4.2); ASSERT_DOUBLE_EQ(lattice->ylattice, sqrt(2.0) * 4.2); @@ -177,7 +177,7 @@ TEST_F(LatticeRegionTest, lattice_fcc) BEGIN_HIDE_OUTPUT(); command("lattice fcc 3.5 origin 0.5 0.5 0.5"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::FCC); ASSERT_DOUBLE_EQ(lattice->xlattice, 3.5); ASSERT_DOUBLE_EQ(lattice->ylattice, 3.5); @@ -215,7 +215,7 @@ TEST_F(LatticeRegionTest, lattice_hcp) BEGIN_HIDE_OUTPUT(); command("lattice hcp 3.0 orient z 0 0 1"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::HCP); ASSERT_DOUBLE_EQ(lattice->xlattice, 3.0); ASSERT_DOUBLE_EQ(lattice->ylattice, 3.0 * sqrt(3.0)); @@ -259,7 +259,7 @@ TEST_F(LatticeRegionTest, lattice_diamond) BEGIN_HIDE_OUTPUT(); command("lattice diamond 4.1 orient x 1 1 2 orient y -1 1 0 orient z -1 -1 1"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::DIAMOND); ASSERT_DOUBLE_EQ(lattice->xlattice, 6.6952719636073539); ASSERT_DOUBLE_EQ(lattice->ylattice, 5.7982756057296889); @@ -312,7 +312,7 @@ TEST_F(LatticeRegionTest, lattice_sq) command("dimension 2"); command("lattice sq 3.0"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::SQ); ASSERT_DOUBLE_EQ(lattice->xlattice, 3.0); ASSERT_DOUBLE_EQ(lattice->ylattice, 3.0); @@ -338,7 +338,7 @@ TEST_F(LatticeRegionTest, lattice_sq2) command("dimension 2"); command("lattice sq2 2.0"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::SQ2); ASSERT_DOUBLE_EQ(lattice->xlattice, 2.0); ASSERT_DOUBLE_EQ(lattice->ylattice, 2.0); @@ -364,7 +364,7 @@ TEST_F(LatticeRegionTest, lattice_hex) command("dimension 2"); command("lattice hex 2.0"); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::HEX); ASSERT_DOUBLE_EQ(lattice->xlattice, 2.0); ASSERT_DOUBLE_EQ(lattice->ylattice, 3.4641016151377544); @@ -414,7 +414,7 @@ TEST_F(LatticeRegionTest, lattice_custom) "basis $t 0.0 0.125 " "basis $f 0.5 0.125 "); END_HIDE_OUTPUT(); - auto lattice = lmp->domain->lattice; + auto *lattice = lmp->domain->lattice; ASSERT_EQ(lattice->style, Lattice::CUSTOM); ASSERT_DOUBLE_EQ(lattice->xlattice, 4.34); ASSERT_DOUBLE_EQ(lattice->ylattice, 4.34 * sqrt(3.0)); @@ -499,7 +499,7 @@ TEST_F(LatticeRegionTest, region_block_lattice) END_HIDE_OUTPUT(); ASSERT_EQ(lmp->domain->triclinic, 0); - auto x = lmp->atom->x; + auto *x = lmp->atom->x; ASSERT_EQ(lmp->atom->natoms, 8); ASSERT_DOUBLE_EQ(x[0][0], 0.0); ASSERT_DOUBLE_EQ(x[0][1], 0.0); @@ -525,7 +525,7 @@ TEST_F(LatticeRegionTest, region_block_box) END_HIDE_OUTPUT(); ASSERT_EQ(lmp->domain->triclinic, 0); - auto x = lmp->atom->x; + auto *x = lmp->atom->x; ASSERT_EQ(lmp->atom->natoms, 1); ASSERT_DOUBLE_EQ(x[0][0], 1.125); ASSERT_DOUBLE_EQ(x[0][1], 1.125); diff --git a/unittest/commands/test_regions.cpp b/unittest/commands/test_regions.cpp index 370799afea..e74637e17c 100644 --- a/unittest/commands/test_regions.cpp +++ b/unittest/commands/test_regions.cpp @@ -80,7 +80,7 @@ TEST_F(RegionTest, NoBox) list = domain->get_region_list(); EXPECT_EQ(list.size(), 9); - auto reg = domain->get_region_by_id("reg1"); + auto *reg = domain->get_region_by_id("reg1"); EXPECT_EQ(reg->interior, 1); EXPECT_EQ(reg->scaleflag, 1); EXPECT_EQ(reg->bboxflag, 1); @@ -231,17 +231,17 @@ TEST_F(RegionTest, Counts) command("region reg10 prism 0 5 0 5 -5 5 0.0 0.0 0.0"); // same as block END_HIDE_OUTPUT(); - auto x = atom->x; - auto reg1 = domain->get_region_by_id("reg1"); - auto reg2 = domain->get_region_by_id("reg2"); - auto reg3 = domain->get_region_by_id("reg3"); - auto reg4 = domain->get_region_by_id("reg4"); - auto reg5 = domain->get_region_by_id("reg5"); - auto reg6 = domain->get_region_by_id("reg6"); - auto reg7 = domain->get_region_by_id("reg7"); - auto reg8 = domain->get_region_by_id("reg8"); - auto reg9 = domain->get_region_by_id("reg9"); - auto reg10 = domain->get_region_by_id("reg10"); + auto *x = atom->x; + auto *reg1 = domain->get_region_by_id("reg1"); + auto *reg2 = domain->get_region_by_id("reg2"); + auto *reg3 = domain->get_region_by_id("reg3"); + auto *reg4 = domain->get_region_by_id("reg4"); + auto *reg5 = domain->get_region_by_id("reg5"); + auto *reg6 = domain->get_region_by_id("reg6"); + auto *reg7 = domain->get_region_by_id("reg7"); + auto *reg8 = domain->get_region_by_id("reg8"); + auto *reg9 = domain->get_region_by_id("reg9"); + auto *reg10 = domain->get_region_by_id("reg10"); int count1, count2, count3, count4, count5, count6, count7, count8, count9, count10; count1 = count2 = count3 = count4 = count5 = count6 = count7 = count8 = count9 = count10 = 0; reg1->prematch(); diff --git a/unittest/commands/test_reset_atoms.cpp b/unittest/commands/test_reset_atoms.cpp index d09a60c886..9054333332 100644 --- a/unittest/commands/test_reset_atoms.cpp +++ b/unittest/commands/test_reset_atoms.cpp @@ -56,7 +56,7 @@ TEST_F(ResetAtomsIDTest, MolIDAll) { if (lmp->atom->natoms == 0) GTEST_SKIP(); - auto molid = lmp->atom->molecule; + auto *molid = lmp->atom->molecule; ASSERT_EQ(molid[GETIDX(1)], 1); ASSERT_EQ(molid[GETIDX(2)], 1); ASSERT_EQ(molid[GETIDX(3)], 1); @@ -128,7 +128,7 @@ TEST_F(ResetAtomsIDTest, DeletePlusAtomID) { if (lmp->atom->natoms == 0) GTEST_SKIP(); - auto molid = lmp->atom->molecule; + auto *molid = lmp->atom->molecule; // delete two water molecules BEGIN_HIDE_OUTPUT(); @@ -206,7 +206,7 @@ TEST_F(ResetAtomsIDTest, PartialOffset) { if (lmp->atom->natoms == 0) GTEST_SKIP(); - auto molid = lmp->atom->molecule; + auto *molid = lmp->atom->molecule; // delete two water molecules BEGIN_HIDE_OUTPUT(); @@ -286,7 +286,7 @@ TEST_F(ResetAtomsIDTest, DeleteAdd) { if (lmp->atom->natoms == 0) GTEST_SKIP(); - auto molid = lmp->atom->molecule; + auto *molid = lmp->atom->molecule; // delete two water molecules BEGIN_HIDE_OUTPUT(); @@ -445,12 +445,12 @@ TEST_F(ResetAtomsIDTest, TopologyData) ASSERT_EQ(lmp->atom->natoms, 23); ASSERT_EQ(lmp->atom->map_tag_max, 26); - auto num_bond = lmp->atom->num_bond; - auto num_angle = lmp->atom->num_angle; - auto bond_atom = lmp->atom->bond_atom; - auto angle_atom1 = lmp->atom->angle_atom1; - auto angle_atom2 = lmp->atom->angle_atom2; - auto angle_atom3 = lmp->atom->angle_atom3; + auto *num_bond = lmp->atom->num_bond; + auto *num_angle = lmp->atom->num_angle; + auto *bond_atom = lmp->atom->bond_atom; + auto *angle_atom1 = lmp->atom->angle_atom1; + auto *angle_atom2 = lmp->atom->angle_atom2; + auto *angle_atom3 = lmp->atom->angle_atom3; ASSERT_EQ(num_bond[GETIDX(1)], 2); ASSERT_EQ(bond_atom[GETIDX(1)][0], 2); ASSERT_EQ(bond_atom[GETIDX(1)][1], 3); diff --git a/unittest/commands/test_set_property.cpp b/unittest/commands/test_set_property.cpp index 36b86b3526..c306ea4739 100644 --- a/unittest/commands/test_set_property.cpp +++ b/unittest/commands/test_set_property.cpp @@ -85,7 +85,7 @@ TEST_F(SetTest, NoBoxNoAtoms) command("create_atoms 1 single 0.5 0.5 0.5"); command("compute 0 all property/atom proc"); END_HIDE_OUTPUT(); - auto compute = lmp->modify->get_compute_by_id("0"); + auto *compute = lmp->modify->get_compute_by_id("0"); compute->compute_peratom(); ASSERT_EQ(compute->vector_atom[0], 0); @@ -119,7 +119,7 @@ TEST_F(SetTest, StylesTypes) command("compute 1 all property/atom id type mol"); END_HIDE_OUTPUT(); - auto compute = lmp->modify->get_compute_by_id("1"); + auto *compute = lmp->modify->get_compute_by_id("1"); ASSERT_NE(compute, nullptr); compute->compute_peratom(); @@ -409,7 +409,7 @@ TEST_F(SetTest, EffPackage) command("compute 2 all property/atom espin eradius"); END_HIDE_OUTPUT(); - auto compute = lmp->modify->get_compute_by_id("2"); + auto *compute = lmp->modify->get_compute_by_id("2"); ASSERT_NE(compute, nullptr); compute->compute_peratom(); diff --git a/unittest/commands/test_variables.cpp b/unittest/commands/test_variables.cpp index 1826263dea..8f2f4ba9d9 100644 --- a/unittest/commands/test_variables.cpp +++ b/unittest/commands/test_variables.cpp @@ -389,8 +389,9 @@ TEST_F(VariableTest, Expressions) command("print \"${err2}\"");); TEST_FAILURE(".*ERROR on proc 0: Variable err3: Invalid power expression in variable formula.*", command("print \"${err3}\"");); - TEST_FAILURE(".*ERROR: Variable one: Mis-matched special function variable in variable formula.*", - command("print \"${isrt}\"");); + TEST_FAILURE( + ".*ERROR: Variable one: Mis-matched special function variable in variable formula.*", + command("print \"${isrt}\"");); TEST_FAILURE(".*ERROR: Variable vec4: index 11 exceeds vector size of 10.*", command("print \"${xxxl}\"");); } diff --git a/unittest/cplusplus/test_input_class.cpp b/unittest/cplusplus/test_input_class.cpp index 708d3f7cae..4061c0071c 100644 --- a/unittest/cplusplus/test_input_class.cpp +++ b/unittest/cplusplus/test_input_class.cpp @@ -22,9 +22,9 @@ protected: LAMMPS *lmp; Input_commands() { - const char * args[] = {"LAMMPS_test", nullptr}; - char ** argv = (char**)args; - int argc = 1; + const char *args[] = {"LAMMPS_test", nullptr}; + char **argv = (char **)args; + int argc = 1; int flag; MPI_Initialized(&flag); diff --git a/unittest/cplusplus/test_lammps_class.cpp b/unittest/cplusplus/test_lammps_class.cpp index 6f279fc96c..23d83c4ecb 100644 --- a/unittest/cplusplus/test_lammps_class.cpp +++ b/unittest/cplusplus/test_lammps_class.cpp @@ -21,9 +21,9 @@ protected: LAMMPS *lmp; LAMMPS_plain() : lmp(nullptr) { - const char * args[] = {"LAMMPS_test", nullptr}; - char ** argv = (char**)args; - int argc = 1; + const char *args[] = {"LAMMPS_test", nullptr}; + char **argv = (char **)args; + int argc = 1; int flag; MPI_Initialized(&flag); @@ -37,7 +37,7 @@ protected: LAMMPS::argv args = {"LAMMPS_test", "-log", "none", "-echo", "both", "-nocite"}; ::testing::internal::CaptureStdout(); - lmp = new LAMMPS(args, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, StartsWith("LAMMPS (")); } @@ -157,9 +157,9 @@ protected: LAMMPS *lmp; LAMMPS_omp() : lmp(nullptr) { - const char * args[] = {"LAMMPS_test", nullptr}; - char ** argv = (char**)args; - int argc = 1; + const char *args[] = {"LAMMPS_test", nullptr}; + char **argv = (char **)args; + int argc = 1; int flag; MPI_Initialized(&flag); @@ -238,9 +238,9 @@ protected: LAMMPS *lmp; LAMMPS_kokkos() : lmp(nullptr) { - const char * args[] = {"LAMMPS_test", nullptr}; - char ** argv = (char**)args; - int argc = 1; + const char *args[] = {"LAMMPS_test", nullptr}; + char **argv = (char **)args; + int argc = 1; int flag; MPI_Initialized(&flag); @@ -330,7 +330,7 @@ TEST(LAMMPS_init, OpenMP) LAMMPS::argv args = {"LAMMPS_init", "-in", "in.lammps_empty", "-log", "none", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = new LAMMPS(args, MPI_COMM_WORLD); + auto *lmp = new LAMMPS(args, MPI_COMM_WORLD); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, ContainsRegex(".*using 2 OpenMP thread.*per MPI task.*")); @@ -361,7 +361,7 @@ TEST(LAMMPS_init, NoOpenMP) LAMMPS::argv args = {"LAMMPS_init", "-in", "in.lammps_class_noomp", "-log", "none", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = new LAMMPS(args, MPI_COMM_WORLD); + auto *lmp = new LAMMPS(args, MPI_COMM_WORLD); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, ContainsRegex( ".*OMP_NUM_THREADS environment is not set.*Defaulting to 1 thread.*")); diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index 6e823b32fc..bbacdd8f24 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -70,7 +70,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton // check if prerequisite styles are available Info *info = new Info(lmp); int nfail = 0; - for (auto &prerequisite : cfg.prerequisites) { + for (const auto &prerequisite : cfg.prerequisites) { std::string style = prerequisite.second; // this is a test for angle styles, so if the suffixed @@ -120,7 +120,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("variable input_dir index " + INPUT_FOLDER); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -129,11 +129,11 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("angle_style " + cfg.angle_style); - for (auto &angle_coeff : cfg.angle_coeff) { + for (const auto &angle_coeff : cfg.angle_coeff) { command("angle_coeff " + angle_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -176,12 +176,12 @@ void restart_lammps(LAMMPS *lmp, const TestConfig &cfg) } if ((cfg.angle_style.substr(0, 6) == "hybrid") || !lmp->force->angle->writedata) { - for (auto &angle_coeff : cfg.angle_coeff) { + for (const auto &angle_coeff : cfg.angle_coeff) { command("angle_coeff " + angle_coeff); } } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -204,7 +204,7 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) command("variable newton_bond delete"); command("variable newton_bond index on"); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -214,10 +214,10 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) std::string input_file = platform::path_join(INPUT_FOLDER, cfg.input_file); parse_input_script(input_file); - for (auto &angle_coeff : cfg.angle_coeff) { + for (const auto &angle_coeff : cfg.angle_coeff) { command("angle_coeff " + angle_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } command("run 0 post no"); @@ -234,7 +234,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; - for (auto &prerequisite : config.prerequisites) { + for (const auto &prerequisite : config.prerequisites) { std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; } return; @@ -253,7 +253,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // angle_coeff block.clear(); - for (auto &angle_coeff : config.angle_coeff) { + for (const auto &angle_coeff : config.angle_coeff) { block += angle_coeff + "\n"; } writer.emit_block("angle_coeff", block); @@ -277,14 +277,14 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) writer.emit("init_energy", lmp->force->angle->energy); // init_stress - auto stress = lmp->force->angle->virial; + auto *stress = lmp->force->angle->virial; block = fmt::format("{:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e}", stress[0], stress[1], stress[2], stress[3], stress[4], stress[5]); writer.emit_block("init_stress", block); // init_forces block.clear(); - auto f = lmp->atom->f; + auto *f = lmp->atom->f; for (int i = 1; i <= natoms; ++i) { const int j = lmp->atom->map(i); block += fmt::format("{:3} {:23.16e} {:23.16e} {:23.16e}\n", i, f[j][0], f[j][1], f[j][2]); @@ -345,7 +345,7 @@ TEST(AngleStyle, plain) double epsilon = test_config.epsilon; ErrorStats stats; - auto angle = lmp->force->angle; + auto *angle = lmp->force->angle; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", angle->virial, test_config.init_stress, epsilon); @@ -463,7 +463,7 @@ TEST(AngleStyle, omp) double epsilon = 5.0 * test_config.epsilon; ErrorStats stats; - auto angle = lmp->force->angle; + auto *angle = lmp->force->angle; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", angle->virial, test_config.init_stress, 10 * epsilon); @@ -746,9 +746,9 @@ TEST(AngleStyle, extract) GTEST_SKIP(); } - auto angle = lmp->force->angle; - void *ptr = nullptr; - int dim = 0; + auto *angle = lmp->force->angle; + void *ptr = nullptr; + int dim = 0; for (auto extract : test_config.extract) { ptr = angle->extract(extract.first.c_str(), dim); EXPECT_NE(ptr, nullptr); diff --git a/unittest/force-styles/test_bond_style.cpp b/unittest/force-styles/test_bond_style.cpp index eb6b0b488d..d2523ff51d 100644 --- a/unittest/force-styles/test_bond_style.cpp +++ b/unittest/force-styles/test_bond_style.cpp @@ -70,7 +70,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton // check if prerequisite styles are available Info *info = new Info(lmp); int nfail = 0; - for (auto &prerequisite : cfg.prerequisites) { + for (const auto &prerequisite : cfg.prerequisites) { std::string style = prerequisite.second; // this is a test for bond styles, so if the suffixed @@ -120,7 +120,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("variable input_dir index " + INPUT_FOLDER); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -129,11 +129,11 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("bond_style " + cfg.bond_style); - for (auto &bond_coeff : cfg.bond_coeff) { + for (const auto &bond_coeff : cfg.bond_coeff) { command("bond_coeff " + bond_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -176,12 +176,12 @@ void restart_lammps(LAMMPS *lmp, const TestConfig &cfg) } if ((cfg.bond_style.substr(0, 6) == "hybrid") || !lmp->force->bond->writedata) { - for (auto &bond_coeff : cfg.bond_coeff) { + for (const auto &bond_coeff : cfg.bond_coeff) { command("bond_coeff " + bond_coeff); } } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -204,7 +204,7 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) command("variable newton_bond delete"); command("variable newton_bond index on"); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -214,10 +214,10 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) std::string input_file = platform::path_join(INPUT_FOLDER, cfg.input_file); parse_input_script(input_file); - for (auto &bond_coeff : cfg.bond_coeff) { + for (const auto &bond_coeff : cfg.bond_coeff) { command("bond_coeff " + bond_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } command("run 0 post no"); @@ -234,7 +234,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; - for (auto &prerequisite : config.prerequisites) { + for (const auto &prerequisite : config.prerequisites) { std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; } return; @@ -253,7 +253,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // bond_coeff block.clear(); - for (auto &bond_coeff : config.bond_coeff) { + for (const auto &bond_coeff : config.bond_coeff) { block += bond_coeff + "\n"; } writer.emit_block("bond_coeff", block); @@ -277,14 +277,14 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) writer.emit("init_energy", lmp->force->bond->energy); // init_stress - auto stress = lmp->force->bond->virial; + auto *stress = lmp->force->bond->virial; block = fmt::format("{:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e}", stress[0], stress[1], stress[2], stress[3], stress[4], stress[5]); writer.emit_block("init_stress", block); // init_forces block.clear(); - auto f = lmp->atom->f; + auto *f = lmp->atom->f; for (int i = 1; i <= natoms; ++i) { const int j = lmp->atom->map(i); block += fmt::format("{:3} {:23.16e} {:23.16e} {:23.16e}\n", i, f[j][0], f[j][1], f[j][2]); @@ -345,7 +345,7 @@ TEST(BondStyle, plain) double epsilon = test_config.epsilon; ErrorStats stats; - auto bond = lmp->force->bond; + auto *bond = lmp->force->bond; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", bond->virial, test_config.init_stress, epsilon); @@ -465,7 +465,7 @@ TEST(BondStyle, omp) double epsilon = 5.0 * test_config.epsilon; ErrorStats stats; - auto bond = lmp->force->bond; + auto *bond = lmp->force->bond; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", bond->virial, test_config.init_stress, 10 * epsilon); @@ -532,7 +532,6 @@ TEST(BondStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; - TEST(BondStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP(); @@ -652,7 +651,7 @@ TEST(BondStyle, single) command("pair_coeff * *"); command("bond_style " + test_config.bond_style); - auto bond = lmp->force->bond; + auto *bond = lmp->force->bond; for (auto &bond_coeff : test_config.bond_coeff) { command("bond_coeff " + bond_coeff); @@ -860,9 +859,9 @@ TEST(BondStyle, extract) GTEST_SKIP(); } - auto bond = lmp->force->bond; - void *ptr = nullptr; - int dim = 0; + auto *bond = lmp->force->bond; + void *ptr = nullptr; + int dim = 0; for (auto extract : test_config.extract) { ptr = bond->extract(extract.first.c_str(), dim); EXPECT_NE(ptr, nullptr); diff --git a/unittest/force-styles/test_config.h b/unittest/force-styles/test_config.h index b284052d6d..09b32f54de 100644 --- a/unittest/force-styles/test_config.h +++ b/unittest/force-styles/test_config.h @@ -96,7 +96,7 @@ public: restart_vel.clear(); global_vector.clear(); } - TestConfig(const TestConfig &) = delete; + TestConfig(const TestConfig &) = delete; TestConfig &operator=(const TestConfig &) = delete; std::string tags_line() const diff --git a/unittest/force-styles/test_config_reader.h b/unittest/force-styles/test_config_reader.h index 1af7589add..0427049bfc 100644 --- a/unittest/force-styles/test_config_reader.h +++ b/unittest/force-styles/test_config_reader.h @@ -22,8 +22,8 @@ class TestConfigReader : public YamlReader { public: TestConfigReader(TestConfig &config); - TestConfigReader() = delete; - const TestConfigReader & operator=(TestConfig &) = delete; + TestConfigReader() = delete; + const TestConfigReader &operator=(TestConfig &) = delete; void skip_tests(const yaml_event_t &event); void prerequisites(const yaml_event_t &event); diff --git a/unittest/force-styles/test_dihedral_style.cpp b/unittest/force-styles/test_dihedral_style.cpp index 060dd040c2..e6c34843c3 100644 --- a/unittest/force-styles/test_dihedral_style.cpp +++ b/unittest/force-styles/test_dihedral_style.cpp @@ -63,12 +63,12 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton = true) { - LAMMPS *lmp = new LAMMPS(args, MPI_COMM_WORLD); + auto *lmp = new LAMMPS(args, MPI_COMM_WORLD); // check if prerequisite styles are available Info *info = new Info(lmp); int nfail = 0; - for (auto &prerequisite : cfg.prerequisites) { + for (const auto &prerequisite : cfg.prerequisites) { std::string style = prerequisite.second; // this is a test for dihedral styles, so if the suffixed @@ -118,7 +118,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("variable input_dir index " + INPUT_FOLDER); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -127,11 +127,11 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("dihedral_style " + cfg.dihedral_style); - for (auto &dihedral_coeff : cfg.dihedral_coeff) { + for (const auto &dihedral_coeff : cfg.dihedral_coeff) { command("dihedral_coeff " + dihedral_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -174,12 +174,12 @@ void restart_lammps(LAMMPS *lmp, const TestConfig &cfg) } if ((cfg.dihedral_style.substr(0, 6) == "hybrid") || !lmp->force->dihedral->writedata) { - for (auto &dihedral_coeff : cfg.dihedral_coeff) { + for (const auto &dihedral_coeff : cfg.dihedral_coeff) { command("dihedral_coeff " + dihedral_coeff); } } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -202,7 +202,7 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) command("variable newton_bond delete"); command("variable newton_bond index on"); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -221,10 +221,10 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) std::string input_file = platform::path_join(INPUT_FOLDER, cfg.input_file); parse_input_script(input_file); - for (auto &dihedral_coeff : cfg.dihedral_coeff) { + for (const auto &dihedral_coeff : cfg.dihedral_coeff) { command("dihedral_coeff " + dihedral_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } command("run 0 post no"); @@ -241,7 +241,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; - for (auto &prerequisite : config.prerequisites) { + for (const auto &prerequisite : config.prerequisites) { std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; } return; @@ -260,7 +260,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // dihedral_coeff block.clear(); - for (auto &dihedral_coeff : config.dihedral_coeff) { + for (const auto &dihedral_coeff : config.dihedral_coeff) { block += dihedral_coeff + "\n"; } writer.emit_block("dihedral_coeff", block); @@ -278,14 +278,14 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) writer.emit("init_energy", lmp->force->dihedral->energy); // init_stress - auto stress = lmp->force->dihedral->virial; + auto *stress = lmp->force->dihedral->virial; block = fmt::format("{:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e}", stress[0], stress[1], stress[2], stress[3], stress[4], stress[5]); writer.emit_block("init_stress", block); // init_forces block.clear(); - auto f = lmp->atom->f; + auto *f = lmp->atom->f; for (int i = 1; i <= natoms; ++i) { const int j = lmp->atom->map(i); block += fmt::format("{:3} {:23.16e} {:23.16e} {:23.16e}\n", i, f[j][0], f[j][1], f[j][2]); @@ -346,7 +346,7 @@ TEST(DihedralStyle, plain) double epsilon = test_config.epsilon; ErrorStats stats; - auto dihedral = lmp->force->dihedral; + auto *dihedral = lmp->force->dihedral; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", dihedral->virial, test_config.init_stress, epsilon); @@ -466,7 +466,7 @@ TEST(DihedralStyle, omp) double epsilon = 5.0 * test_config.epsilon; ErrorStats stats; - auto dihedral = lmp->force->dihedral; + auto *dihedral = lmp->force->dihedral; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", dihedral->virial, test_config.init_stress, @@ -534,7 +534,6 @@ TEST(DihedralStyle, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); }; - TEST(DihedralStyle, numdiff) { if (!LAMMPS::is_installed_pkg("EXTRA-FIX")) GTEST_SKIP(); diff --git a/unittest/force-styles/test_fix_timestep.cpp b/unittest/force-styles/test_fix_timestep.cpp index 64c56f3602..ae1029a3d1 100644 --- a/unittest/force-styles/test_fix_timestep.cpp +++ b/unittest/force-styles/test_fix_timestep.cpp @@ -71,7 +71,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool use_re // check if prerequisite styles are available Info *info = new Info(lmp); int nfail = 0; - for (auto &prerequisite : cfg.prerequisites) { + for (const auto &prerequisite : cfg.prerequisites) { std::string style = prerequisite.second; // this is a test for fix styles, so if the suffixed @@ -97,7 +97,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool use_re }; command("variable input_dir index " + INPUT_FOLDER); - for (auto &pre_command : cfg.pre_commands) + for (const auto &pre_command : cfg.pre_commands) command(pre_command); std::string input_file = platform::path_join(INPUT_FOLDER, cfg.input_file); @@ -128,7 +128,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool use_re command("group solute molecule 1:2"); command("group solvent molecule 3:5"); - for (auto &post_command : cfg.post_commands) + for (const auto &post_command : cfg.post_commands) command(post_command); command("timestep 0.25"); @@ -158,10 +158,10 @@ void restart_lammps(LAMMPS *lmp, const TestConfig &cfg, bool use_rmass, bool use if (use_respa) command("run_style respa 2 1 bond 1 pair 2"); - for (auto &post_command : cfg.post_commands) + for (const auto &post_command : cfg.post_commands) command(post_command); - auto ifix = lmp->modify->get_fix_by_id("test"); + auto *ifix = lmp->modify->get_fix_by_id("test"); if (ifix && !utils::strmatch(ifix->style, "^move")) { // must be set to trigger calling Fix::reset_dt() with timestep lmp->update->first_update = 1; @@ -198,16 +198,16 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // natoms writer.emit("natoms", natoms); - auto ifix = lmp->modify->get_fix_by_id("test"); + auto *ifix = lmp->modify->get_fix_by_id("test"); if (!ifix) { std::cerr << "ERROR: no fix defined with fix ID 'test'\n"; exit(1); } else { // run_stress, if enabled if (ifix->thermo_virial) { - auto stress = ifix->virial; - block = fmt::format("{:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e}", - stress[0], stress[1], stress[2], stress[3], stress[4], stress[5]); + auto *stress = ifix->virial; + block = fmt::format("{:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e}", + stress[0], stress[1], stress[2], stress[3], stress[4], stress[5]); writer.emit_block("run_stress", block); } @@ -229,7 +229,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // run_pos block.clear(); - auto x = lmp->atom->x; + auto *x = lmp->atom->x; for (int i = 1; i <= natoms; ++i) { const int j = lmp->atom->map(i); block += fmt::format("{:3} {:23.16e} {:23.16e} {:23.16e}\n", i, x[j][0], x[j][1], x[j][2]); @@ -238,7 +238,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // run_vel block.clear(); - auto v = lmp->atom->v; + auto *v = lmp->atom->v; for (int i = 1; i <= natoms; ++i) { const int j = lmp->atom->map(i); block += fmt::format("{:3} {:23.16e} {:23.16e} {:23.16e}\n", i, v[j][0], v[j][1], v[j][2]); @@ -289,7 +289,7 @@ TEST(FixTimestep, plain) EXPECT_POSITIONS("run_pos (normal run, verlet)", lmp->atom, test_config.run_pos, epsilon); EXPECT_VELOCITIES("run_vel (normal run, verlet)", lmp->atom, test_config.run_vel, epsilon); - auto ifix = lmp->modify->get_fix_by_id("test"); + auto *ifix = lmp->modify->get_fix_by_id("test"); if (!ifix) { FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; } else { @@ -317,8 +317,8 @@ TEST(FixTimestep, plain) // check t_target for thermostats - int dim = -1; - double *ptr = (double *)ifix->extract("t_target", dim); + int dim = -1; + auto *ptr = (double *)ifix->extract("t_target", dim); if ((ptr != nullptr) && (dim == 0)) { int ivar = lmp->input->variable->find("t_target"); if (ivar >= 0) { @@ -583,7 +583,7 @@ TEST(FixTimestep, omp) EXPECT_POSITIONS("run_pos (normal run, verlet)", lmp->atom, test_config.run_pos, epsilon); EXPECT_VELOCITIES("run_vel (normal run, verlet)", lmp->atom, test_config.run_vel, epsilon); - auto ifix = lmp->modify->get_fix_by_id("test"); + auto *ifix = lmp->modify->get_fix_by_id("test"); if (!ifix) { FAIL() << "ERROR: no fix defined with fix ID 'test'\n"; } else { @@ -611,8 +611,8 @@ TEST(FixTimestep, omp) // check t_target for thermostats - int dim = -1; - double *ptr = (double *)ifix->extract("t_target", dim); + int dim = -1; + auto *ptr = (double *)ifix->extract("t_target", dim); if ((ptr != nullptr) && (dim == 0)) { int ivar = lmp->input->variable->find("t_target"); if (ivar >= 0) { diff --git a/unittest/force-styles/test_improper_style.cpp b/unittest/force-styles/test_improper_style.cpp index c90d30c21a..59028fb1ff 100644 --- a/unittest/force-styles/test_improper_style.cpp +++ b/unittest/force-styles/test_improper_style.cpp @@ -70,7 +70,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton // check if prerequisite styles are available Info *info = new Info(lmp); int nfail = 0; - for (auto &prerequisite : cfg.prerequisites) { + for (const auto &prerequisite : cfg.prerequisites) { std::string style = prerequisite.second; // this is a test for improper styles, so if the suffixed @@ -120,7 +120,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("variable input_dir index " + INPUT_FOLDER); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -129,11 +129,11 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("improper_style " + cfg.improper_style); - for (auto &improper_coeff : cfg.improper_coeff) { + for (const auto &improper_coeff : cfg.improper_coeff) { command("improper_coeff " + improper_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -176,12 +176,12 @@ void restart_lammps(LAMMPS *lmp, const TestConfig &cfg) } if ((cfg.improper_style.substr(0, 6) == "hybrid") || !lmp->force->improper->writedata) { - for (auto &improper_coeff : cfg.improper_coeff) { + for (const auto &improper_coeff : cfg.improper_coeff) { command("improper_coeff " + improper_coeff); } } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -204,7 +204,7 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) command("variable newton_bond delete"); command("variable newton_bond index on"); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -214,10 +214,10 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) std::string input_file = platform::path_join(INPUT_FOLDER, cfg.input_file); parse_input_script(input_file); - for (auto &improper_coeff : cfg.improper_coeff) { + for (const auto &improper_coeff : cfg.improper_coeff) { command("improper_coeff " + improper_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } command("run 0 post no"); @@ -234,7 +234,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; - for (auto &prerequisite : config.prerequisites) { + for (const auto &prerequisite : config.prerequisites) { std::cerr << prerequisite.first << "_style " << prerequisite.second << "\n"; } return; @@ -253,7 +253,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // improper_coeff block.clear(); - for (auto &improper_coeff : config.improper_coeff) { + for (const auto &improper_coeff : config.improper_coeff) { block += improper_coeff + "\n"; } writer.emit_block("improper_coeff", block); @@ -271,14 +271,14 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) writer.emit("init_energy", lmp->force->improper->energy); // init_stress - auto stress = lmp->force->improper->virial; + auto *stress = lmp->force->improper->virial; block = fmt::format("{:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e} {:23.16e}", stress[0], stress[1], stress[2], stress[3], stress[4], stress[5]); writer.emit_block("init_stress", block); // init_forces block.clear(); - auto f = lmp->atom->f; + auto *f = lmp->atom->f; for (int i = 1; i <= natoms; ++i) { const int j = lmp->atom->map(i); block += fmt::format("{:3} {:23.16e} {:23.16e} {:23.16e}\n", i, f[j][0], f[j][1], f[j][2]); @@ -339,7 +339,7 @@ TEST(ImproperStyle, plain) double epsilon = test_config.epsilon; ErrorStats stats; - auto improper = lmp->force->improper; + auto *improper = lmp->force->improper; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", improper->virial, test_config.init_stress, epsilon); @@ -459,7 +459,7 @@ TEST(ImproperStyle, omp) double epsilon = 5.0 * test_config.epsilon; ErrorStats stats; - auto improper = lmp->force->improper; + auto *improper = lmp->force->improper; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", improper->virial, test_config.init_stress, diff --git a/unittest/force-styles/test_main.cpp b/unittest/force-styles/test_main.cpp index 1cf428eee4..da2574a037 100644 --- a/unittest/force-styles/test_main.cpp +++ b/unittest/force-styles/test_main.cpp @@ -130,7 +130,7 @@ void write_yaml_header(YamlWriter *writer, TestConfig *cfg, const char *version) // skip tests block.clear(); - for (auto &skip : cfg->skip_tests) { + for (const auto &skip : cfg->skip_tests) { if (block.empty()) block = skip; else diff --git a/unittest/force-styles/test_main.h b/unittest/force-styles/test_main.h index 36bcd7bdff..8199537c39 100644 --- a/unittest/force-styles/test_main.h +++ b/unittest/force-styles/test_main.h @@ -14,9 +14,9 @@ #ifndef TEST_MAIN_H #define TEST_MAIN_H -#include "test_config.h" -#include "lammps.h" #include "atom.h" +#include "lammps.h" +#include "test_config.h" #include #include @@ -37,9 +37,13 @@ void write_yaml_header(class YamlWriter *writer, TestConfig *cfg, const char *ve EXPECT_PRED_FORMAT2(::testing::DoubleLE, err, eps); \ } while (0); -void EXPECT_STRESS(const std::string & name, double * stress, const stress_t & expected_stress, double epsilon); -void EXPECT_FORCES(const std::string & name, LAMMPS_NS::Atom * atom, const std::vector & f_ref, double epsilon); -void EXPECT_POSITIONS(const std::string & name, LAMMPS_NS::Atom * atom, const std::vector & x_ref, double epsilon); -void EXPECT_VELOCITIES(const std::string & name, LAMMPS_NS::Atom * atom, const std::vector & v_ref, double epsilon); +void EXPECT_STRESS(const std::string &name, double *stress, const stress_t &expected_stress, + double epsilon); +void EXPECT_FORCES(const std::string &name, LAMMPS_NS::Atom *atom, + const std::vector &f_ref, double epsilon); +void EXPECT_POSITIONS(const std::string &name, LAMMPS_NS::Atom *atom, + const std::vector &x_ref, double epsilon); +void EXPECT_VELOCITIES(const std::string &name, LAMMPS_NS::Atom *atom, + const std::vector &v_ref, double epsilon); #endif diff --git a/unittest/force-styles/test_pair_style.cpp b/unittest/force-styles/test_pair_style.cpp index 9db9c7ac8b..884d802aa5 100644 --- a/unittest/force-styles/test_pair_style.cpp +++ b/unittest/force-styles/test_pair_style.cpp @@ -71,7 +71,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton // check if prerequisite styles are available Info *info = new Info(lmp); int nfail = 0; - for (auto &prerequisite : cfg.prerequisites) { + for (const auto &prerequisite : cfg.prerequisites) { std::string style = prerequisite.second; // this is a test for pair styles, so if the suffixed @@ -122,7 +122,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("variable input_dir index " + INPUT_FOLDER); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -131,7 +131,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("pair_style " + cfg.pair_style); - for (auto &pair_coeff : cfg.pair_coeff) { + for (const auto &pair_coeff : cfg.pair_coeff) { command("pair_coeff " + pair_coeff); } @@ -142,7 +142,7 @@ LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton command("pair_modify table 0"); command("pair_modify table/disp 0"); - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } @@ -188,12 +188,12 @@ void restart_lammps(LAMMPS *lmp, const TestConfig &cfg, bool nofdotr = false, bo command("pair_style " + cfg.pair_style); } if (!lmp->force->pair->restartinfo || !lmp->force->pair->writedata) { - for (auto &pair_coeff : cfg.pair_coeff) { + for (const auto &pair_coeff : cfg.pair_coeff) { command("pair_coeff " + pair_coeff); } } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } if (nofdotr) command("pair_modify nofdotr"); @@ -217,7 +217,7 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) command("variable newton_pair delete"); command("variable newton_pair index on"); - for (auto &pre_command : cfg.pre_commands) { + for (const auto &pre_command : cfg.pre_commands) { command(pre_command); } @@ -227,10 +227,10 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) std::string input_file = platform::path_join(INPUT_FOLDER, cfg.input_file); parse_input_script(input_file); - for (auto &pair_coeff : cfg.pair_coeff) { + for (const auto &pair_coeff : cfg.pair_coeff) { command("pair_coeff " + pair_coeff); } - for (auto &post_command : cfg.post_commands) { + for (const auto &post_command : cfg.post_commands) { command(post_command); } command("run 0 post no"); @@ -287,7 +287,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) writer.emit("init_coul", lmp->force->pair->eng_coul); // init_stress - auto stress = lmp->force->pair->virial; + auto *stress = lmp->force->pair->virial; // avoid false positives on tiny stresses. force to zero instead. for (int i = 0; i < 6; ++i) if (fabs(stress[i]) < 1.0e-13) stress[i] = 0.0; @@ -297,7 +297,7 @@ void generate_yaml_file(const char *outfile, const TestConfig &config) // init_forces block.clear(); - auto f = lmp->atom->f; + auto *f = lmp->atom->f; for (int i = 1; i <= natoms; ++i) { const int j = lmp->atom->map(i); block += fmt::format("{:3} {:23.16e} {:23.16e} {:23.16e}\n", i, f[j][0], f[j][1], f[j][2]); @@ -367,7 +367,7 @@ TEST(PairStyle, plain) if (lmp->force->kspace && lmp->force->kspace->compute_flag) if (utils::strmatch(lmp->force->kspace_style, "^pppm")) epsilon *= 2.0e8; #endif - auto pair = lmp->force->pair; + auto *pair = lmp->force->pair; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton on)", pair->virial, test_config.init_stress, epsilon); @@ -547,7 +547,7 @@ TEST(PairStyle, omp) if (lmp->force->kspace && lmp->force->kspace->compute_flag) if (utils::strmatch(lmp->force->kspace_style, "^pppm")) epsilon *= 2.0e8; #endif - auto pair = lmp->force->pair; + auto *pair = lmp->force->pair; ErrorStats stats; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); @@ -679,7 +679,7 @@ TEST(PairStyle, kokkos_omp) if (lmp->force->kspace && lmp->force->kspace->compute_flag) if (utils::strmatch(lmp->force->kspace_style, "^pppm")) epsilon *= 2.0e8; #endif - auto pair = lmp->force->pair; + auto *pair = lmp->force->pair; ErrorStats stats; EXPECT_FORCES("init_forces (newton on)", lmp->atom, test_config.init_forces, epsilon); @@ -821,7 +821,7 @@ TEST(PairStyle, gpu) if (utils::strmatch(lmp->force->kspace_style, "^pppm")) epsilon *= 2.0e8; #endif ErrorStats stats; - auto pair = lmp->force->pair; + auto *pair = lmp->force->pair; EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress (newton off)", pair->virial, test_config.init_stress, 10 * epsilon); @@ -902,7 +902,7 @@ TEST(PairStyle, intel) ASSERT_EQ(lmp->atom->natoms, nlocal); ErrorStats stats; - auto pair = lmp->force->pair; + auto *pair = lmp->force->pair; EXPECT_FORCES("init_forces", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress", pair->virial, test_config.init_stress, 10 * epsilon); @@ -973,7 +973,7 @@ TEST(PairStyle, opt) if (utils::strmatch(lmp->force->kspace_style, "^pppm")) epsilon *= 2.0e8; #endif ErrorStats stats; - auto pair = lmp->force->pair; + auto *pair = lmp->force->pair; EXPECT_FORCES("init_forces (newton off)", lmp->atom, test_config.init_forces, epsilon); EXPECT_STRESS("init_stress", pair->virial, test_config.init_stress, 10 * epsilon); @@ -1284,7 +1284,7 @@ TEST(PairStyle, extract) GTEST_SKIP(); } - auto pair = lmp->force->pair; + auto *pair = lmp->force->pair; if (!pair->compute_flag) { std::cerr << "Pair style disabled" << std::endl; if (!verbose) ::testing::internal::CaptureStdout(); diff --git a/unittest/force-styles/yaml_writer.h b/unittest/force-styles/yaml_writer.h index be4861fcc0..9a9775881f 100644 --- a/unittest/force-styles/yaml_writer.h +++ b/unittest/force-styles/yaml_writer.h @@ -22,9 +22,9 @@ class YamlWriter { public: YamlWriter(const char *outfile); virtual ~YamlWriter(); - YamlWriter() = delete; - YamlWriter(const YamlWriter &) = delete; - const YamlWriter & operator=(const YamlWriter &) = delete; + YamlWriter() = delete; + YamlWriter(const YamlWriter &) = delete; + const YamlWriter &operator=(const YamlWriter &) = delete; // emitters void emit(const std::string &key, const double value); diff --git a/unittest/formats/compressed_dump_test.h b/unittest/formats/compressed_dump_test.h index 3c4376a5b8..bb238a63a1 100644 --- a/unittest/formats/compressed_dump_test.h +++ b/unittest/formats/compressed_dump_test.h @@ -101,8 +101,8 @@ public: { BEGIN_HIDE_OUTPUT(); std::string converted_file = compressed_file.substr(0, compressed_file.find_last_of('.')); - std::string cmdline = - fmt::format("\"{}\" -d -c {} > {}", COMPRESS_EXECUTABLE, compressed_file, converted_file); + std::string cmdline = fmt::format("\"{}\" -d -c {} > {}", COMPRESS_EXECUTABLE, + compressed_file, converted_file); system(cmdline.c_str()); END_HIDE_OUTPUT(); return converted_file; diff --git a/unittest/formats/test_atom_styles.cpp b/unittest/formats/test_atom_styles.cpp index 1da2dfa33c..68bc0a4437 100644 --- a/unittest/formats/test_atom_styles.cpp +++ b/unittest/formats/test_atom_styles.cpp @@ -553,8 +553,8 @@ TEST_F(AtomStyleTest, atomic) ASSERT_EQ(lmp->atom->molecular, Atom::ATOMIC); ASSERT_EQ(lmp->atom->ntypes, 2); - auto x = lmp->atom->x; - auto v = lmp->atom->v; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -642,7 +642,7 @@ TEST_F(AtomStyleTest, atomic) command("replicate 2 2 2"); END_HIDE_OUTPUT(); ASSERT_EQ(lmp->atom->map_tag_max, 16); - x = lmp->atom->x; + x = lmp->atom->x; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -870,9 +870,9 @@ TEST_F(AtomStyleTest, charge) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 4); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto q = lmp->atom->q; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *q = lmp->atom->q; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -1056,10 +1056,10 @@ TEST_F(AtomStyleTest, sphere) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 4); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto rmass = lmp->atom->rmass; - auto omega = lmp->atom->omega; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *rmass = lmp->atom->rmass; + auto *omega = lmp->atom->omega; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -1243,13 +1243,13 @@ TEST_F(AtomStyleTest, ellipsoid) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; - auto ellipsoid = lmp->atom->ellipsoid; - auto rmass = lmp->atom->rmass; - auto avec = dynamic_cast(lmp->atom->avec); - auto bonus = avec->bonus; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; + auto *ellipsoid = lmp->atom->ellipsoid; + auto *rmass = lmp->atom->rmass; + auto *avec = dynamic_cast(lmp->atom->avec); + auto *bonus = avec->bonus; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -1571,13 +1571,13 @@ TEST_F(AtomStyleTest, line) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; - auto line = lmp->atom->line; - auto rmass = lmp->atom->rmass; - auto avec = dynamic_cast(lmp->atom->avec); - auto bonus = avec->bonus; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; + auto *line = lmp->atom->line; + auto *rmass = lmp->atom->rmass; + auto *avec = dynamic_cast(lmp->atom->avec); + auto *bonus = avec->bonus; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.0, EPSILON); @@ -1853,14 +1853,14 @@ TEST_F(AtomStyleTest, tri) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; - auto tri = lmp->atom->tri; - auto rmass = lmp->atom->rmass; - auto radius = lmp->atom->radius; - auto avec = dynamic_cast(lmp->atom->avec); - auto bonus = avec->bonus; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; + auto *tri = lmp->atom->tri; + auto *rmass = lmp->atom->rmass; + auto *radius = lmp->atom->radius; + auto *avec = dynamic_cast(lmp->atom->avec); + auto *bonus = avec->bonus; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -2180,7 +2180,7 @@ TEST_F(AtomStyleTest, body_nparticle) ASSERT_ATOM_STATE_EQ(lmp->atom, expected); - auto avec = dynamic_cast(lmp->atom->avec); + auto *avec = dynamic_cast(lmp->atom->avec); ASSERT_NE(lmp->atom->avec, nullptr); ASSERT_NE(avec->bptr, nullptr); ASSERT_THAT(std::string(avec->bptr->style), Eq("nparticle")); @@ -2265,14 +2265,14 @@ TEST_F(AtomStyleTest, body_nparticle) ASSERT_NE(lmp->atom->radius, nullptr); ASSERT_EQ(lmp->atom->mass_setflag, nullptr); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; - auto body = lmp->atom->body; - auto rmass = lmp->atom->rmass; - auto radius = lmp->atom->radius; - auto angmom = lmp->atom->angmom; - auto bonus = avec->bonus; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; + auto *body = lmp->atom->body; + auto *rmass = lmp->atom->rmass; + auto *radius = lmp->atom->radius; + auto *angmom = lmp->atom->angmom; + auto *bonus = avec->bonus; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -2832,9 +2832,9 @@ TEST_F(AtomStyleTest, template) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 12); - auto molecule = lmp->atom->molecule; - auto molindex = lmp->atom->molindex; - auto molatom = lmp->atom->molatom; + auto *molecule = lmp->atom->molecule; + auto *molindex = lmp->atom->molindex; + auto *molatom = lmp->atom->molatom; ASSERT_EQ(molecule[GETIDX(1)], 1); ASSERT_EQ(molecule[GETIDX(2)], 1); @@ -2933,9 +2933,9 @@ TEST_F(AtomStyleTest, template) ASSERT_EQ(molatom[GETIDX(11)], -1); ASSERT_EQ(molatom[GETIDX(12)], -1); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; EXPECT_NEAR(x[GETIDX(10)][0], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(10)][1], -2.0, EPSILON); @@ -3147,7 +3147,7 @@ TEST_F(AtomStyleTest, template_charge) ASSERT_ATOM_STATE_EQ(lmp->atom, expected); - auto hybrid = dynamic_cast(lmp->atom->avec); + auto *hybrid = dynamic_cast(lmp->atom->avec); ASSERT_THAT(std::string(lmp->atom->atom_style), Eq("hybrid")); ASSERT_EQ(hybrid->nstyles, 2); ASSERT_THAT(std::string(hybrid->keywords[0]), Eq("template")); @@ -3247,9 +3247,9 @@ TEST_F(AtomStyleTest, template_charge) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 12); - auto molecule = lmp->atom->molecule; - auto molindex = lmp->atom->molindex; - auto molatom = lmp->atom->molatom; + auto *molecule = lmp->atom->molecule; + auto *molindex = lmp->atom->molindex; + auto *molatom = lmp->atom->molatom; ASSERT_EQ(molecule[GETIDX(1)], 1); ASSERT_EQ(molecule[GETIDX(2)], 1); @@ -3348,10 +3348,10 @@ TEST_F(AtomStyleTest, template_charge) ASSERT_EQ(molatom[GETIDX(11)], -1); ASSERT_EQ(molatom[GETIDX(12)], -1); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; - auto q = lmp->atom->q; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; + auto *q = lmp->atom->q; EXPECT_NEAR(x[GETIDX(10)][0], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(10)][1], -2.0, EPSILON); @@ -3655,9 +3655,9 @@ TEST_F(AtomStyleTest, bond) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto num_bond = lmp->atom->num_bond; - auto bond_type = lmp->atom->bond_type; - auto bond_atom = lmp->atom->bond_atom; + auto *num_bond = lmp->atom->num_bond; + auto *bond_type = lmp->atom->bond_type; + auto *bond_atom = lmp->atom->bond_atom; ASSERT_EQ(num_bond[GETIDX(1)], 2); ASSERT_EQ(num_bond[GETIDX(2)], 0); @@ -3714,12 +3714,12 @@ TEST_F(AtomStyleTest, bond) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; - num_bond = lmp->atom->num_bond; - bond_type = lmp->atom->bond_type; - bond_atom = lmp->atom->bond_atom; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; + num_bond = lmp->atom->num_bond; + bond_type = lmp->atom->bond_type; + bond_atom = lmp->atom->bond_atom; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); @@ -4013,14 +4013,14 @@ TEST_F(AtomStyleTest, angle) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto num_bond = lmp->atom->num_bond; - auto bond_type = lmp->atom->bond_type; - auto bond_atom = lmp->atom->bond_atom; - auto num_angle = lmp->atom->num_angle; - auto angle_type = lmp->atom->angle_type; - auto angle_atom1 = lmp->atom->angle_atom1; - auto angle_atom2 = lmp->atom->angle_atom2; - auto angle_atom3 = lmp->atom->angle_atom3; + auto *num_bond = lmp->atom->num_bond; + auto *bond_type = lmp->atom->bond_type; + auto *bond_atom = lmp->atom->bond_atom; + auto *num_angle = lmp->atom->num_angle; + auto *angle_type = lmp->atom->angle_type; + auto *angle_atom1 = lmp->atom->angle_atom1; + auto *angle_atom2 = lmp->atom->angle_atom2; + auto *angle_atom3 = lmp->atom->angle_atom3; ASSERT_EQ(num_bond[GETIDX(1)], 2); ASSERT_EQ(num_bond[GETIDX(2)], 0); @@ -4107,9 +4107,9 @@ TEST_F(AtomStyleTest, angle) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; num_bond = lmp->atom->num_bond; bond_atom = lmp->atom->bond_atom; num_angle = lmp->atom->num_angle; @@ -4288,7 +4288,7 @@ TEST_F(AtomStyleTest, full_ellipsoid) ASSERT_ATOM_STATE_EQ(lmp->atom, expected); - auto hybrid = dynamic_cast(lmp->atom->avec); + auto *hybrid = dynamic_cast(lmp->atom->avec); ASSERT_THAT(std::string(lmp->atom->atom_style), Eq("hybrid")); ASSERT_EQ(hybrid->nstyles, 2); ASSERT_THAT(std::string(hybrid->keywords[0]), Eq("full")); @@ -4398,15 +4398,15 @@ TEST_F(AtomStyleTest, full_ellipsoid) ASSERT_EQ(lmp->atom->map_user, 1); ASSERT_EQ(lmp->atom->map_tag_max, 6); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto q = lmp->atom->q; - auto type = lmp->atom->type; - auto ellipsoid = lmp->atom->ellipsoid; - auto rmass = lmp->atom->rmass; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *q = lmp->atom->q; + auto *type = lmp->atom->type; + auto *ellipsoid = lmp->atom->ellipsoid; + auto *rmass = lmp->atom->rmass; - auto avec = dynamic_cast(hybrid->styles[1]); - auto bonus = avec->bonus; + auto *avec = dynamic_cast(hybrid->styles[1]); + auto *bonus = avec->bonus; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -4768,9 +4768,9 @@ TEST_F(AtomStyleTest, property_atom) ASSERT_EQ(lmp->atom->map_user, Atom::MAP_ARRAY); ASSERT_EQ(lmp->atom->map_tag_max, 4); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto q = lmp->atom->q; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *q = lmp->atom->q; EXPECT_NEAR(x[GETIDX(1)][0], -2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], 2.0, EPSILON); EXPECT_NEAR(x[GETIDX(1)][2], 0.1, EPSILON); @@ -4805,10 +4805,10 @@ TEST_F(AtomStyleTest, property_atom) ASSERT_EQ(lmp->atom->mass_setflag[1], 1); ASSERT_EQ(lmp->atom->mass_setflag[2], 1); - auto rmass = lmp->atom->rmass; - auto one = lmp->atom->ivector[0]; - auto two = lmp->atom->dvector[0]; - auto three = lmp->atom->dvector[1]; + auto *rmass = lmp->atom->rmass; + auto *one = lmp->atom->ivector[0]; + auto *two = lmp->atom->dvector[0]; + auto *three = lmp->atom->dvector[1]; EXPECT_NEAR(rmass[GETIDX(1)], 4.0, EPSILON); EXPECT_NEAR(rmass[GETIDX(2)], 4.0, EPSILON); @@ -4939,7 +4939,7 @@ TEST_F(AtomStyleTest, oxdna) ASSERT_ATOM_STATE_EQ(lmp->atom, expected); - auto hybrid = dynamic_cast(lmp->atom->avec); + auto *hybrid = dynamic_cast(lmp->atom->avec); ASSERT_THAT(std::string(lmp->atom->atom_style), Eq("hybrid")); ASSERT_EQ(hybrid->nstyles, 3); ASSERT_THAT(std::string(hybrid->keywords[0]), Eq("bond")); @@ -5152,14 +5152,14 @@ TEST_F(AtomStyleTest, oxdna) ASSERT_NE(lmp->atom->mass_setflag, nullptr); ASSERT_NE(lmp->atom->id5p, nullptr); - auto x = lmp->atom->x; - auto v = lmp->atom->v; - auto type = lmp->atom->type; - auto ellipsoid = lmp->atom->ellipsoid; - auto rmass = lmp->atom->rmass; + auto *x = lmp->atom->x; + auto *v = lmp->atom->v; + auto *type = lmp->atom->type; + auto *ellipsoid = lmp->atom->ellipsoid; + auto *rmass = lmp->atom->rmass; - auto avec = dynamic_cast(hybrid->styles[1]); - auto bonus = avec->bonus; + auto *avec = dynamic_cast(hybrid->styles[1]); + auto *bonus = avec->bonus; EXPECT_NEAR(x[GETIDX(1)][0], -0.33741452300167507, EPSILON); EXPECT_NEAR(x[GETIDX(1)][1], -0.43708835412476305, EPSILON); @@ -5328,10 +5328,10 @@ TEST_F(AtomStyleTest, oxdna) EXPECT_NEAR(bonus[9].quat[2], 0.9849325709665359, EPSILON); EXPECT_NEAR(bonus[9].quat[3], -0.0516705065113425, EPSILON); - auto num_bond = lmp->atom->num_bond; - auto bond_type = lmp->atom->bond_type; - auto bond_atom = lmp->atom->bond_atom; - auto id5p = lmp->atom->id5p; + auto *num_bond = lmp->atom->num_bond; + auto *bond_type = lmp->atom->bond_type; + auto *bond_atom = lmp->atom->bond_atom; + auto *id5p = lmp->atom->id5p; ASSERT_EQ(num_bond[GETIDX(1)], 1); ASSERT_EQ(num_bond[GETIDX(2)], 1); diff --git a/unittest/formats/test_dump_atom_compressed.cpp b/unittest/formats/test_dump_atom_compressed.cpp index ea240ef4e4..9cf2a45ee6 100644 --- a/unittest/formats/test_dump_atom_compressed.cpp +++ b/unittest/formats/test_dump_atom_compressed.cpp @@ -93,15 +93,15 @@ TEST_F(DumpAtomCompressTest, compressed_multi_file_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_run1_*.melt"; - auto base_name_0 = "multi_file_run1_0.melt"; - auto base_name_1 = "multi_file_run1_1.melt"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *base_name = "multi_file_run1_*.melt"; + const auto *base_name_0 = "multi_file_run1_0.melt"; + const auto *base_name_1 = "multi_file_run1_1.melt"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); if (compression_style == "atom/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, "", "", "", "checksum no", 1); @@ -133,15 +133,15 @@ TEST_F(DumpAtomCompressTest, compressed_multi_file_with_pad_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_pad_run1_*.melt"; - auto base_name_0 = "multi_file_pad_run1_000.melt"; - auto base_name_1 = "multi_file_pad_run1_001.melt"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *base_name = "multi_file_pad_run1_*.melt"; + const auto *base_name_0 = "multi_file_pad_run1_000.melt"; + const auto *base_name_1 = "multi_file_pad_run1_001.melt"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); generate_text_and_compressed_dump(text_file, compressed_file, "", "pad 3", 1); @@ -174,18 +174,18 @@ TEST_F(DumpAtomCompressTest, compressed_multi_file_with_maxfiles_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_maxfiles_run1_*.melt"; - auto base_name_0 = "multi_file_maxfiles_run1_0.melt"; - auto base_name_1 = "multi_file_maxfiles_run1_1.melt"; - auto base_name_2 = "multi_file_maxfiles_run1_2.melt"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto text_file_2 = text_dump_filename(base_name_2); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto compressed_file_2 = compressed_dump_filename(base_name_2); + const auto *base_name = "multi_file_maxfiles_run1_*.melt"; + const auto *base_name_0 = "multi_file_maxfiles_run1_0.melt"; + const auto *base_name_1 = "multi_file_maxfiles_run1_1.melt"; + const auto *base_name_2 = "multi_file_maxfiles_run1_2.melt"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto text_file_2 = text_dump_filename(base_name_2); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + auto compressed_file_2 = compressed_dump_filename(base_name_2); generate_text_and_compressed_dump(text_file, compressed_file, "", "maxfiles 2", 2); @@ -220,9 +220,9 @@ TEST_F(DumpAtomCompressTest, compressed_with_units_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "with_units_run0.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "with_units_run0.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); generate_text_and_compressed_dump(text_file, compressed_file, "", "scale no units yes", 0); @@ -244,9 +244,9 @@ TEST_F(DumpAtomCompressTest, compressed_with_time_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "with_time_run0.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "with_time_run0.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); generate_text_and_compressed_dump(text_file, compressed_file, "", "scale no time yes", 0); @@ -268,9 +268,9 @@ TEST_F(DumpAtomCompressTest, compressed_triclinic_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "tri_run0.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "tri_run0.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); enable_triclinic(); generate_text_and_compressed_dump(text_file, compressed_file, "", "", 0); @@ -293,9 +293,9 @@ TEST_F(DumpAtomCompressTest, compressed_triclinic_with_units_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "tri_with_units_run0.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "tri_with_units_run0.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); enable_triclinic(); generate_text_and_compressed_dump(text_file, compressed_file, "", "scale no units yes", 0); @@ -318,9 +318,9 @@ TEST_F(DumpAtomCompressTest, compressed_triclinic_with_time_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "tri_with_time_run0.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "tri_with_time_run0.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); enable_triclinic(); generate_text_and_compressed_dump(text_file, compressed_file, "", "scale no time yes", 0); @@ -343,9 +343,9 @@ TEST_F(DumpAtomCompressTest, compressed_triclinic_with_image_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "tri_with_image_run0.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "tri_with_image_run0.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); enable_triclinic(); generate_text_and_compressed_dump(text_file, compressed_file, "", "image yes", 0); @@ -396,9 +396,9 @@ TEST_F(DumpAtomCompressTest, compressed_modify_clevel_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "modify_clevel_run0.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "modify_clevel_run0.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); generate_text_and_compressed_dump(text_file, compressed_file, "", "", "", "compression_level 3", 0); diff --git a/unittest/formats/test_dump_cfg.cpp b/unittest/formats/test_dump_cfg.cpp index fe08485ac4..2e094c3691 100644 --- a/unittest/formats/test_dump_cfg.cpp +++ b/unittest/formats/test_dump_cfg.cpp @@ -51,8 +51,8 @@ TEST_F(DumpCfgTest, invalid_options) TEST_F(DumpCfgTest, require_multifile) { - auto dump_file = "dump.melt.cfg_run.cfg"; - auto fields = + const auto *dump_file = "dump.melt.cfg_run.cfg"; + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz xu yu zu xsu ysu zsu vx vy vz fx fy fz"; BEGIN_HIDE_OUTPUT(); @@ -64,8 +64,8 @@ TEST_F(DumpCfgTest, require_multifile) TEST_F(DumpCfgTest, run0) { - auto dump_file = "dump_cfg_run*.melt.cfg"; - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *dump_file = "dump_cfg_run*.melt.cfg"; + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_dump(dump_file, fields, "", 0); @@ -78,8 +78,8 @@ TEST_F(DumpCfgTest, run0) TEST_F(DumpCfgTest, write_dump) { - auto dump_file = "dump_cfg_run*.melt.cfg"; - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *dump_file = "dump_cfg_run*.melt.cfg"; + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; BEGIN_HIDE_OUTPUT(); command("run 0 post no"); @@ -105,8 +105,8 @@ TEST_F(DumpCfgTest, write_dump) TEST_F(DumpCfgTest, unwrap_run0) { - auto dump_file = "dump_cfg_unwrap_run*.melt.cfg"; - auto fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *dump_file = "dump_cfg_unwrap_run*.melt.cfg"; + const auto *fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_dump(dump_file, fields, "", 0); @@ -119,8 +119,8 @@ TEST_F(DumpCfgTest, unwrap_run0) TEST_F(DumpCfgTest, no_buffer_run0) { - auto dump_file = "dump_cfg_no_buffer_run*.melt.cfg"; - auto fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *dump_file = "dump_cfg_no_buffer_run*.melt.cfg"; + const auto *fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_dump(dump_file, fields, "buffer no", 0); @@ -133,8 +133,8 @@ TEST_F(DumpCfgTest, no_buffer_run0) TEST_F(DumpCfgTest, no_unwrap_no_buffer_run0) { - auto dump_file = "dump_cfg_no_unwrap_no_buffer_run*.melt.cfg"; - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *dump_file = "dump_cfg_no_unwrap_no_buffer_run*.melt.cfg"; + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_dump(dump_file, fields, "buffer no", 0); diff --git a/unittest/formats/test_dump_cfg_compressed.cpp b/unittest/formats/test_dump_cfg_compressed.cpp index 158e8926bf..b152637374 100644 --- a/unittest/formats/test_dump_cfg_compressed.cpp +++ b/unittest/formats/test_dump_cfg_compressed.cpp @@ -35,14 +35,14 @@ TEST_F(DumpCfgCompressTest, compressed_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "run*.melt.cfg"; + const auto *base_name = "run*.melt.cfg"; auto text_files = text_dump_filename(base_name); auto compressed_files = compressed_dump_filename(base_name); - auto base_name_0 = "run0.melt.cfg"; - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *base_name_0 = "run0.melt.cfg"; + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; if (compression_style == "cfg/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, fields, fields, "", @@ -69,14 +69,14 @@ TEST_F(DumpCfgCompressTest, compressed_no_buffer_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "no_buffer_run*.melt.cfg"; + const auto *base_name = "no_buffer_run*.melt.cfg"; auto text_files = text_dump_filename(base_name); auto compressed_files = compressed_dump_filename(base_name); - auto base_name_0 = "no_buffer_run0.melt.cfg"; - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *base_name_0 = "no_buffer_run0.melt.cfg"; + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; if (compression_style == "cfg/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, fields, fields, "buffer no", @@ -103,14 +103,14 @@ TEST_F(DumpCfgCompressTest, compressed_unwrap_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "unwrap_run*.melt.cfg"; + const auto *base_name = "unwrap_run*.melt.cfg"; auto text_files = text_dump_filename(base_name); auto compressed_files = compressed_dump_filename(base_name); - auto base_name_0 = "unwrap_run0.melt.cfg"; - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *base_name_0 = "unwrap_run0.melt.cfg"; + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_text_and_compressed_dump(text_files, compressed_files, fields, "", 0); @@ -132,16 +132,16 @@ TEST_F(DumpCfgCompressTest, compressed_multi_file_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_run1_*.melt.cfg"; - auto base_name_0 = "multi_file_run1_0.melt.cfg"; - auto base_name_1 = "multi_file_run1_1.melt.cfg"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *base_name = "multi_file_run1_*.melt.cfg"; + const auto *base_name_0 = "multi_file_run1_0.melt.cfg"; + const auto *base_name_1 = "multi_file_run1_1.melt.cfg"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; if (compression_style == "cfg/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "", @@ -174,16 +174,16 @@ TEST_F(DumpCfgCompressTest, compressed_multi_file_with_pad_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_pad_run1_*.melt.cfg"; - auto base_name_0 = "multi_file_pad_run1_000.melt.cfg"; - auto base_name_1 = "multi_file_pad_run1_001.melt.cfg"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *base_name = "multi_file_pad_run1_*.melt.cfg"; + const auto *base_name_0 = "multi_file_pad_run1_000.melt.cfg"; + const auto *base_name_1 = "multi_file_pad_run1_001.melt.cfg"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_text_and_compressed_dump(text_file, compressed_file, fields, "pad 3", 1); @@ -216,19 +216,19 @@ TEST_F(DumpCfgCompressTest, compressed_multi_file_with_maxfiles_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_maxfiles_run1_*.melt.cfg"; - auto base_name_0 = "multi_file_maxfiles_run1_0.melt.cfg"; - auto base_name_1 = "multi_file_maxfiles_run1_1.melt.cfg"; - auto base_name_2 = "multi_file_maxfiles_run1_2.melt.cfg"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto text_file_2 = text_dump_filename(base_name_2); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto compressed_file_2 = compressed_dump_filename(base_name_2); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *base_name = "multi_file_maxfiles_run1_*.melt.cfg"; + const auto *base_name_0 = "multi_file_maxfiles_run1_0.melt.cfg"; + const auto *base_name_1 = "multi_file_maxfiles_run1_1.melt.cfg"; + const auto *base_name_2 = "multi_file_maxfiles_run1_2.melt.cfg"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto text_file_2 = text_dump_filename(base_name_2); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + auto compressed_file_2 = compressed_dump_filename(base_name_2); + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_text_and_compressed_dump(text_file, compressed_file, fields, "maxfiles 2", 2); @@ -263,7 +263,7 @@ TEST_F(DumpCfgCompressTest, compressed_modify_bad_param) { if (compression_style != "cfg/gz") GTEST_SKIP(); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; BEGIN_HIDE_OUTPUT(); command(fmt::format("dump id1 all {} 1 {} {}", compression_style, compressed_dump_filename("modify_bad_param_run0_*.melt.cfg"), fields)); @@ -278,7 +278,7 @@ TEST_F(DumpCfgCompressTest, compressed_modify_multi_bad_param) { if (compression_style != "cfg/gz") GTEST_SKIP(); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; BEGIN_HIDE_OUTPUT(); command(fmt::format("dump id1 all {} 1 {} {}", compression_style, compressed_dump_filename("modify_multi_bad_param_run0_*.melt.cfg"), @@ -294,13 +294,13 @@ TEST_F(DumpCfgCompressTest, compressed_modify_clevel_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "modify_clevel_run*.melt.cfg"; - auto base_name_0 = "modify_clevel_run0.melt.cfg"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; + const auto *base_name = "modify_clevel_run*.melt.cfg"; + const auto *base_name_0 = "modify_clevel_run0.melt.cfg"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz"; generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "", "compression_level 3", 0); diff --git a/unittest/formats/test_dump_custom.cpp b/unittest/formats/test_dump_custom.cpp index 08d5d65695..99693ec088 100644 --- a/unittest/formats/test_dump_custom.cpp +++ b/unittest/formats/test_dump_custom.cpp @@ -111,7 +111,7 @@ public: TEST_F(DumpCustomTest, run1) { auto dump_file = dump_filename("run1"); - auto fields = + const auto *fields = "id type proc procp1 mass x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; generate_dump(dump_file, fields, "units yes", 1); @@ -128,8 +128,8 @@ TEST_F(DumpCustomTest, run1) TEST_F(DumpCustomTest, thresh_run0) { - auto dump_file = dump_filename("thresh_run0"); - auto fields = "id type x y z"; + auto dump_file = dump_filename("thresh_run0"); + const auto *fields = "id type x y z"; generate_dump(dump_file, fields, "units yes thresh x < 1 thresh y < 1 thresh z < 1", 0); @@ -149,8 +149,8 @@ TEST_F(DumpCustomTest, compute_run0) command("compute comp all property/atom x y z"); END_HIDE_OUTPUT(); - auto dump_file = dump_filename("compute_run0"); - auto fields = "id type x y z c_comp[1] c_comp[2] c_comp[3]"; + auto dump_file = dump_filename("compute_run0"); + const auto *fields = "id type x y z c_comp[1] c_comp[2] c_comp[3]"; generate_dump(dump_file, fields, "units yes", 0); @@ -172,8 +172,8 @@ TEST_F(DumpCustomTest, fix_run0) command("fix numdiff all numdiff 1 0.0001"); END_HIDE_OUTPUT(); - auto dump_file = dump_filename("fix_run0"); - auto fields = "id x y z f_numdiff[1] f_numdiff[2] f_numdiff[3]"; + auto dump_file = dump_filename("fix_run0"); + const auto *fields = "id x y z f_numdiff[1] f_numdiff[2] f_numdiff[3]"; generate_dump(dump_file, fields, "units yes", 0); @@ -194,8 +194,8 @@ TEST_F(DumpCustomTest, custom_run0) command("compute 1 all property/atom i_flag1 d_flag2"); END_HIDE_OUTPUT(); - auto dump_file = dump_filename("custom_run0"); - auto fields = "id x y z i_flag1 d_flag2"; + auto dump_file = dump_filename("custom_run0"); + const auto *fields = "id x y z i_flag1 d_flag2"; generate_dump(dump_file, fields, "units yes", 0); @@ -215,7 +215,8 @@ TEST_F(DumpCustomTest, binary_run1) auto text_file = text_dump_filename("run1"); auto binary_file = binary_dump_filename("run1"); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; generate_text_and_binary_dump(text_file, binary_file, fields, "units yes", 1); @@ -234,7 +235,8 @@ TEST_F(DumpCustomTest, binary_run1) TEST_F(DumpCustomTest, triclinic_run1) { auto dump_file = dump_filename("tri_run1"); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; enable_triclinic(); @@ -254,9 +256,9 @@ TEST_F(DumpCustomTest, binary_triclinic_run1) { if (!BINARY2TXT_EXECUTABLE) GTEST_SKIP(); - auto text_file = text_dump_filename("tri_run1"); - auto binary_file = binary_dump_filename("tri_run1"); - auto fields = "id type proc x y z xs ys zs xsu ysu zsu vx vy vz fx fy fz"; + auto text_file = text_dump_filename("tri_run1"); + auto binary_file = binary_dump_filename("tri_run1"); + const auto *fields = "id type proc x y z xs ys zs xsu ysu zsu vx vy vz fx fy fz"; enable_triclinic(); @@ -281,8 +283,8 @@ TEST_F(DumpCustomTest, with_variable_run1) command("variable p atom (c_1%10)+1"); END_HIDE_OUTPUT(); - auto dump_file = dump_filename("with_variable_run1"); - auto fields = "id type x y z v_p"; + auto dump_file = dump_filename("with_variable_run1"); + const auto *fields = "id type x y z v_p"; generate_dump(dump_file, fields, "units yes", 1); @@ -298,8 +300,8 @@ TEST_F(DumpCustomTest, with_variable_run1) TEST_F(DumpCustomTest, run1plus1) { - auto dump_file = dump_filename("run1plus1"); - auto fields = "id type x y z"; + auto dump_file = dump_filename("run1plus1"); + const auto *fields = "id type x y z"; generate_dump(dump_file, fields, "units yes", 1); @@ -315,8 +317,8 @@ TEST_F(DumpCustomTest, run1plus1) TEST_F(DumpCustomTest, run2) { - auto dump_file = dump_filename("run2"); - auto fields = "id type x y z"; + auto dump_file = dump_filename("run2"); + const auto *fields = "id type x y z"; generate_dump(dump_file, fields, "", 2); ASSERT_FILE_EXISTS(dump_file); @@ -326,8 +328,8 @@ TEST_F(DumpCustomTest, run2) TEST_F(DumpCustomTest, rerun) { - auto dump_file = dump_filename("rerun"); - auto fields = "id type xs ys zs"; + auto dump_file = dump_filename("rerun"); + const auto *fields = "id type xs ys zs"; HIDE_OUTPUT([&] { command("fix 1 all nve"); @@ -358,8 +360,8 @@ TEST_F(DumpCustomTest, rerun) TEST_F(DumpCustomTest, rerun_bin) { - auto dump_file = binary_dump_filename("rerun"); - auto fields = "id type xs ys zs"; + auto dump_file = binary_dump_filename("rerun"); + const auto *fields = "id type xs ys zs"; HIDE_OUTPUT([&] { command("fix 1 all nve"); diff --git a/unittest/formats/test_dump_custom_compressed.cpp b/unittest/formats/test_dump_custom_compressed.cpp index 91d72e4483..4a3e4b5284 100644 --- a/unittest/formats/test_dump_custom_compressed.cpp +++ b/unittest/formats/test_dump_custom_compressed.cpp @@ -31,10 +31,11 @@ TEST_F(DumpCustomCompressTest, compressed_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "custom_run1.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *base_name = "custom_run1.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; if (compression_style == "custom/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "units yes", @@ -61,10 +62,11 @@ TEST_F(DumpCustomCompressTest, compressed_with_time_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "with_time_custom_run1.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *base_name = "with_time_custom_run1.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; if (compression_style == "custom/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "time yes", @@ -91,10 +93,11 @@ TEST_F(DumpCustomCompressTest, compressed_no_buffer_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "no_buffer_custom_run1.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *base_name = "no_buffer_custom_run1.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; if (compression_style == "custom/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "buffer no", @@ -121,10 +124,10 @@ TEST_F(DumpCustomCompressTest, compressed_triclinic_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "custom_tri_run1.melt"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); - auto fields = "id type proc x y z xs ys zs xsu ysu zsu vx vy vz fx fy fz"; + const auto *base_name = "custom_tri_run1.melt"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); + const auto *fields = "id type proc x y z xs ys zs xsu ysu zsu vx vy vz fx fy fz"; enable_triclinic(); @@ -148,16 +151,17 @@ TEST_F(DumpCustomCompressTest, compressed_multi_file_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_run1_*.melt.custom"; - auto base_name_0 = "multi_file_run1_0.melt.custom"; - auto base_name_1 = "multi_file_run1_1.melt.custom"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *base_name = "multi_file_run1_*.melt.custom"; + const auto *base_name_0 = "multi_file_run1_0.melt.custom"; + const auto *base_name_1 = "multi_file_run1_1.melt.custom"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; if (compression_style == "custom/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "", @@ -190,16 +194,17 @@ TEST_F(DumpCustomCompressTest, compressed_multi_file_with_pad_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_pad_run1_*.melt.custom"; - auto base_name_0 = "multi_file_pad_run1_000.melt.custom"; - auto base_name_1 = "multi_file_pad_run1_001.melt.custom"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *base_name = "multi_file_pad_run1_*.melt.custom"; + const auto *base_name_0 = "multi_file_pad_run1_000.melt.custom"; + const auto *base_name_1 = "multi_file_pad_run1_001.melt.custom"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; generate_text_and_compressed_dump(text_file, compressed_file, fields, "pad 3", 1); @@ -232,19 +237,20 @@ TEST_F(DumpCustomCompressTest, compressed_multi_file_with_maxfiles_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_maxfiles_run1_*.melt.custom"; - auto base_name_0 = "multi_file_maxfiles_run1_0.melt.custom"; - auto base_name_1 = "multi_file_maxfiles_run1_1.melt.custom"; - auto base_name_2 = "multi_file_maxfiles_run1_2.melt.custom"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto text_file_2 = text_dump_filename(base_name_2); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto compressed_file_2 = compressed_dump_filename(base_name_2); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *base_name = "multi_file_maxfiles_run1_*.melt.custom"; + const auto *base_name_0 = "multi_file_maxfiles_run1_0.melt.custom"; + const auto *base_name_1 = "multi_file_maxfiles_run1_1.melt.custom"; + const auto *base_name_2 = "multi_file_maxfiles_run1_2.melt.custom"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto text_file_2 = text_dump_filename(base_name_2); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + auto compressed_file_2 = compressed_dump_filename(base_name_2); + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; generate_text_and_compressed_dump(text_file, compressed_file, fields, "maxfiles 2", 2); @@ -279,7 +285,8 @@ TEST_F(DumpCustomCompressTest, compressed_modify_bad_param) { if (compression_style != "custom/gz") GTEST_SKIP(); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; command(fmt::format("dump id1 all {} 1 {} {}", compression_style, compressed_dump_filename("modify_bad_param_run0_*.melt.custom"), fields)); @@ -292,7 +299,8 @@ TEST_F(DumpCustomCompressTest, compressed_modify_multi_bad_param) { if (compression_style != "custom/gz") GTEST_SKIP(); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; command(fmt::format("dump id1 all {} 1 {} {}", compression_style, compressed_dump_filename("modify_multi_bad_param_run0_*.melt.custom"), fields)); @@ -306,11 +314,12 @@ TEST_F(DumpCustomCompressTest, compressed_modify_clevel_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "modify_clevel_run0.melt.custom"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "modify_clevel_run0.melt.custom"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); - auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; + const auto *fields = + "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz"; generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "", "compression_level 3", 0); diff --git a/unittest/formats/test_dump_local.cpp b/unittest/formats/test_dump_local.cpp index d138ee3ac3..004a0590cd 100644 --- a/unittest/formats/test_dump_local.cpp +++ b/unittest/formats/test_dump_local.cpp @@ -73,7 +73,7 @@ public: TEST_F(DumpLocalTest, run0) { - auto dump_file = "dump_local_run0.melt"; + const auto *dump_file = "dump_local_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "", 0); ASSERT_FILE_EXISTS(dump_file); @@ -98,7 +98,7 @@ TEST_F(DumpLocalTest, run0) TEST_F(DumpLocalTest, label_run0) { - auto dump_file = "dump_local_label_run0.melt"; + const auto *dump_file = "dump_local_label_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "label ELEMENTS", 0); ASSERT_FILE_EXISTS(dump_file); @@ -110,7 +110,7 @@ TEST_F(DumpLocalTest, label_run0) TEST_F(DumpLocalTest, format_line_run0) { - auto dump_file = "dump_local_format_line_run0.melt"; + const auto *dump_file = "dump_local_format_line_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "format line \"%d %20.8g\"", 0); ASSERT_FILE_EXISTS(dump_file); @@ -123,7 +123,7 @@ TEST_F(DumpLocalTest, format_line_run0) TEST_F(DumpLocalTest, format_int_run0) { - auto dump_file = "dump_local_format_int_run0.melt"; + const auto *dump_file = "dump_local_format_int_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "format int \"%20d\"", 0); ASSERT_FILE_EXISTS(dump_file); @@ -136,7 +136,7 @@ TEST_F(DumpLocalTest, format_int_run0) TEST_F(DumpLocalTest, format_float_run0) { - auto dump_file = "dump_local_format_float_run0.melt"; + const auto *dump_file = "dump_local_format_float_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "format float \"%20.5g\"", 0); ASSERT_FILE_EXISTS(dump_file); @@ -149,7 +149,7 @@ TEST_F(DumpLocalTest, format_float_run0) TEST_F(DumpLocalTest, format_column_run0) { - auto dump_file = "dump_local_format_column_run0.melt"; + const auto *dump_file = "dump_local_format_column_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "format 1 \"%20d\"", 0); ASSERT_FILE_EXISTS(dump_file); @@ -162,7 +162,7 @@ TEST_F(DumpLocalTest, format_column_run0) TEST_F(DumpLocalTest, no_buffer_run0) { - auto dump_file = "dump_local_format_line_run0.melt"; + const auto *dump_file = "dump_local_format_line_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "buffer no", 0); ASSERT_FILE_EXISTS(dump_file); @@ -187,7 +187,7 @@ TEST_F(DumpLocalTest, no_buffer_run0) TEST_F(DumpLocalTest, with_units_run0) { - auto dump_file = "dump_with_units_run0.melt"; + const auto *dump_file = "dump_with_units_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "units yes", 0); ASSERT_FILE_EXISTS(dump_file); @@ -206,7 +206,7 @@ TEST_F(DumpLocalTest, with_units_run0) TEST_F(DumpLocalTest, with_time_run0) { - auto dump_file = "dump_with_time_run0.melt"; + const auto *dump_file = "dump_with_time_run0.melt"; generate_dump(dump_file, "index c_comp[1]", "time yes", 0); ASSERT_FILE_EXISTS(dump_file); @@ -225,7 +225,7 @@ TEST_F(DumpLocalTest, with_time_run0) TEST_F(DumpLocalTest, triclinic_run0) { - auto dump_file = "dump_local_triclinic_run0.melt"; + const auto *dump_file = "dump_local_triclinic_run0.melt"; enable_triclinic(); generate_dump(dump_file, "index c_comp[1]", "", 0); diff --git a/unittest/formats/test_dump_local_compressed.cpp b/unittest/formats/test_dump_local_compressed.cpp index 8523e99a30..dff182013a 100644 --- a/unittest/formats/test_dump_local_compressed.cpp +++ b/unittest/formats/test_dump_local_compressed.cpp @@ -40,13 +40,13 @@ TEST_F(DumpLocalCompressTest, compressed_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "run*.melt.local"; - auto base_name_0 = "run0.melt.local"; - auto text_files = text_dump_filename(base_name); - auto compressed_files = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "index c_comp[1]"; + const auto *base_name = "run*.melt.local"; + const auto *base_name_0 = "run0.melt.local"; + auto text_files = text_dump_filename(base_name); + auto compressed_files = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "index c_comp[1]"; if (compression_style == "local/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, fields, fields, "", @@ -73,13 +73,13 @@ TEST_F(DumpLocalCompressTest, compressed_no_buffer_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "no_buffer_run*.melt.local"; - auto base_name_0 = "no_buffer_run0.melt.local"; - auto text_files = text_dump_filename(base_name); - auto compressed_files = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "index c_comp[1]"; + const auto *base_name = "no_buffer_run*.melt.local"; + const auto *base_name_0 = "no_buffer_run0.melt.local"; + auto text_files = text_dump_filename(base_name); + auto compressed_files = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "index c_comp[1]"; if (compression_style == "local/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, fields, fields, "buffer no", @@ -106,13 +106,13 @@ TEST_F(DumpLocalCompressTest, compressed_with_time_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "with_time_run*.melt.local"; - auto base_name_0 = "with_time_run0.melt.local"; - auto text_files = text_dump_filename(base_name); - auto compressed_files = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "index c_comp[1]"; + const auto *base_name = "with_time_run*.melt.local"; + const auto *base_name_0 = "with_time_run0.melt.local"; + auto text_files = text_dump_filename(base_name); + auto compressed_files = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "index c_comp[1]"; if (compression_style == "local/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, fields, fields, "time yes", @@ -139,13 +139,13 @@ TEST_F(DumpLocalCompressTest, compressed_with_units_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "with_units_run*.melt.local"; - auto base_name_0 = "with_units_run0.melt.local"; - auto text_files = text_dump_filename(base_name); - auto compressed_files = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "index c_comp[1]"; + const auto *base_name = "with_units_run*.melt.local"; + const auto *base_name_0 = "with_units_run0.melt.local"; + auto text_files = text_dump_filename(base_name); + auto compressed_files = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "index c_comp[1]"; if (compression_style == "local/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, fields, fields, "units yes", @@ -173,13 +173,13 @@ TEST_F(DumpLocalCompressTest, compressed_triclinic_run0) if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); enable_triclinic(); - auto base_name = "triclinic_run*.melt.local"; - auto base_name_0 = "triclinic_run0.melt.local"; - auto text_files = text_dump_filename(base_name); - auto compressed_files = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto fields = "index c_comp[1]"; + const auto *base_name = "triclinic_run*.melt.local"; + const auto *base_name_0 = "triclinic_run0.melt.local"; + auto text_files = text_dump_filename(base_name); + auto compressed_files = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *fields = "index c_comp[1]"; if (compression_style == "local/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, fields, fields, "", @@ -206,16 +206,16 @@ TEST_F(DumpLocalCompressTest, compressed_multi_file_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_run1_*.melt.local"; - auto base_name_0 = "multi_file_run1_0.melt.local"; - auto base_name_1 = "multi_file_run1_1.melt.local"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto fields = "index c_comp[1]"; + const auto *base_name = "multi_file_run1_*.melt.local"; + const auto *base_name_0 = "multi_file_run1_0.melt.local"; + const auto *base_name_1 = "multi_file_run1_1.melt.local"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *fields = "index c_comp[1]"; if (compression_style == "local/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "", @@ -248,16 +248,16 @@ TEST_F(DumpLocalCompressTest, compressed_multi_file_with_pad_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_pad_run1_*.melt.local"; - auto base_name_0 = "multi_file_pad_run1_000.melt.local"; - auto base_name_1 = "multi_file_pad_run1_001.melt.local"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto fields = "index c_comp[1]"; + const auto *base_name = "multi_file_pad_run1_*.melt.local"; + const auto *base_name_0 = "multi_file_pad_run1_000.melt.local"; + const auto *base_name_1 = "multi_file_pad_run1_001.melt.local"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *fields = "index c_comp[1]"; generate_text_and_compressed_dump(text_file, compressed_file, fields, "pad 3", 1); @@ -290,19 +290,19 @@ TEST_F(DumpLocalCompressTest, compressed_multi_file_with_maxfiles_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_maxfiles_run1_*.melt.local"; - auto base_name_0 = "multi_file_maxfiles_run1_0.melt.local"; - auto base_name_1 = "multi_file_maxfiles_run1_1.melt.local"; - auto base_name_2 = "multi_file_maxfiles_run1_2.melt.local"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto text_file_2 = text_dump_filename(base_name_2); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto compressed_file_2 = compressed_dump_filename(base_name_2); - auto fields = "index c_comp[1]"; + const auto *base_name = "multi_file_maxfiles_run1_*.melt.local"; + const auto *base_name_0 = "multi_file_maxfiles_run1_0.melt.local"; + const auto *base_name_1 = "multi_file_maxfiles_run1_1.melt.local"; + const auto *base_name_2 = "multi_file_maxfiles_run1_2.melt.local"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto text_file_2 = text_dump_filename(base_name_2); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + auto compressed_file_2 = compressed_dump_filename(base_name_2); + const auto *fields = "index c_comp[1]"; generate_text_and_compressed_dump(text_file, compressed_file, fields, "maxfiles 2", 2); @@ -337,7 +337,7 @@ TEST_F(DumpLocalCompressTest, compressed_modify_bad_param) { if (compression_style != "local/gz") GTEST_SKIP(); - auto fields = "index c_comp[1]"; + const auto *fields = "index c_comp[1]"; BEGIN_HIDE_OUTPUT(); command(fmt::format("dump id1 all {} 1 {} {}", compression_style, @@ -353,7 +353,7 @@ TEST_F(DumpLocalCompressTest, compressed_modify_multi_bad_param) { if (compression_style != "local/gz") GTEST_SKIP(); - auto fields = "index c_comp[1]"; + const auto *fields = "index c_comp[1]"; BEGIN_HIDE_OUTPUT(); command(fmt::format("dump id1 all {} 1 {} {}", compression_style, @@ -370,10 +370,10 @@ TEST_F(DumpLocalCompressTest, compressed_modify_clevel_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "modify_clevel_run0.melt.local"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); - auto fields = "index c_comp[1]"; + const auto *base_name = "modify_clevel_run0.melt.local"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); + const auto *fields = "index c_comp[1]"; generate_text_and_compressed_dump(text_file, compressed_file, fields, fields, "", "compression_level 3", 0); diff --git a/unittest/formats/test_dump_netcdf.cpp b/unittest/formats/test_dump_netcdf.cpp index e7288377ae..d85172c70d 100644 --- a/unittest/formats/test_dump_netcdf.cpp +++ b/unittest/formats/test_dump_netcdf.cpp @@ -91,8 +91,8 @@ public: TEST_F(DumpNetCDFTest, run0_plain) { if (!lammps_has_style(lmp, "dump", "netcdf")) GTEST_SKIP(); - auto dump_file = dump_filename("run0"); - auto fields = "id type proc procp1 mass x y z ix iy iz xu yu zu vx vy vz fx fy fz"; + auto dump_file = dump_filename("run0"); + const auto *fields = "id type proc procp1 mass x y z ix iy iz xu yu zu vx vy vz fx fy fz"; set_style("netcdf"); generate_dump(dump_file, fields, "", 0); @@ -285,8 +285,8 @@ TEST_F(DumpNetCDFTest, run0_plain) TEST_F(DumpNetCDFTest, run0_mpi) { if (!lammps_has_style(lmp, "dump", "netcdf/mpiio")) GTEST_SKIP(); - auto dump_file = dump_filename("mpi0"); - auto fields = "id type proc procp1 mass x y z ix iy iz xu yu zu vx vy vz fx fy fz"; + auto dump_file = dump_filename("mpi0"); + const auto *fields = "id type proc procp1 mass x y z ix iy iz xu yu zu vx vy vz fx fy fz"; set_style("netcdf/mpiio"); generate_dump(dump_file, fields, "", 0); diff --git a/unittest/formats/test_dump_xyz_compressed.cpp b/unittest/formats/test_dump_xyz_compressed.cpp index ec47f0e180..78bc70489a 100644 --- a/unittest/formats/test_dump_xyz_compressed.cpp +++ b/unittest/formats/test_dump_xyz_compressed.cpp @@ -31,12 +31,12 @@ TEST_F(DumpXYZCompressTest, compressed_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "run*.melt.xyz"; - auto base_name_0 = "run0.melt.xyz"; - auto text_files = text_dump_filename(base_name); - auto compressed_files = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *base_name = "run*.melt.xyz"; + const auto *base_name_0 = "run0.melt.xyz"; + auto text_files = text_dump_filename(base_name); + auto compressed_files = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); if (compression_style == "xyz/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, "", "", "", "checksum yes", @@ -63,12 +63,12 @@ TEST_F(DumpXYZCompressTest, compressed_no_buffer_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "no_buffer_run*.melt.xyz"; - auto base_name_0 = "no_buffer_run0.melt.xyz"; - auto text_files = text_dump_filename(base_name); - auto compressed_files = compressed_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto compressed_file_0 = compressed_dump_filename(base_name_0); + const auto *base_name = "no_buffer_run*.melt.xyz"; + const auto *base_name_0 = "no_buffer_run0.melt.xyz"; + auto text_files = text_dump_filename(base_name); + auto compressed_files = compressed_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto compressed_file_0 = compressed_dump_filename(base_name_0); if (compression_style == "xyz/zstd") { generate_text_and_compressed_dump(text_files, compressed_files, "", "", "buffer no", @@ -95,15 +95,15 @@ TEST_F(DumpXYZCompressTest, compressed_multi_file_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_run1_*.melt.xyz"; - auto base_name_0 = "multi_file_run1_0.melt.xyz"; - auto base_name_1 = "multi_file_run1_1.melt.xyz"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *base_name = "multi_file_run1_*.melt.xyz"; + const auto *base_name_0 = "multi_file_run1_0.melt.xyz"; + const auto *base_name_1 = "multi_file_run1_1.melt.xyz"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); if (compression_style == "xyz/zstd") { generate_text_and_compressed_dump(text_file, compressed_file, "", "", "", "checksum no", 1); @@ -135,15 +135,15 @@ TEST_F(DumpXYZCompressTest, compressed_multi_file_with_pad_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_pad_run1_*.melt.xyz"; - auto base_name_0 = "multi_file_pad_run1_000.melt.xyz"; - auto base_name_1 = "multi_file_pad_run1_001.melt.xyz"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); + const auto *base_name = "multi_file_pad_run1_*.melt.xyz"; + const auto *base_name_0 = "multi_file_pad_run1_000.melt.xyz"; + const auto *base_name_1 = "multi_file_pad_run1_001.melt.xyz"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); generate_text_and_compressed_dump(text_file, compressed_file, "", "pad 3", 1); @@ -176,18 +176,18 @@ TEST_F(DumpXYZCompressTest, compressed_multi_file_with_maxfiles_run1) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "multi_file_maxfiles_run1_*.melt.xyz"; - auto base_name_0 = "multi_file_maxfiles_run1_0.melt.xyz"; - auto base_name_1 = "multi_file_maxfiles_run1_1.melt.xyz"; - auto base_name_2 = "multi_file_maxfiles_run1_2.melt.xyz"; - auto text_file = text_dump_filename(base_name); - auto text_file_0 = text_dump_filename(base_name_0); - auto text_file_1 = text_dump_filename(base_name_1); - auto text_file_2 = text_dump_filename(base_name_2); - auto compressed_file = compressed_dump_filename(base_name); - auto compressed_file_0 = compressed_dump_filename(base_name_0); - auto compressed_file_1 = compressed_dump_filename(base_name_1); - auto compressed_file_2 = compressed_dump_filename(base_name_2); + const auto *base_name = "multi_file_maxfiles_run1_*.melt.xyz"; + const auto *base_name_0 = "multi_file_maxfiles_run1_0.melt.xyz"; + const auto *base_name_1 = "multi_file_maxfiles_run1_1.melt.xyz"; + const auto *base_name_2 = "multi_file_maxfiles_run1_2.melt.xyz"; + auto text_file = text_dump_filename(base_name); + auto text_file_0 = text_dump_filename(base_name_0); + auto text_file_1 = text_dump_filename(base_name_1); + auto text_file_2 = text_dump_filename(base_name_2); + auto compressed_file = compressed_dump_filename(base_name); + auto compressed_file_0 = compressed_dump_filename(base_name_0); + auto compressed_file_1 = compressed_dump_filename(base_name_1); + auto compressed_file_2 = compressed_dump_filename(base_name_2); generate_text_and_compressed_dump(text_file, compressed_file, "", "maxfiles 2", 2); @@ -250,9 +250,9 @@ TEST_F(DumpXYZCompressTest, compressed_modify_clevel_run0) { if (!COMPRESS_EXECUTABLE) GTEST_SKIP(); - auto base_name = "modify_clevel_run0.melt.xyz"; - auto text_file = text_dump_filename(base_name); - auto compressed_file = compressed_dump_filename(base_name); + const auto *base_name = "modify_clevel_run0.melt.xyz"; + auto text_file = text_dump_filename(base_name); + auto compressed_file = compressed_dump_filename(base_name); generate_text_and_compressed_dump(text_file, compressed_file, "", "", "", "compression_level 3", 0); diff --git a/unittest/formats/test_file_operations.cpp b/unittest/formats/test_file_operations.cpp index 19d7a0999b..cd08650bf8 100644 --- a/unittest/formats/test_file_operations.cpp +++ b/unittest/formats/test_file_operations.cpp @@ -511,10 +511,10 @@ TEST_F(FileOperationsTest, read_data_fix) lmp->atom->molecule[1] = 6; lmp->atom->molecule[2] = 5; lmp->atom->molecule[3] = 6; - lmp->atom->tag[0] = 9; - lmp->atom->tag[1] = 6; - lmp->atom->tag[2] = 7; - lmp->atom->tag[3] = 8; + lmp->atom->tag[0] = 9; + lmp->atom->tag[1] = 6; + lmp->atom->tag[2] = 7; + lmp->atom->tag[3] = 8; lmp->atom->map_init(1); lmp->atom->map_set(); command("write_data test_mol_id_merge.data"); diff --git a/unittest/formats/test_image_flags.cpp b/unittest/formats/test_image_flags.cpp index c915a27c3e..06976e0684 100644 --- a/unittest/formats/test_image_flags.cpp +++ b/unittest/formats/test_image_flags.cpp @@ -61,10 +61,10 @@ protected: TEST_F(ImageFlagsTest, change_box) { - auto image = lmp->atom->image; - int imx = (image[0] & IMGMASK) - IMGMAX; - int imy = (image[0] >> IMGBITS & IMGMASK) - IMGMAX; - int imz = (image[0] >> IMG2BITS) - IMGMAX; + auto *image = lmp->atom->image; + int imx = (image[0] & IMGMASK) - IMGMAX; + int imy = (image[0] >> IMGBITS & IMGMASK) - IMGMAX; + int imz = (image[0] >> IMG2BITS) - IMGMAX; ASSERT_EQ(imx, -1); ASSERT_EQ(imy, 2); @@ -153,10 +153,10 @@ TEST_F(ImageFlagsTest, read_data) command("read_data test_image_flags.data"); END_HIDE_OUTPUT(); - auto image = lmp->atom->image; - int imx = (image[0] & IMGMASK) - IMGMAX; - int imy = (image[0] >> IMGBITS & IMGMASK) - IMGMAX; - int imz = (image[0] >> IMG2BITS) - IMGMAX; + auto *image = lmp->atom->image; + int imx = (image[0] & IMGMASK) - IMGMAX; + int imy = (image[0] >> IMGBITS & IMGMASK) - IMGMAX; + int imz = (image[0] >> IMG2BITS) - IMGMAX; ASSERT_EQ(imx, -1); ASSERT_EQ(imy, 2); diff --git a/unittest/formats/test_potential_file_reader.cpp b/unittest/formats/test_potential_file_reader.cpp index 3d14a73d31..b1ebcbdd7c 100644 --- a/unittest/formats/test_potential_file_reader.cpp +++ b/unittest/formats/test_potential_file_reader.cpp @@ -67,7 +67,7 @@ TEST_F(PotentialFileReaderTest, Sw_native) PotentialFileReader reader(lmp, "Si.sw", "Stillinger-Weber"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairSW::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairSW::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairSW::NPARAMS_PER_LINE); } @@ -79,7 +79,7 @@ TEST_F(PotentialFileReaderTest, Sw_conv) PotentialFileReader reader(lmp, "Si.sw", "Stillinger-Weber", utils::METAL2REAL); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairSW::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairSW::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairSW::NPARAMS_PER_LINE); } @@ -101,7 +101,7 @@ TEST_F(PotentialFileReaderTest, Comb) PotentialFileReader reader(lmp, "ffield.comb", "COMB"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairComb::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairComb::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairComb::NPARAMS_PER_LINE); } @@ -112,7 +112,7 @@ TEST_F(PotentialFileReaderTest, Comb3) PotentialFileReader reader(lmp, "ffield.comb3", "COMB3"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairComb3::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairComb3::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairComb3::NPARAMS_PER_LINE); } @@ -123,7 +123,7 @@ TEST_F(PotentialFileReaderTest, Tersoff) PotentialFileReader reader(lmp, "Si.tersoff", "Tersoff"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairTersoff::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairTersoff::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairTersoff::NPARAMS_PER_LINE); } @@ -134,7 +134,7 @@ TEST_F(PotentialFileReaderTest, TersoffMod) PotentialFileReader reader(lmp, "Si.tersoff.mod", "Tersoff/Mod"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairTersoffMOD::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairTersoffMOD::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairTersoffMOD::NPARAMS_PER_LINE); } @@ -145,7 +145,7 @@ TEST_F(PotentialFileReaderTest, TersoffModC) PotentialFileReader reader(lmp, "Si.tersoff.modc", "Tersoff/ModC"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairTersoffMODC::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairTersoffMODC::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairTersoffMODC::NPARAMS_PER_LINE); } @@ -156,7 +156,7 @@ TEST_F(PotentialFileReaderTest, TersoffTable) PotentialFileReader reader(lmp, "Si.tersoff", "TersoffTable"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairTersoffTable::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairTersoffTable::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairTersoffTable::NPARAMS_PER_LINE); } @@ -167,7 +167,7 @@ TEST_F(PotentialFileReaderTest, TersoffZBL) PotentialFileReader reader(lmp, "SiC.tersoff.zbl", "Tersoff/ZBL"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairTersoffZBL::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairTersoffZBL::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairTersoffZBL::NPARAMS_PER_LINE); } @@ -178,7 +178,7 @@ TEST_F(PotentialFileReaderTest, GW) PotentialFileReader reader(lmp, "SiC.gw", "GW"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairGW::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairGW::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairGW::NPARAMS_PER_LINE); } @@ -189,7 +189,7 @@ TEST_F(PotentialFileReaderTest, GWZBL) PotentialFileReader reader(lmp, "SiC.gw.zbl", "GW/ZBL"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairGWZBL::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairGWZBL::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairGWZBL::NPARAMS_PER_LINE); } @@ -200,7 +200,7 @@ TEST_F(PotentialFileReaderTest, Nb3bHarmonic) PotentialFileReader reader(lmp, "MOH.nb3b.harmonic", "NB3B Harmonic"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairNb3bHarmonic::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairNb3bHarmonic::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairNb3bHarmonic::NPARAMS_PER_LINE); } @@ -211,7 +211,7 @@ TEST_F(PotentialFileReaderTest, Vashishta) PotentialFileReader reader(lmp, "SiC.vashishta", "Vashishta"); END_HIDE_OUTPUT(); - auto line = reader.next_line(PairVashishta::NPARAMS_PER_LINE); + auto *line = reader.next_line(PairVashishta::NPARAMS_PER_LINE); ASSERT_EQ(utils::count_words(line), PairVashishta::NPARAMS_PER_LINE); } diff --git a/unittest/formats/test_text_file_reader.cpp b/unittest/formats/test_text_file_reader.cpp index 8615b71b2a..687f6539f0 100644 --- a/unittest/formats/test_text_file_reader.cpp +++ b/unittest/formats/test_text_file_reader.cpp @@ -61,8 +61,8 @@ protected: TEST_F(TextFileReaderTest, nofile) { - ASSERT_THROW({ TextFileReader reader("text_reader_noexist.file", "test"); }, - FileReaderException); + ASSERT_THROW( + { TextFileReader reader("text_reader_noexist.file", "test"); }, FileReaderException); } // this test cannot work on windows due to its non unix-like permission system @@ -76,8 +76,8 @@ TEST_F(TextFileReaderTest, permissions) fputs("word\n", fp); fclose(fp); chmod("text_reader_noperms.file", 0); - ASSERT_THROW({ TextFileReader reader("text_reader_noperms.file", "test"); }, - FileReaderException); + ASSERT_THROW( + { TextFileReader reader("text_reader_noperms.file", "test"); }, FileReaderException); platform::unlink("text_reader_noperms.file"); } #endif @@ -93,8 +93,8 @@ TEST_F(TextFileReaderTest, usefp) FILE *fp = fopen("text_reader_two.file", "r"); ASSERT_NE(fp, nullptr); - auto reader = new TextFileReader(fp, "test"); - auto line = reader->next_line(); + auto *reader = new TextFileReader(fp, "test"); + auto *line = reader->next_line(); ASSERT_STREQ(line, "4 "); line = reader->next_line(1); ASSERT_STREQ(line, "4 0.5 "); @@ -120,7 +120,7 @@ TEST_F(TextFileReaderTest, comments) test_files(); TextFileReader reader("text_reader_two.file", "test"); reader.ignore_comments = true; - auto line = reader.next_line(); + auto *line = reader.next_line(); ASSERT_STREQ(line, "4 "); line = reader.next_line(1); ASSERT_STREQ(line, "4 0.5 "); @@ -141,7 +141,7 @@ TEST_F(TextFileReaderTest, nocomments) test_files(); TextFileReader reader("text_reader_one.file", "test"); reader.ignore_comments = false; - auto line = reader.next_line(); + auto *line = reader.next_line(); ASSERT_STREQ(line, "# test file 1 for text file reader\n"); line = reader.next_line(1); ASSERT_STREQ(line, "one\n"); diff --git a/unittest/fortran/wrap_configuration.cpp b/unittest/fortran/wrap_configuration.cpp index 08974d8a08..0161a80125 100644 --- a/unittest/fortran/wrap_configuration.cpp +++ b/unittest/fortran/wrap_configuration.cpp @@ -136,8 +136,8 @@ TEST_F(LAMMPS_configuration, has_package) }; // clang-format on - for (std::size_t i = 0; i < pkg_name.size(); i++) - EXPECT_EQ(f_lammps_has_package(pkg_name[i].c_str()), Info::has_package(pkg_name[i])); + for (const auto &i : pkg_name) + EXPECT_EQ(f_lammps_has_package(i.c_str()), Info::has_package(i)); } TEST_F(LAMMPS_configuration, package_count) diff --git a/unittest/fortran/wrap_create.cpp b/unittest/fortran/wrap_create.cpp index 260e6ba1f1..81c40f9700 100644 --- a/unittest/fortran/wrap_create.cpp +++ b/unittest/fortran/wrap_create.cpp @@ -34,7 +34,7 @@ TEST(open_no_mpi, no_args) void *handle = f_lammps_no_mpi_no_args(); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.substr(0, 6).c_str(), "LAMMPS"); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); EXPECT_EQ(lmp->infile, stdin); EXPECT_EQ(lmp->screen, stdout); @@ -51,7 +51,7 @@ TEST(open_no_mpi, with_args) void *handle = f_lammps_no_mpi_with_args(); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.substr(0, 6).c_str(), "LAMMPS"); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->infile, stdin); EXPECT_EQ(lmp->screen, stdout); EXPECT_EQ(lmp->logfile, nullptr); @@ -70,10 +70,10 @@ TEST(fortran_open, no_args) void *handle = f_lammps_open_no_args(); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.substr(0, 6).c_str(), "LAMMPS"); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; - int f_comm = f_lammps_get_comm(); - MPI_Comm mycomm = MPI_Comm_f2c(f_comm); + int f_comm = f_lammps_get_comm(); + auto mycomm = MPI_Comm_f2c(f_comm); EXPECT_EQ(lmp->world, mycomm); EXPECT_EQ(lmp->infile, stdin); EXPECT_EQ(lmp->screen, stdout); @@ -90,10 +90,10 @@ TEST(fortran_open, with_args) void *handle = f_lammps_open_with_args(); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.substr(0, 6).c_str(), "LAMMPS"); - LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; + auto *lmp = (LAMMPS_NS::LAMMPS *)handle; - int f_comm = f_lammps_get_comm(); - MPI_Comm mycomm = MPI_Comm_f2c(f_comm); + int f_comm = f_lammps_get_comm(); + auto mycomm = MPI_Comm_f2c(f_comm); EXPECT_EQ(lmp->world, mycomm); EXPECT_EQ(lmp->infile, stdin); EXPECT_EQ(lmp->screen, stdout); diff --git a/unittest/fortran/wrap_create_atoms.cpp b/unittest/fortran/wrap_create_atoms.cpp index 3addbcf070..4d4692bd5e 100644 --- a/unittest/fortran/wrap_create_atoms.cpp +++ b/unittest/fortran/wrap_create_atoms.cpp @@ -1,8 +1,8 @@ // unit tests for creating atoms in a LAMMPS instance through the Fortran wrapper +#include "atom.h" #include "lammps.h" #include "library.h" -#include "atom.h" #include #include #include @@ -56,39 +56,39 @@ TEST_F(LAMMPS_create_atoms, create_three) #endif double **x, **v; EXPECT_EQ(lmp->atom->nlocal, 3); - tag = lmp->atom->tag; + tag = lmp->atom->tag; image = lmp->atom->image; - x = lmp->atom->x; - v = lmp->atom->v; + x = lmp->atom->x; + v = lmp->atom->v; f_lammps_create_three_atoms(); EXPECT_EQ(lmp->atom->nlocal, 6); for (int i = 0; i < lmp->atom->nlocal; i++) { if (tag[i] == 4) { - EXPECT_EQ(image[i],lammps_encode_image_flags(1,-1,3)); - EXPECT_DOUBLE_EQ(x[i][0],1.0); - EXPECT_DOUBLE_EQ(x[i][1],1.8); - EXPECT_DOUBLE_EQ(x[i][2],2.718281828); - EXPECT_DOUBLE_EQ(v[i][0],0.0); - EXPECT_DOUBLE_EQ(v[i][1],1.0); - EXPECT_DOUBLE_EQ(v[i][2],-1.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(1, -1, 3)); + EXPECT_DOUBLE_EQ(x[i][0], 1.0); + EXPECT_DOUBLE_EQ(x[i][1], 1.8); + EXPECT_DOUBLE_EQ(x[i][2], 2.718281828); + EXPECT_DOUBLE_EQ(v[i][0], 0.0); + EXPECT_DOUBLE_EQ(v[i][1], 1.0); + EXPECT_DOUBLE_EQ(v[i][2], -1.0); } if (tag[i] == 5) { - EXPECT_EQ(image[i],lammps_encode_image_flags(-2,-2,1)); - EXPECT_DOUBLE_EQ(x[i][0],1.8); - EXPECT_DOUBLE_EQ(x[i][1],0.1); - EXPECT_DOUBLE_EQ(x[i][2],1.8); - EXPECT_DOUBLE_EQ(v[i][0],1.0); - EXPECT_DOUBLE_EQ(v[i][1],-1.0); - EXPECT_DOUBLE_EQ(v[i][2],3.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(-2, -2, 1)); + EXPECT_DOUBLE_EQ(x[i][0], 1.8); + EXPECT_DOUBLE_EQ(x[i][1], 0.1); + EXPECT_DOUBLE_EQ(x[i][2], 1.8); + EXPECT_DOUBLE_EQ(v[i][0], 1.0); + EXPECT_DOUBLE_EQ(v[i][1], -1.0); + EXPECT_DOUBLE_EQ(v[i][2], 3.0); } if (tag[i] == 6) { - EXPECT_EQ(image[i],lammps_encode_image_flags(-2,0,0)); - EXPECT_DOUBLE_EQ(x[i][0],0.6); - EXPECT_DOUBLE_EQ(x[i][1],0.8); - EXPECT_DOUBLE_EQ(x[i][2],2.2); - EXPECT_DOUBLE_EQ(v[i][0],0.1); - EXPECT_DOUBLE_EQ(v[i][1],0.2); - EXPECT_DOUBLE_EQ(v[i][2],-0.2); + EXPECT_EQ(image[i], lammps_encode_image_flags(-2, 0, 0)); + EXPECT_DOUBLE_EQ(x[i][0], 0.6); + EXPECT_DOUBLE_EQ(x[i][1], 0.8); + EXPECT_DOUBLE_EQ(x[i][2], 2.2); + EXPECT_DOUBLE_EQ(v[i][0], 0.1); + EXPECT_DOUBLE_EQ(v[i][1], 0.2); + EXPECT_DOUBLE_EQ(v[i][2], -0.2); } } }; @@ -106,30 +106,30 @@ TEST_F(LAMMPS_create_atoms, create_two_more) EXPECT_EQ(lmp->atom->nlocal, 6); f_lammps_create_two_more(); EXPECT_EQ(lmp->atom->nlocal, 8); - tag = lmp->atom->tag; + tag = lmp->atom->tag; image = lmp->atom->image; - x = lmp->atom->x; - v = lmp->atom->v; + x = lmp->atom->x; + v = lmp->atom->v; for (int i = 0; i < lmp->atom->nlocal; i++) { if (tag[i] == 7) { - EXPECT_EQ(image[i],lammps_encode_image_flags(0,0,0)); - EXPECT_DOUBLE_EQ(x[i][0],0.1); - EXPECT_DOUBLE_EQ(x[i][1],1.9); - EXPECT_DOUBLE_EQ(x[i][2],3.8); - EXPECT_DOUBLE_EQ(v[i][0],0.0); - EXPECT_DOUBLE_EQ(v[i][1],0.0); - EXPECT_DOUBLE_EQ(v[i][2],0.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(0, 0, 0)); + EXPECT_DOUBLE_EQ(x[i][0], 0.1); + EXPECT_DOUBLE_EQ(x[i][1], 1.9); + EXPECT_DOUBLE_EQ(x[i][2], 3.8); + EXPECT_DOUBLE_EQ(v[i][0], 0.0); + EXPECT_DOUBLE_EQ(v[i][1], 0.0); + EXPECT_DOUBLE_EQ(v[i][2], 0.0); } if (tag[i] == 8) { - EXPECT_EQ(image[i],lammps_encode_image_flags(0,0,0)); - EXPECT_DOUBLE_EQ(x[i][0],1.2); - EXPECT_DOUBLE_EQ(x[i][1],2.1); - EXPECT_DOUBLE_EQ(x[i][2],1.25); - EXPECT_DOUBLE_EQ(v[i][0],0.0); - EXPECT_DOUBLE_EQ(v[i][1],0.0); - EXPECT_DOUBLE_EQ(v[i][2],0.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(0, 0, 0)); + EXPECT_DOUBLE_EQ(x[i][0], 1.2); + EXPECT_DOUBLE_EQ(x[i][1], 2.1); + EXPECT_DOUBLE_EQ(x[i][2], 1.25); + EXPECT_DOUBLE_EQ(v[i][0], 0.0); + EXPECT_DOUBLE_EQ(v[i][1], 0.0); + EXPECT_DOUBLE_EQ(v[i][2], 0.0); } - } + } }; TEST_F(LAMMPS_create_atoms, create_two_more_bigsmall) @@ -149,30 +149,30 @@ TEST_F(LAMMPS_create_atoms, create_two_more_bigsmall) f_lammps_create_two_more_small(); #endif EXPECT_EQ(lmp->atom->nlocal, 8); - tag = lmp->atom->tag; + tag = lmp->atom->tag; image = lmp->atom->image; - x = lmp->atom->x; - v = lmp->atom->v; + x = lmp->atom->x; + v = lmp->atom->v; for (int i = 0; i < lmp->atom->nlocal; i++) { if (tag[i] == 7) { - EXPECT_EQ(image[i],lammps_encode_image_flags(-1,0,0)); - EXPECT_DOUBLE_EQ(x[i][0],1.2); - EXPECT_DOUBLE_EQ(x[i][1],2.1); - EXPECT_DOUBLE_EQ(x[i][2],1.25); - EXPECT_DOUBLE_EQ(v[i][0],0.0); - EXPECT_DOUBLE_EQ(v[i][1],0.0); - EXPECT_DOUBLE_EQ(v[i][2],0.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(-1, 0, 0)); + EXPECT_DOUBLE_EQ(x[i][0], 1.2); + EXPECT_DOUBLE_EQ(x[i][1], 2.1); + EXPECT_DOUBLE_EQ(x[i][2], 1.25); + EXPECT_DOUBLE_EQ(v[i][0], 0.0); + EXPECT_DOUBLE_EQ(v[i][1], 0.0); + EXPECT_DOUBLE_EQ(v[i][2], 0.0); } if (tag[i] == 8) { - EXPECT_EQ(image[i],lammps_encode_image_flags(1,0,0)); - EXPECT_DOUBLE_EQ(x[i][0],0.1); - EXPECT_DOUBLE_EQ(x[i][1],1.9); - EXPECT_DOUBLE_EQ(x[i][2],3.8); - EXPECT_DOUBLE_EQ(v[i][0],0.0); - EXPECT_DOUBLE_EQ(v[i][1],0.0); - EXPECT_DOUBLE_EQ(v[i][2],0.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(1, 0, 0)); + EXPECT_DOUBLE_EQ(x[i][0], 0.1); + EXPECT_DOUBLE_EQ(x[i][1], 1.9); + EXPECT_DOUBLE_EQ(x[i][2], 3.8); + EXPECT_DOUBLE_EQ(v[i][0], 0.0); + EXPECT_DOUBLE_EQ(v[i][1], 0.0); + EXPECT_DOUBLE_EQ(v[i][2], 0.0); } - } + } }; TEST_F(LAMMPS_create_atoms, create_two_more_bigsmall2) @@ -192,28 +192,28 @@ TEST_F(LAMMPS_create_atoms, create_two_more_bigsmall2) f_lammps_create_two_more_small2(); #endif EXPECT_EQ(lmp->atom->nlocal, 8); - tag = lmp->atom->tag; + tag = lmp->atom->tag; image = lmp->atom->image; - x = lmp->atom->x; - v = lmp->atom->v; + x = lmp->atom->x; + v = lmp->atom->v; for (int i = 0; i < lmp->atom->nlocal; i++) { if (tag[i] == 7) { - EXPECT_EQ(image[i],lammps_encode_image_flags(0,0,0)); - EXPECT_DOUBLE_EQ(x[i][0],1.2); - EXPECT_DOUBLE_EQ(x[i][1],2.1); - EXPECT_DOUBLE_EQ(x[i][2],1.25); - EXPECT_DOUBLE_EQ(v[i][0],0.0); - EXPECT_DOUBLE_EQ(v[i][1],0.0); - EXPECT_DOUBLE_EQ(v[i][2],0.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(0, 0, 0)); + EXPECT_DOUBLE_EQ(x[i][0], 1.2); + EXPECT_DOUBLE_EQ(x[i][1], 2.1); + EXPECT_DOUBLE_EQ(x[i][2], 1.25); + EXPECT_DOUBLE_EQ(v[i][0], 0.0); + EXPECT_DOUBLE_EQ(v[i][1], 0.0); + EXPECT_DOUBLE_EQ(v[i][2], 0.0); } if (tag[i] == 8) { - EXPECT_EQ(image[i],lammps_encode_image_flags(0,0,0)); - EXPECT_DOUBLE_EQ(x[i][0],0.1); - EXPECT_DOUBLE_EQ(x[i][1],1.9); - EXPECT_DOUBLE_EQ(x[i][2],3.8); - EXPECT_DOUBLE_EQ(v[i][0],0.0); - EXPECT_DOUBLE_EQ(v[i][1],0.0); - EXPECT_DOUBLE_EQ(v[i][2],0.0); + EXPECT_EQ(image[i], lammps_encode_image_flags(0, 0, 0)); + EXPECT_DOUBLE_EQ(x[i][0], 0.1); + EXPECT_DOUBLE_EQ(x[i][1], 1.9); + EXPECT_DOUBLE_EQ(x[i][2], 3.8); + EXPECT_DOUBLE_EQ(v[i][0], 0.0); + EXPECT_DOUBLE_EQ(v[i][1], 0.0); + EXPECT_DOUBLE_EQ(v[i][2], 0.0); } - } + } }; diff --git a/unittest/fortran/wrap_extract_fix.cpp b/unittest/fortran/wrap_extract_fix.cpp index bbb535c1e7..ec49e290ac 100644 --- a/unittest/fortran/wrap_extract_fix.cpp +++ b/unittest/fortran/wrap_extract_fix.cpp @@ -51,7 +51,7 @@ protected: TEST_F(LAMMPS_extract_fix, global_scalar) { f_lammps_setup_extract_fix(); - double *scalar = + auto *scalar = (double *)lammps_extract_fix(lmp, "recenter", LMP_STYLE_GLOBAL, LMP_TYPE_SCALAR, -1, -1); EXPECT_DOUBLE_EQ(f_lammps_extract_fix_global_scalar(), *scalar); lammps_free(scalar); @@ -60,11 +60,11 @@ TEST_F(LAMMPS_extract_fix, global_scalar) TEST_F(LAMMPS_extract_fix, global_vector) { f_lammps_setup_extract_fix(); - double *x = + auto *x = (double *)lammps_extract_fix(lmp, "recenter", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, 0, -1); - double *y = + auto *y = (double *)lammps_extract_fix(lmp, "recenter", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, 1, -1); - double *z = + auto *z = (double *)lammps_extract_fix(lmp, "recenter", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, 2, -1); EXPECT_DOUBLE_EQ(f_lammps_extract_fix_global_vector(1), *x); EXPECT_DOUBLE_EQ(f_lammps_extract_fix_global_vector(2), *y); diff --git a/unittest/fortran/wrap_fixexternal.cpp b/unittest/fortran/wrap_fixexternal.cpp index 694aceb009..1a709018c7 100644 --- a/unittest/fortran/wrap_fixexternal.cpp +++ b/unittest/fortran/wrap_fixexternal.cpp @@ -18,7 +18,7 @@ void f_lammps_close(); void f_lammps_setup_fix_external_callback(); void f_lammps_setup_fix_external_array(); void f_lammps_set_fix_external_callbacks(); -void f_lammps_get_force(int, double*); +void f_lammps_get_force(int, double *); void f_lammps_reverse_direction(); void f_lammps_find_forces(); void f_lammps_add_energy(); @@ -59,11 +59,11 @@ TEST_F(LAMMPS_fixexternal, callback) f_lammps_set_fix_external_callbacks(); lammps_command(lmp, "run 0"); double f[3]; - f_lammps_get_force(1,f); + f_lammps_get_force(1, f); EXPECT_DOUBLE_EQ(f[0], 3.0); EXPECT_DOUBLE_EQ(f[1], -3.0); EXPECT_DOUBLE_EQ(f[2], 3.75); - f_lammps_get_force(2,f); + f_lammps_get_force(2, f); EXPECT_DOUBLE_EQ(f[0], -3.0); EXPECT_DOUBLE_EQ(f[1], 3.0); EXPECT_DOUBLE_EQ(f[2], -3.75); @@ -71,11 +71,11 @@ TEST_F(LAMMPS_fixexternal, callback) f_lammps_reverse_direction(); f_lammps_set_fix_external_callbacks(); lammps_command(lmp, "run 0"); - f_lammps_get_force(1,f); + f_lammps_get_force(1, f); EXPECT_DOUBLE_EQ(f[0], -1.0); EXPECT_DOUBLE_EQ(f[1], 1.0); EXPECT_DOUBLE_EQ(f[2], -1.25); - f_lammps_get_force(2,f); + f_lammps_get_force(2, f); EXPECT_DOUBLE_EQ(f[0], 1.0); EXPECT_DOUBLE_EQ(f[1], -1.0); EXPECT_DOUBLE_EQ(f[2], 1.25); @@ -85,7 +85,7 @@ TEST_F(LAMMPS_fixexternal, array) { f_lammps_setup_fix_external_array(); double **f; - f = (double**) lammps_extract_atom(lmp, "f"); + f = (double **)lammps_extract_atom(lmp, "f"); f_lammps_find_forces(); lammps_command(lmp, "run 0"); EXPECT_DOUBLE_EQ(f[0][0], 14.0); @@ -112,19 +112,19 @@ TEST_F(LAMMPS_fixexternal, virial_global) double virial[6], volume; f_lammps_set_virial(); lammps_command(lmp, "run 0"); - volume = lammps_get_thermo(lmp, "vol"); + volume = lammps_get_thermo(lmp, "vol"); virial[0] = lammps_get_thermo(lmp, "pxx"); virial[1] = lammps_get_thermo(lmp, "pyy"); virial[2] = lammps_get_thermo(lmp, "pzz"); virial[3] = lammps_get_thermo(lmp, "pxy"); virial[4] = lammps_get_thermo(lmp, "pxz"); virial[5] = lammps_get_thermo(lmp, "pyz"); - EXPECT_DOUBLE_EQ(virial[0], 1.0/volume); - EXPECT_DOUBLE_EQ(virial[1], 2.0/volume); - EXPECT_DOUBLE_EQ(virial[2], 2.5/volume); - EXPECT_DOUBLE_EQ(virial[3], -1.0/volume); - EXPECT_DOUBLE_EQ(virial[4], -2.25/volume); - EXPECT_DOUBLE_EQ(virial[5], -3.02/volume); + EXPECT_DOUBLE_EQ(virial[0], 1.0 / volume); + EXPECT_DOUBLE_EQ(virial[1], 2.0 / volume); + EXPECT_DOUBLE_EQ(virial[2], 2.5 / volume); + EXPECT_DOUBLE_EQ(virial[3], -1.0 / volume); + EXPECT_DOUBLE_EQ(virial[4], -2.25 / volume); + EXPECT_DOUBLE_EQ(virial[5], -3.02 / volume); }; TEST_F(LAMMPS_fixexternal, energy_peratom) @@ -135,13 +135,12 @@ TEST_F(LAMMPS_fixexternal, energy_peratom) double energy; lammps_command(lmp, "run 0"); int nlocal = lammps_extract_setting(lmp, "nlocal"); - for (int i = 1; i <= nlocal; i++) - { + for (int i = 1; i <= nlocal; i++) { energy = f_lammps_find_peratom_energy(i); if (i == 1) - EXPECT_DOUBLE_EQ(energy, 1.0); + EXPECT_DOUBLE_EQ(energy, 1.0); else - EXPECT_DOUBLE_EQ(energy, 10.0); + EXPECT_DOUBLE_EQ(energy, 10.0); } }; @@ -153,26 +152,22 @@ TEST_F(LAMMPS_fixexternal, virial_peratom) double virial[6]; lammps_command(lmp, "run 0"); int nlocal = lammps_extract_setting(lmp, "nlocal"); - for (int i = 1; i <= nlocal; i++) - { + for (int i = 1; i <= nlocal; i++) { f_lammps_find_peratom_virial(virial, i); - if (i == 1) - { - EXPECT_DOUBLE_EQ(virial[0], -1.0); - EXPECT_DOUBLE_EQ(virial[1], -2.0); - EXPECT_DOUBLE_EQ(virial[2], 1.0); - EXPECT_DOUBLE_EQ(virial[3], 2.0); - EXPECT_DOUBLE_EQ(virial[4], -3.0); - EXPECT_DOUBLE_EQ(virial[5], 3.0); - } - else - { - EXPECT_DOUBLE_EQ(virial[0], -10.0); - EXPECT_DOUBLE_EQ(virial[1], -20.0); - EXPECT_DOUBLE_EQ(virial[2], 10.0); - EXPECT_DOUBLE_EQ(virial[3], 20.0); - EXPECT_DOUBLE_EQ(virial[4], -30.0); - EXPECT_DOUBLE_EQ(virial[5], 30.0); + if (i == 1) { + EXPECT_DOUBLE_EQ(virial[0], -1.0); + EXPECT_DOUBLE_EQ(virial[1], -2.0); + EXPECT_DOUBLE_EQ(virial[2], 1.0); + EXPECT_DOUBLE_EQ(virial[3], 2.0); + EXPECT_DOUBLE_EQ(virial[4], -3.0); + EXPECT_DOUBLE_EQ(virial[5], 3.0); + } else { + EXPECT_DOUBLE_EQ(virial[0], -10.0); + EXPECT_DOUBLE_EQ(virial[1], -20.0); + EXPECT_DOUBLE_EQ(virial[2], 10.0); + EXPECT_DOUBLE_EQ(virial[3], 20.0); + EXPECT_DOUBLE_EQ(virial[4], -30.0); + EXPECT_DOUBLE_EQ(virial[5], 30.0); } } }; @@ -184,11 +179,9 @@ TEST_F(LAMMPS_fixexternal, vector) f_lammps_fixexternal_set_vector(); lammps_command(lmp, "run 0"); double *v; - for (int i = 0; i < 8; i++) - { - v = (double*) lammps_extract_fix(lmp, "ext2", LMP_STYLE_GLOBAL, - LMP_TYPE_VECTOR, i, 1); - EXPECT_DOUBLE_EQ(i+1, *v); - std::free(v); + for (int i = 0; i < 8; i++) { + v = (double *)lammps_extract_fix(lmp, "ext2", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, i, 1); + EXPECT_DOUBLE_EQ(i + 1, *v); + std::free(v); } }; diff --git a/unittest/fortran/wrap_gather_scatter.cpp b/unittest/fortran/wrap_gather_scatter.cpp index 1578f0e138..adc01d64b1 100644 --- a/unittest/fortran/wrap_gather_scatter.cpp +++ b/unittest/fortran/wrap_gather_scatter.cpp @@ -277,7 +277,7 @@ TEST_F(LAMMPS_gather_scatter, gather_compute) lammps_command(lmp, "run 0"); int natoms = lmp->atom->natoms; int *tag = lmp->atom->tag; - double *pe = (double *)lammps_extract_compute(lmp, "pe", LMP_STYLE_ATOM, LMP_TYPE_VECTOR); + auto *pe = (double *)lammps_extract_compute(lmp, "pe", LMP_STYLE_ATOM, LMP_TYPE_VECTOR); for (int i = 0; i < natoms; i++) EXPECT_DOUBLE_EQ(f_lammps_gather_pe_atom(tag[i]), pe[i]); #endif @@ -292,7 +292,7 @@ TEST_F(LAMMPS_gather_scatter, gather_compute_concat) lammps_command(lmp, "run 0"); int natoms = lmp->atom->natoms; int *tag = lmp->atom->tag; - double *pe = (double *)lammps_extract_compute(lmp, "pe", LMP_STYLE_ATOM, LMP_TYPE_VECTOR); + auto *pe = (double *)lammps_extract_compute(lmp, "pe", LMP_STYLE_ATOM, LMP_TYPE_VECTOR); for (int i = 0; i < natoms; i++) EXPECT_DOUBLE_EQ(f_lammps_gather_pe_atom(tag[i]), pe[i]); #endif @@ -305,11 +305,11 @@ TEST_F(LAMMPS_gather_scatter, gather_compute_subset) #else f_lammps_setup_gather_scatter(); lammps_command(lmp, "run 0"); - int ids[2] = {3, 1}; - int *tag = lmp->atom->tag; - double pe[2] = {0.0, 0.0}; - int nlocal = lammps_extract_setting(lmp, "nlocal"); - double *pa_pe = (double *)lammps_extract_compute(lmp, "pe", LMP_STYLE_ATOM, LMP_TYPE_VECTOR); + int ids[2] = {3, 1}; + int *tag = lmp->atom->tag; + double pe[2] = {0.0, 0.0}; + int nlocal = lammps_extract_setting(lmp, "nlocal"); + auto *pa_pe = (double *)lammps_extract_compute(lmp, "pe", LMP_STYLE_ATOM, LMP_TYPE_VECTOR); for (int i = 0; i < nlocal; i++) { if (tag[i] == ids[0]) pe[0] = pa_pe[i]; @@ -330,10 +330,10 @@ TEST_F(LAMMPS_gather_scatter, scatter_compute) #else f_lammps_setup_gather_scatter(); int natoms = lmp->atom->natoms; - double *pe = new double[natoms]; + auto *pe = new double[natoms]; lammps_command(lmp, "run 0"); lammps_gather(lmp, "c_pe", 1, 1, pe); - double *old_pe = new double[natoms]; + auto *old_pe = new double[natoms]; for (int i = 0; i < natoms; i++) old_pe[i] = pe[i]; EXPECT_DOUBLE_EQ(pe[0], old_pe[0]); @@ -356,10 +356,10 @@ TEST_F(LAMMPS_gather_scatter, scatter_subset_compute) #else f_lammps_setup_gather_scatter(); int natoms = lmp->atom->natoms; - double *pe = new double[natoms]; + auto *pe = new double[natoms]; lammps_command(lmp, "run 0"); lammps_gather(lmp, "c_pe", 1, 1, pe); - double *old_pe = new double[natoms]; + auto *old_pe = new double[natoms]; for (int i = 0; i < natoms; i++) old_pe[i] = pe[i]; EXPECT_DOUBLE_EQ(pe[0], old_pe[0]); diff --git a/unittest/fortran/wrap_neighlist.cpp b/unittest/fortran/wrap_neighlist.cpp index ce09dcccb6..7a08cd61e5 100644 --- a/unittest/fortran/wrap_neighlist.cpp +++ b/unittest/fortran/wrap_neighlist.cpp @@ -1,14 +1,14 @@ // unit tests for accessing neighbor lists in a LAMMPS instance through the Fortran wrapper +#include "force.h" +#include "info.h" #include "lammps.h" #include "library.h" -#include "force.h" #include "modify.h" -#include "neighbor.h" #include "neigh_list.h" -#include "info.h" -//#include -//#include +#include "neighbor.h" +// #include +// #include #include #include @@ -33,13 +33,15 @@ protected: LAMMPS_neighbors() = default; ~LAMMPS_neighbors() override = default; - void SetUp() override { + void SetUp() override + { ::testing::internal::CaptureStdout(); lmp = (LAMMPS_NS::LAMMPS *)f_lammps_with_args(); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.substr(0, 8).c_str(), "LAMMPS ("); } - void TearDown() override { + void TearDown() override + { ::testing::internal::CaptureStdout(); f_lammps_close(); std::string output = ::testing::internal::GetCapturedStdout(); @@ -52,14 +54,13 @@ TEST_F(LAMMPS_neighbors, pair) { f_lammps_setup_neigh_tests(); int pair_neighlist = f_lammps_pair_neighlist_test(); - Pair *pair = lmp->force->pair_match("lj/cut",1,0); - int index = -2; + Pair *pair = lmp->force->pair_match("lj/cut", 1, 0); + int index = -2; if (pair != nullptr) { for (int i = 0; i < lmp->neighbor->nlist; i++) { NeighList *list = lmp->neighbor->lists[i]; - if ((list->requestor_type == NeighList::PAIR) - and (pair == list->requestor) - and (list->id == 0)) { + if ((list->requestor_type == NeighList::PAIR) and (pair == list->requestor) and + (list->id == 0)) { index = i; break; } @@ -72,16 +73,16 @@ TEST_F(LAMMPS_neighbors, fix) { if (not Info::has_package("REPLICA")) GTEST_SKIP(); f_lammps_setup_neigh_tests(); - auto fix = lmp->modify->get_fix_by_id("f"); + auto *fix = lmp->modify->get_fix_by_id("f"); EXPECT_NE(fix, nullptr); int ilist = -2; for (int i = 0; i < lmp->neighbor->nlist; i++) { - NeighList *list = lmp->neighbor->lists[i]; - if ( (list->requestor_type == NeighList::FIX) - and (fix == list->requestor) and (list->id == 0) ) { - ilist = i; - break; - } + NeighList *list = lmp->neighbor->lists[i]; + if ((list->requestor_type == NeighList::FIX) and (fix == list->requestor) and + (list->id == 0)) { + ilist = i; + break; + } } EXPECT_EQ(ilist, f_lammps_fix_neighlist_test()); }; @@ -89,13 +90,13 @@ TEST_F(LAMMPS_neighbors, fix) TEST_F(LAMMPS_neighbors, compute) { f_lammps_setup_neigh_tests(); - auto compute = lmp->modify->get_compute_by_id("c"); - EXPECT_NE(compute,nullptr); + auto *compute = lmp->modify->get_compute_by_id("c"); + EXPECT_NE(compute, nullptr); int ilist = -2; - for (int i=0; i < lmp->neighbor->nlist; i++) { + for (int i = 0; i < lmp->neighbor->nlist; i++) { NeighList *list = lmp->neighbor->lists[i]; - if ( (list->requestor_type == NeighList::COMPUTE) - and (compute == list->requestor) and (list->id == 0) ) { + if ((list->requestor_type == NeighList::COMPUTE) and (compute == list->requestor) and + (list->id == 0)) { ilist = i; break; } @@ -107,17 +108,17 @@ TEST_F(LAMMPS_neighbors, numelements) { f_lammps_setup_neigh_tests(); int num_neigh = 0; - int pair_id = f_lammps_pair_neighlist_test(); - num_neigh = f_lammps_neighlist_num_elements(pair_id); + int pair_id = f_lammps_pair_neighlist_test(); + num_neigh = f_lammps_neighlist_num_elements(pair_id); EXPECT_EQ(num_neigh, lammps_neighlist_num_elements(lmp, pair_id)); if (Info::has_package("REPLICA")) { - int fix_id = f_lammps_fix_neighlist_test(); - num_neigh = f_lammps_neighlist_num_elements(fix_id); - EXPECT_EQ(num_neigh, lammps_neighlist_num_elements(lmp, fix_id)); + int fix_id = f_lammps_fix_neighlist_test(); + num_neigh = f_lammps_neighlist_num_elements(fix_id); + EXPECT_EQ(num_neigh, lammps_neighlist_num_elements(lmp, fix_id)); } int compute_id = f_lammps_compute_neighlist_test(); - num_neigh = f_lammps_neighlist_num_elements(compute_id); + num_neigh = f_lammps_neighlist_num_elements(compute_id); EXPECT_EQ(num_neigh, lammps_neighlist_num_elements(lmp, compute_id)); }; -} // LAMMPS_NS +} // namespace LAMMPS_NS diff --git a/unittest/testing/core.h b/unittest/testing/core.h index 8f1a84d2d8..79a2560fae 100644 --- a/unittest/testing/core.h +++ b/unittest/testing/core.h @@ -107,7 +107,7 @@ public: protected: std::string testbinary = "LAMMPSTest"; - LAMMPS::argv args = {"-log", "none", "-echo", "screen", "-nocite"}; + LAMMPS::argv args = {"-log", "none", "-echo", "screen", "-nocite"}; LAMMPS *lmp; Info *info; diff --git a/unittest/utils/test_lepton.cpp b/unittest/utils/test_lepton.cpp index 55d3bf8351..9e8b75af57 100644 --- a/unittest/utils/test_lepton.cpp +++ b/unittest/utils/test_lepton.cpp @@ -130,7 +130,10 @@ TEST(LeptonCustomFunction, zbl) class ExampleFunction : public Lepton::CustomFunction { int getNumArguments() const override { return 2; } - double evaluate(const double *arguments) const override { return 2.0 * arguments[0] * arguments[1]; } + double evaluate(const double *arguments) const override + { + return 2.0 * arguments[0] * arguments[1]; + } double evaluateDerivative(const double *arguments, const int *derivOrder) const override { if (derivOrder[0] == 1) { diff --git a/unittest/utils/test_lmptype.cpp b/unittest/utils/test_lmptype.cpp index 383c9d4b2c..a14f3a2cab 100644 --- a/unittest/utils/test_lmptype.cpp +++ b/unittest/utils/test_lmptype.cpp @@ -24,7 +24,7 @@ TEST(Types, ubuf) { double buf[3]; double d1 = 0.1; - int i1 = -10; + int i1 = -10; #if defined(LAMMPS_SMALLSMALL) bigint b1 = 2048; #else @@ -43,14 +43,14 @@ TEST(Types, multitype) { multitype m[7]; int64_t b1 = (3L << 48) - 1; - int i1 = 20; - double d1 = 0.1; + int i1 = 20; + double d1 = 0.1; m[0] = b1; m[1] = i1; m[2] = d1; - m[3] = (bigint) -((1L << 40) + (1L << 50)); + m[3] = (bigint) - ((1L << 40) + (1L << 50)); m[4] = -1023; m[5] = -2.225; @@ -72,7 +72,7 @@ TEST(Types, multitype) EXPECT_EQ(m[2].data.d, d1); #if !defined(LAMMPS_SMALLSMALL) - EXPECT_EQ(m[3].data.b, -((1L << 40) + (1L << 50))); + EXPECT_EQ(m[3].data.b, -((1L << 40) + (1L << 50))); #endif EXPECT_EQ(m[4].data.i, -1023); EXPECT_EQ(m[5].data.d, -2.225); diff --git a/unittest/utils/test_math_eigen_impl.cpp b/unittest/utils/test_math_eigen_impl.cpp index b38438d1f7..497e468ac7 100644 --- a/unittest/utils/test_math_eigen_impl.cpp +++ b/unittest/utils/test_math_eigen_impl.cpp @@ -385,9 +385,9 @@ void TestJacobi(int n, //::SORT_INCREASING_ABS_EVALS); #else ecalc.Diagonalize(M, evals, evecs, - Jacobi::SORT_INCREASING_ABS_EVALS); #endif @@ -488,7 +488,7 @@ void TestJacobi(int n, //::SORT_DECREASING_ABS_EVALS); #else ecalc.Diagonalize(M, evals, evecs, - Jacobi::SORT_DECREASING_ABS_EVALS); #endif @@ -511,7 +511,7 @@ void TestJacobi(int n, //::SORT_INCREASING_EVALS); #else ecalc.Diagonalize(M, evals, evecs, - Jacobi::SORT_INCREASING_EVALS); #endif for (int i = 1; i < n; i++) @@ -533,8 +533,8 @@ void TestJacobi(int n, //::DO_NOT_SORT); #else ecalc.Diagonalize( - M, evals, evecs, - Jacobi::DO_NOT_SORT); + M, evals, evecs, + Jacobi::DO_NOT_SORT); #endif } // if (test_code_coverage) From c0dfccdd6469800c41de9142f8661859505aa4f9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 4 Jul 2024 11:18:08 -0400 Subject: [PATCH 162/385] add a few more flags to clang-tidy --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index d8b4f0a4f6..617ba7fdb8 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -204,7 +204,7 @@ option(BUILD_LAMMPS_GUI "Build and install the LAMMPS GUI" OFF) # Support using clang-tidy for C++ files with selected options set(ENABLE_CLANG_TIDY OFF CACHE BOOL "Include clang-tidy processing when compiling") if(ENABLE_CLANG_TIDY) - set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=-*,performance-trivially-destructible,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-member-init,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-boolean-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,modernize-use-override,modernize-use-bool-literals,modernize-use-emplace,modernize-return-braced-init-list,modernize-use-equals-default,modernize-use-equals-delete,modernize-replace-random-shuffle,modernize-deprecated-headers,modernize-use-nullptr,modernize-use-noexcept,modernize-redundant-void-arg;-fix;-header-filter=.*,header-filter=library.h,header-filter=fmt/*.h" CACHE STRING "clang-tidy settings") + set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=-*,performance-trivially-destructible,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-member-init,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-boolean-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-qualified-auto,misc-unused-parameters,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-shrink-to-fit,modernize-use-auto,modernize-use-using,modernize-use-override,modernize-use-bool-literals,modernize-use-emplace,modernize-return-braced-init-list,modernize-use-equals-default,modernize-use-equals-delete,modernize-replace-random-shuffle,modernize-deprecated-headers,modernize-use-nullptr,modernize-use-noexcept,modernize-redundant-void-arg;-fix;-header-filter=.*,header-filter=library.h,header-filter=fmt/*.h" CACHE STRING "clang-tidy settings") else() unset(CMAKE_CXX_CLANG_TIDY CACHE) endif() From 0d54f99fc0d7516011a503846a54ae56c9ebcbed Mon Sep 17 00:00:00 2001 From: Michele Ceriotti Date: Thu, 4 Jul 2024 17:34:18 +0200 Subject: [PATCH 163/385] Fixed a nasty bug when running the ipi interface with many MPI workers Looks like the migrate() call should happen before trajectory folding --- src/MISC/fix_ipi.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/MISC/fix_ipi.cpp b/src/MISC/fix_ipi.cpp index 87668b9192..e08727a4ed 100644 --- a/src/MISC/fix_ipi.cpp +++ b/src/MISC/fix_ipi.cpp @@ -373,6 +373,9 @@ void FixIPI::initial_integrate(int /*vflag*/) if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); + // move atoms to new processors via irregular() + // only needed if migrate_check() says an atom moves to far + if (irregular->migrate_check()) irregular->migrate_atoms(); if (domain->triclinic) domain->lamda2x(atom->nlocal); // ensures continuity of trajectories relative to the @@ -394,11 +397,6 @@ void FixIPI::initial_integrate(int /*vflag*/) } } } - // move atoms to new processors via irregular() - // only needed if migrate_check() says an atom moves to far - if (domain->triclinic) domain->x2lamda(atom->nlocal); - if (irregular->migrate_check()) irregular->migrate_atoms(); - if (domain->triclinic) domain->lamda2x(atom->nlocal); // check if kspace solver is used if (reset_flag && kspace_flag) { From eeaecb3ed355165a53e62a0fc3fb3320db73c794 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 4 Jul 2024 15:13:06 -0400 Subject: [PATCH 164/385] macOS app bundle requires -D BUILD_TOOLS=yes --- tools/lammps-gui/CMakeLists.txt | 52 ++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 951b350edb..141918a319 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -207,30 +207,34 @@ if(APPLE) ) # additional targets to populate the bundle tree and create the .dmg image file set(APP_CONTENTS ${CMAKE_BINARY_DIR}/lammps-gui.app/Contents) - add_custom_target(complete-bundle - ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/bin - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/lmp ${APP_CONTENTS}/bin/ - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/msi2lmp ${APP_CONTENTS}/bin/ - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/binary2txt ${APP_CONTENTS}/bin/ - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/stl_bin2txt ${APP_CONTENTS}/bin/ - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/phana ${APP_CONTENTS}/bin/ - COMMAND ${CMAKE_COMMAND} -E create_symlink ../MacOS/lammps-gui ${APP_CONTENTS}/bin/lammps-gui - COMMAND ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/Resources - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/cmake/packaging/README.macos ${APP_CONTENTS}/Resources/README.txt - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/cmake/packaging/lammps.icns ${APP_CONTENTS}/Resources - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/cmake/packaging/LAMMPS_DMG_Background.png ${APP_CONTENTS}/Resources - COMMAND ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/share/lammps - COMMAND ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/share/lammps/man/man1 - COMMAND ${CMAKE_COMMAND} -E copy_directory ${LAMMPS_DIR}/potentials ${APP_CONTENTS}/share/lammps/potentials - COMMAND ${CMAKE_COMMAND} -E copy_directory ${LAMMPS_DIR}/bench ${APP_CONTENTS}/share/lammps/bench - COMMAND ${CMAKE_COMMAND} -E copy_directory ${LAMMPS_DIR}/tools/msi2lmp/frc_files ${APP_CONTENTS}/share/lammps/frc_files - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/doc/lammps.1 ${APP_CONTENTS}/share/lammps/man/man1/ - COMMAND ${CMAKE_COMMAND} -E create_symlink lammps.1 ${APP_CONTENTS}/share/lammps/man/man1/lmp.1 - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/doc/msi2lmp.1 ${APP_CONTENTS}/share/lammps/man/man1 - DEPENDS lammps-gui lammps lmp binary2txt stl_bin2txt msi2lmp phana - COMMENT "Copying additional files into macOS app bundle tree" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) + if(BUILD_TOOLS) + add_custom_target(complete-bundle + ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/bin + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/lmp ${APP_CONTENTS}/bin/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/msi2lmp ${APP_CONTENTS}/bin/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/binary2txt ${APP_CONTENTS}/bin/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/stl_bin2txt ${APP_CONTENTS}/bin/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/phana ${APP_CONTENTS}/bin/ + COMMAND ${CMAKE_COMMAND} -E create_symlink ../MacOS/lammps-gui ${APP_CONTENTS}/bin/lammps-gui + COMMAND ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/Resources + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/cmake/packaging/README.macos ${APP_CONTENTS}/Resources/README.txt + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/cmake/packaging/lammps.icns ${APP_CONTENTS}/Resources + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/cmake/packaging/LAMMPS_DMG_Background.png ${APP_CONTENTS}/Resources + COMMAND ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/share/lammps + COMMAND ${CMAKE_COMMAND} -E make_directory ${APP_CONTENTS}/share/lammps/man/man1 + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LAMMPS_DIR}/potentials ${APP_CONTENTS}/share/lammps/potentials + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LAMMPS_DIR}/bench ${APP_CONTENTS}/share/lammps/bench + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LAMMPS_DIR}/tools/msi2lmp/frc_files ${APP_CONTENTS}/share/lammps/frc_files + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/doc/lammps.1 ${APP_CONTENTS}/share/lammps/man/man1/ + COMMAND ${CMAKE_COMMAND} -E create_symlink lammps.1 ${APP_CONTENTS}/share/lammps/man/man1/lmp.1 + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_DIR}/doc/msi2lmp.1 ${APP_CONTENTS}/share/lammps/man/man1 + DEPENDS lammps-gui lammps lmp binary2txt stl_bin2txt msi2lmp phana + COMMENT "Copying additional files into macOS app bundle tree" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + else() + message(FATAL_ERROR "Must use -D BUILD_TOOLS=yes for building app bundle") + endif() if(FFMPEG_EXECUTABLE) add_custom_target(copy-ffmpeg COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FFMPEG_EXECUTABLE} ${APP_CONTENTS}/bin/ From 810698dc07ca91b7df46f352b7b90d07b72c00d3 Mon Sep 17 00:00:00 2001 From: Michele Ceriotti Date: Fri, 5 Jul 2024 09:07:30 +0200 Subject: [PATCH 165/385] Skip neighbor folding at first call There may be issues due to the fact that the NL is initialized with the LAMMPS data file, that does not have to be the same as the starting config in i-PI --- src/MISC/fix_ipi.cpp | 9 ++++++++- src/MISC/fix_ipi.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/MISC/fix_ipi.cpp b/src/MISC/fix_ipi.cpp index e08727a4ed..80666790e2 100644 --- a/src/MISC/fix_ipi.cpp +++ b/src/MISC/fix_ipi.cpp @@ -188,6 +188,7 @@ FixIPI::FixIPI(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), irregul master = (comm->me == 0) ? 1 : 0; inet = 1; reset_flag = 0; + firsttime = 1; int iarg = 5; while (iarg < narg) { @@ -253,6 +254,7 @@ void FixIPI::init() ipisock = 0; // TODO: should check for success in socket opening, // but the current open_socket routine dies brutally if unsuccessful + // tell lammps we have assigned a socket socketflag = 1; @@ -382,7 +384,11 @@ void FixIPI::initial_integrate(int /*vflag*/) // snapshot at neighbor list creation, minimizing the // number of neighbor list updates auto xhold = neighbor->get_xhold(); - if (xhold != NULL) { // don't wrap if xhold is not used in the NL + if (xhold != NULL && !firsttime) { + // don't wrap if xhold is not used in the NL, or the + // first call (because the NL is initialized from the + // data file that might have nothing to do with the + // current structure for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { auto delx = x[i][0] - xhold[i][0]; @@ -397,6 +403,7 @@ void FixIPI::initial_integrate(int /*vflag*/) } } } + firsttime = 0; // check if kspace solver is used if (reset_flag && kspace_flag) { diff --git a/src/MISC/fix_ipi.h b/src/MISC/fix_ipi.h index de954c8578..31bd59b2fa 100644 --- a/src/MISC/fix_ipi.h +++ b/src/MISC/fix_ipi.h @@ -42,6 +42,7 @@ class FixIPI : public Fix { long bsize; int kspace_flag; int reset_flag; + int firsttime; private: class Irregular *irregular; From 8fcde04097482a598cf8178c458e904a80c572d5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 15:45:49 -0400 Subject: [PATCH 166/385] add a "matches()" method to the Tokenizer and ValueTokenizer classes using utils::strmatch() --- src/tokenizer.cpp | 32 +++++++++++++++++++++++++ src/tokenizer.h | 2 ++ unittest/utils/test_tokenizer.cpp | 39 +++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 00f0b0b761..06c0c45bf7 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -99,6 +99,8 @@ void Tokenizer::reset() } /*! Search the text to be processed for a sub-string. + * + * This method does a generic substring match. * * \param str string to be searched for * \return true if string was found, false if not */ @@ -107,6 +109,20 @@ bool Tokenizer::contains(const std::string &str) const return text.find(str) != std::string::npos; } +/*! Search the text to be processed for regular expression match. + * +\verbatim embed:rst +This method matches the current string against a regular expression using +the :cpp:func:`utils::strmatch() ` function. +\endverbatim + * + * \param str regular expression to be matched against + * \return true if string was found, false if not */ +bool Tokenizer::matches(const std::string &str) const +{ + return utils::strmatch(text, str); +} + /*! Skip over a given number of tokens * * \param n number of tokens to skip over */ @@ -233,6 +249,8 @@ bool ValueTokenizer::has_next() const } /*! Search the text to be processed for a sub-string. + * + * This method does a generic substring match. * * \param value string with value to be searched for * \return true if string was found, false if not */ @@ -241,6 +259,20 @@ bool ValueTokenizer::contains(const std::string &value) const return tokens.contains(value); } +/*! Search the text to be processed for regular expression match. + * +\verbatim embed:rst +This method matches the current string against a regular expression using +the :cpp:func:`utils::strmatch() ` function. +\endverbatim + * + * \param str regular expression to be matched against + * \return true if string was found, false if not */ +bool ValueTokenizer::matches(const std::string &str) const +{ + return tokens.matches(str); +} + /*! Retrieve next token * * \return string with next token */ diff --git a/src/tokenizer.h b/src/tokenizer.h index b5d9abf1f7..42a62fefa0 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -46,6 +46,7 @@ class Tokenizer { void skip(int n = 1); bool has_next() const; bool contains(const std::string &str) const; + bool matches(const std::string &str) const; std::string next(); size_t count(); @@ -119,6 +120,7 @@ class ValueTokenizer { bool has_next() const; bool contains(const std::string &value) const; + bool matches(const std::string &str) const; void skip(int ntokens = 1); size_t count(); diff --git a/unittest/utils/test_tokenizer.cpp b/unittest/utils/test_tokenizer.cpp index 49cc771a25..4d38bfd14f 100644 --- a/unittest/utils/test_tokenizer.cpp +++ b/unittest/utils/test_tokenizer.cpp @@ -173,6 +173,32 @@ TEST(Tokenizer, default_separators) ASSERT_EQ(t.count(), 2); } +TEST(Tokenizer, contains) +{ + Tokenizer values("test word"); + ASSERT_TRUE(values.contains("test")); + ASSERT_TRUE(values.contains("word")); +} + +TEST(Tokenizer, not_contains) +{ + Tokenizer values("test word"); + ASSERT_FALSE(values.contains("test2")); +} + +TEST(Tokenizer, matches) +{ + Tokenizer values("test word"); + ASSERT_TRUE(values.matches("test")); + ASSERT_TRUE(values.matches("word")); +} + +TEST(Tokenizer, not_matches) +{ + Tokenizer values("test word"); + ASSERT_FALSE(values.matches("test2")); +} + TEST(Tokenizer, as_vector1) { Tokenizer t(" \r\n test \t word \f"); @@ -346,6 +372,19 @@ TEST(ValueTokenizer, not_contains) ASSERT_FALSE(values.contains("test2")); } +TEST(ValueTokenizer, matches) +{ + ValueTokenizer values("test word"); + ASSERT_TRUE(values.matches("test")); + ASSERT_TRUE(values.matches("word")); +} + +TEST(ValueTokenizer, not_matches) +{ + ValueTokenizer values("test word"); + ASSERT_FALSE(values.matches("test2")); +} + TEST(ValueTokenizer, missing_int) { ValueTokenizer values("10"); From caa1b4a891c7d36fd42ada8e9eb42dec8243ce05 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 16:12:08 -0400 Subject: [PATCH 167/385] promote ndatum to bigint to avoid overflows --- src/my_page.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/my_page.h b/src/my_page.h index ea19dc8e74..1f5c9ad797 100644 --- a/src/my_page.h +++ b/src/my_page.h @@ -29,8 +29,8 @@ struct HyperOneCoeff { template class MyPage { public: - int ndatum; // total # of stored datums - int nchunk; // total # of stored chunks + bigint ndatum; // total # of stored datums + int nchunk; // total # of stored chunks MyPage(); virtual ~MyPage(); @@ -105,7 +105,7 @@ template class MyPage { // 1 = chunk size exceeded maxchunk // 2 = memory allocation error #if defined(_OPENMP) - char pad[64]; // to avoid false sharing with multi-threading + char pad[64]; // to avoid false sharing with multi-threading #endif void allocate(); void deallocate(); From f0a11dbefdb281b7fa83be7b31872ccc8bb2da9a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 16:16:04 -0400 Subject: [PATCH 168/385] also promote ndatum in MyPoolChunk class --- src/my_pool_chunk.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/my_pool_chunk.h b/src/my_pool_chunk.h index fa0a4e2506..3a8209eb8d 100644 --- a/src/my_pool_chunk.h +++ b/src/my_pool_chunk.h @@ -18,8 +18,8 @@ namespace LAMMPS_NS { template class MyPoolChunk { public: - int ndatum; // total # of stored datums - int nchunk; // total # of stored chunks + bigint ndatum; // total # of stored datums + int nchunk; // total # of stored chunks MyPoolChunk(int user_minchunk = 1, int user_maxchunk = 1, int user_nbin = 1, int user_chunkperpage = 1024, int user_pagedelta = 1); From dacc55b889927e6837f2fb6d5ec73fb5fecda652 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 26 Jun 2024 14:55:36 -0600 Subject: [PATCH 169/385] Prevent overflow in neighbor output --- src/finish.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/finish.cpp b/src/finish.cpp index 554f250fe1..c774f51e58 100644 --- a/src/finish.cpp +++ b/src/finish.cpp @@ -62,7 +62,8 @@ Finish::Finish(LAMMPS *lmp) : Pointers(lmp) {} void Finish::end(int flag) { - int i,nneigh,nneighfull; + int i; + bigint nneigh,nneighfull; int histo[10]; int minflag,prdflag,tadflag,hyperflag; int timeflag,fftflag,histoflag,neighflag; From 2fc664d5da934f05b13a8a2e4117980f74dac964 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Fri, 5 Jul 2024 16:21:43 -0400 Subject: [PATCH 170/385] added kokkos views --- src/KOKKOS/angle_spica_kokkos.cpp | 107 +++++++++++++++++++++++++----- src/KOKKOS/angle_spica_kokkos.h | 19 ++++-- 2 files changed, 101 insertions(+), 25 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index b36923e8b1..b630d808e1 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -21,10 +21,13 @@ #include "atom_kokkos.h" #include "atom_masks.h" #include "comm.h" +#include "error.h" #include "force.h" #include "math_const.h" #include "memory_kokkos.h" #include "neighbor_kokkos.h" +#include "respa.h" +#include "update.h" #include "lj_spica_common.h" @@ -197,45 +200,45 @@ void AngleSPICAKokkos::operator()(TagAngleSPICAComputetype[i1]; - const int type3 = atom->type[i3]; + const int type1 = d_type[i1]; + const int type3 = d_type[i3]; f13=0.0; e13=0.0; - if (rsq3 < rminsq[type1][type3]) { - const int ljt = lj_type[type1][type3]; + if (rsq3 < d_rminsq(type1,type3)) { + const int ljt = d_lj_type(type1,type3); const double r2inv = 1.0/rsq3; if (ljt == LJ12_4) { const double r4inv=r2inv*r2inv; - f13 = r4inv*(lj1[type1][type3]*r4inv*r4inv - lj2[type1][type3]); - if (eflag) e13 = r4inv*(lj3[type1][type3]*r4inv*r4inv - lj4[type1][type3]); + f13 = r4inv*(d_lj1(type1,type3)*r4inv*r4inv - d_lj2(type1,type3)); + if (eflag) e13 = r4inv*(d_lj3(type1,type3)*r4inv*r4inv - d_lj4(type1,type3)); } else if (ljt == LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; - f13 = r6inv*(lj1[type1][type3]*r3inv - lj2[type1][type3]); - if (eflag) e13 = r6inv*(lj3[type1][type3]*r3inv - lj4[type1][type3]); + f13 = r6inv*(d_lj1(type1,type3)*r3inv - d_lj2(type1,type3)); + if (eflag) e13 = r6inv*(d_lj3(type1,type3)*r3inv - d_lj4(type1,type3)); } else if (ljt == LJ12_6) { const double r6inv = r2inv*r2inv*r2inv; - f13 = r6inv*(lj1[type1][type3]*r6inv - lj2[type1][type3]); - if (eflag) e13 = r6inv*(lj3[type1][type3]*r6inv - lj4[type1][type3]); + f13 = r6inv*(d_lj1(type1,type3)*r6inv - d_lj2(type1,type3)); + if (eflag) e13 = r6inv*(d_lj3(type1,type3)*r6inv - d_lj4(type1,type3)); } else if (ljt == LJ12_5) { const double r5inv = r2inv*r2inv*sqrt(r2inv); const double r7inv = r5inv*r2inv; - f13 = r5inv*(lj1[type1][type3]*r7inv - lj2[type1][type3]); - if (eflag) e13 = r5inv*(lj3[type1][type3]*r7inv - lj4[type1][type3]); + f13 = r5inv*(d_lj1(type1,type3)*r7inv - d_lj2(type1,type3)); + if (eflag) e13 = r5inv*(d_lj3(type1,type3)*r7inv - d_lj4(type1,type3)); } // make sure energy is 0.0 at the cutoff. - if (eflag) e13 -= emin[type1][type3]; + if (eflag) e13 -= d_emin(type1,type3); f13 *= r2inv; } @@ -305,16 +308,84 @@ void AngleSPICAKokkos::allocate() { AngleSPICA::allocate(); - int n = atom->nangletypes; - k_k = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::k",n+1); - k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",n+1); - k_repscale = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::repscale",n+1); - k_setflag = typename ArrayTypes::tdual_int_1d("AngleSPICA::setflag",n+1); + int nangletypes = atomKK->nangletypes; + k_k = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::k",nangletypes+1); + k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",nangletypes+1); + k_repscale = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::repscale",nangletypes+1); + k_setflag = typename ArrayTypes::tdual_int_1d("AngleSPICA::setflag",nangletypes+1); d_k = k_k.template view(); d_theta0 = k_theta0.template view(); d_repscale = k_repscale.template view(); d_setflag = k_setflag.template view(); + + int ntypes = atomKK->ntypes; + k_lj_type = typename ArrayTypes::tdual_int_2d("AngleSPICA::lj_type",ntypes+1,ntypes+1); + k_lj1 = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::lj1",ntypes+1,ntypes+1); + k_lj2 = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::lj2",ntypes+1,ntypes+1); + k_lj3 = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::lj3",ntypes+1,ntypes+1); + k_lj4 = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::lj4",ntypes+1,ntypes+1); + k_rminsq = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::rminsq",ntypes+1,ntypes+1); + k_emin = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::emin",ntypes+1,ntypes+1); + + d_lj_type = k_lj_type.template view(); + d_lj1 = k_lj1.template view(); + d_lj2 = k_lj2.template view(); + d_lj3 = k_lj3.template view(); + d_lj4 = k_lj4.template view(); + d_rminsq = k_rminsq.template view(); + d_emin = k_emin.template view(); + +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +template +void AngleSPICAKokkos::init_style() +{ + AngleSPICA::init_style(); + + // error if rRESPA with inner levels + + if (update->whichflag == 1 && utils::strmatch(update->integrate_style,"^respa")) { + int respa = 0; + if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; + if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; + if (respa) + error->all(FLERR,"Cannot use Kokkos pair style with rRESPA inner/middle"); + } + + d_type = atomKK->k_type.view(); + + int ntypes = atomKK->ntypes; + for (int i = 1; i <= ntypes; i++) + for (int j = 1; j <= ntypes; j++) { + k_lj_type.h_view(i,j) = lj_type[i][j]; + k_lj1.h_view(i,j) = lj1[i][j]; + k_lj2.h_view(i,j) = lj2[i][j]; + k_lj3.h_view(i,j) = lj3[i][j]; + k_lj4.h_view(i,j) = lj4[i][j]; + k_rminsq.h_view(i,j) = rminsq[i][j]; + k_emin.h_view(i,j) = emin[i][j]; + } + + k_lj_type.template modify(); + k_lj1.template modify(); + k_lj2.template modify(); + k_lj3.template modify(); + k_lj4.template modify(); + k_rminsq.template modify(); + k_emin.template modify(); + + k_lj_type.template sync(); + k_lj1.template sync(); + k_lj2.template sync(); + k_lj3.template sync(); + k_lj4.template sync(); + k_rminsq.template sync(); + k_emin.template sync(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index 2a35d62e83..75c1010f08 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -42,6 +42,7 @@ class AngleSPICAKokkos : public AngleSPICA { ~AngleSPICAKokkos() override; void compute(int, int) override; void coeff(int, char **) override; + void init_style() override; void read_restart(FILE *) override; template @@ -80,16 +81,20 @@ class AngleSPICAKokkos : public AngleSPICA { int nlocal,newton_bond; int eflag,vflag; - typename ArrayTypes::tdual_ffloat_1d k_k; - typename ArrayTypes::tdual_ffloat_1d k_theta0; - typename ArrayTypes::tdual_ffloat_1d k_repscale; - typename ArrayTypes::tdual_int_1d k_setflag; + typename ArrayTypes::tdual_ffloat_1d k_k, k_theta0, k_repscale; + typename ArrayTypes::t_ffloat_1d d_k, d_theta0, d_repscale; - typename ArrayTypes::t_ffloat_1d d_k; - typename ArrayTypes::t_ffloat_1d d_theta0; - typename ArrayTypes::t_ffloat_1d d_repscale; + typename ArrayTypes::tdual_int_1d k_setflag; typename ArrayTypes::t_int_1d d_setflag; + typename ArrayTypes::t_int_1d d_type; + + typename ArrayTypes::tdual_int_2d k_lj_type; + typename ArrayTypes::t_int_2d d_lj_type; + + typename ArrayTypes::tdual_ffloat_2d k_lj1, k_lj2, k_lj3, k_lj4, k_rminsq, k_emin; + typename ArrayTypes::t_ffloat_2d d_lj1, d_lj2, d_lj3, d_lj4, d_rminsq, d_emin; + void allocate() override; }; From 880aa40d1ba5d0e202228e2d01e28c28a4ad3d4e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 16:23:02 -0400 Subject: [PATCH 171/385] add missing header --- src/my_pool_chunk.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/my_pool_chunk.h b/src/my_pool_chunk.h index 3a8209eb8d..06264884d1 100644 --- a/src/my_pool_chunk.h +++ b/src/my_pool_chunk.h @@ -14,6 +14,8 @@ #ifndef LAMMPS_MY_POOL_CHUNK_H #define LAMMPS_MY_POOL_CHUNK_H +#include "lmptype.h" + namespace LAMMPS_NS { template class MyPoolChunk { From 6fd962e132fbf8c11e333d775e13d1a1fce6b3df Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 16:44:08 -0400 Subject: [PATCH 172/385] spelling --- src/tokenizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 06c0c45bf7..6b87f0c421 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -100,7 +100,7 @@ void Tokenizer::reset() /*! Search the text to be processed for a sub-string. * - * This method does a generic substring match. + * This method does a generic sub-string match. * * \param str string to be searched for * \return true if string was found, false if not */ @@ -250,7 +250,7 @@ bool ValueTokenizer::has_next() const /*! Search the text to be processed for a sub-string. * - * This method does a generic substring match. + * This method does a generic sub-string match. * * \param value string with value to be searched for * \return true if string was found, false if not */ From a3bacfca65a5a3a98e073215340613a1dc6f2618 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 18:55:55 -0400 Subject: [PATCH 173/385] more unit tests for tokenizer functions constains() and matches() --- unittest/utils/test_tokenizer.cpp | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/unittest/utils/test_tokenizer.cpp b/unittest/utils/test_tokenizer.cpp index 4d38bfd14f..6db4a5fe5e 100644 --- a/unittest/utils/test_tokenizer.cpp +++ b/unittest/utils/test_tokenizer.cpp @@ -178,6 +178,9 @@ TEST(Tokenizer, contains) Tokenizer values("test word"); ASSERT_TRUE(values.contains("test")); ASSERT_TRUE(values.contains("word")); + values = Tokenizer("Triangles"); + ASSERT_TRUE(values.contains("angles")); + ASSERT_TRUE(values.contains("Triangles")); } TEST(Tokenizer, not_contains) @@ -190,13 +193,27 @@ TEST(Tokenizer, matches) { Tokenizer values("test word"); ASSERT_TRUE(values.matches("test")); + ASSERT_TRUE(values.matches("^test")); ASSERT_TRUE(values.matches("word")); + ASSERT_TRUE(values.matches("word$")); + ASSERT_TRUE(values.matches("^\\s*\\S+\\s+word")); + values = Tokenizer("Triangles"); + ASSERT_TRUE(values.matches("^\\s*Triangles\\s*$")); + values = Tokenizer("\t20\tatoms"); + ASSERT_TRUE(values.matches("^\\s*\\d+\\s+atoms\\s*$")); } TEST(Tokenizer, not_matches) { Tokenizer values("test word"); ASSERT_FALSE(values.matches("test2")); + ASSERT_FALSE(values.matches("^word")); + ASSERT_FALSE(values.matches("^ ")); + ASSERT_FALSE(values.matches(" $")); + values = Tokenizer("Triangles"); + ASSERT_FALSE(values.matches("^\\s*\\S+\\s+angles")); + values = Tokenizer("\t0x20\tatoms"); + ASSERT_FALSE(values.matches("^\\s*\\d+\\s+atoms\\s*$")); } TEST(Tokenizer, as_vector1) @@ -364,6 +381,9 @@ TEST(ValueTokenizer, contains) ValueTokenizer values("test word"); ASSERT_TRUE(values.contains("test")); ASSERT_TRUE(values.contains("word")); + values = ValueTokenizer("Triangles"); + ASSERT_TRUE(values.contains("angles")); + ASSERT_TRUE(values.contains("Triangles")); } TEST(ValueTokenizer, not_contains) @@ -376,13 +396,27 @@ TEST(ValueTokenizer, matches) { ValueTokenizer values("test word"); ASSERT_TRUE(values.matches("test")); + ASSERT_TRUE(values.matches("^test")); ASSERT_TRUE(values.matches("word")); + ASSERT_TRUE(values.matches("word$")); + ASSERT_TRUE(values.matches("^\\s*\\S+\\s+word")); + values = ValueTokenizer("Triangles"); + ASSERT_TRUE(values.matches("^\\s*Triangles\\s*$")); + values = ValueTokenizer("\t20\tatoms"); + ASSERT_TRUE(values.matches("^\\s*\\d+\\s+atoms\\s*$")); } TEST(ValueTokenizer, not_matches) { ValueTokenizer values("test word"); ASSERT_FALSE(values.matches("test2")); + ASSERT_FALSE(values.matches("^word")); + ASSERT_FALSE(values.matches("^ ")); + ASSERT_FALSE(values.matches(" $")); + values = ValueTokenizer("Triangles"); + ASSERT_FALSE(values.matches("^\\s*\\S+\\s+angles")); + values = ValueTokenizer("\t0x20\tatoms"); + ASSERT_FALSE(values.matches("^\\s*\\d+\\s+atoms\\s*$")); } TEST(ValueTokenizer, missing_int) From b89bc47626aa9e42613124b1bcd6f042b67a6b22 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 19:10:48 -0400 Subject: [PATCH 174/385] more thorough checks for molecule file header keywords --- src/molecule.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/molecule.cpp b/src/molecule.cpp index d0c8e793b3..88ad22fce6 100644 --- a/src/molecule.cpp +++ b/src/molecule.cpp @@ -447,30 +447,30 @@ void Molecule::read(int flag) int nmatch = values.count(); int nwant = 0; - if (values.contains("atoms")) { + if (values.matches("^\\s*\\d+\\s+atoms")) { natoms = values.next_int(); nwant = 2; - } else if (values.contains("bonds")) { + } else if (values.matches("^\\s*\\d+\\s+bonds")) { nbonds = values.next_int(); nwant = 2; - } else if (values.contains("angles")) { + } else if (values.matches("^\\s*\\d+\\s+angles")) { nangles = values.next_int(); nwant = 2; - } else if (values.contains("dihedrals")) { + } else if (values.matches("^\\s*\\d+\\s+dihedrals")) { ndihedrals = values.next_int(); nwant = 2; - } else if (values.contains("impropers")) { + } else if (values.matches("^\\s*\\d+\\s+impropers")) { nimpropers = values.next_int(); nwant = 2; - } else if (values.contains("fragments")) { + } else if (values.matches("^\\s*\\d+\\s+fragments")) { nfragments = values.next_int(); nwant = 2; - } else if (values.contains("mass")) { + } else if (values.matches("^\\s*\\f+\\s+mass")) { massflag = 1; masstotal = values.next_double(); nwant = 2; masstotal *= sizescale * sizescale * sizescale; - } else if (values.contains("com")) { + } else if (values.matches("^\\s*\\f+\\s+\\f+\\s+\\f+\\s+com")) { comflag = 1; com[0] = values.next_double(); com[1] = values.next_double(); @@ -480,8 +480,8 @@ void Molecule::read(int flag) com[1] *= sizescale; com[2] *= sizescale; if (domain->dimension == 2 && com[2] != 0.0) - error->all(FLERR, "Molecule file z center-of-mass must be 0.0 for 2d"); - } else if (values.contains("inertia")) { + error->all(FLERR, "Molecule file z center-of-mass must be 0.0 for 2d systems"); + } else if (values.matches("^\\s*\\f+\\s+\\f+\\s+\\f+\\s+\\f+\\s+\\f+\\s+\\f+\\s+inertia")) { inertiaflag = 1; itensor[0] = values.next_double(); itensor[1] = values.next_double(); @@ -497,7 +497,7 @@ void Molecule::read(int flag) itensor[3] *= scale5; itensor[4] *= scale5; itensor[5] *= scale5; - } else if (values.contains("body")) { + } else if (values.matches("^\\s*\\d+\\s+\\f+\\s+body")) { bodyflag = 1; avec_body = dynamic_cast(atom->style_match("body")); if (!avec_body) error->all(FLERR, "Molecule file requires atom style body"); @@ -506,7 +506,7 @@ void Molecule::read(int flag) nwant = 3; } else { // unknown header keyword - if (utils::strmatch(text, "^\\d+\\s+\\S+")) { + if (values.matches("^\\s*\\d+\\s+\\S+")) { values.next_int(); auto keyword = values.next_string(); error->one(FLERR, "Invalid header keyword: {}", keyword); From 61e391b4493c8a09b65f8bac032ab8b280876f72 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 19:28:04 -0400 Subject: [PATCH 175/385] correct check for invalid header keywords --- src/molecule.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/molecule.cpp b/src/molecule.cpp index 88ad22fce6..b25465ff83 100644 --- a/src/molecule.cpp +++ b/src/molecule.cpp @@ -506,11 +506,9 @@ void Molecule::read(int flag) nwant = 3; } else { // unknown header keyword - if (values.matches("^\\s*\\d+\\s+\\S+")) { - values.next_int(); - auto keyword = values.next_string(); - error->one(FLERR, "Invalid header keyword: {}", keyword); - } else + if (values.matches("^\\s*\\f+\\s+\\S+")) { + error->one(FLERR, "Unknown keyword or incorrectly formatted header line: {}", line); + } else { break; } if (nmatch != nwant) error->one(FLERR, "Invalid header line format in molecule file"); From 96f2e3259164071667344f6b4eb83764f8460d2e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 20:15:30 -0400 Subject: [PATCH 176/385] fix typo --- src/molecule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/molecule.cpp b/src/molecule.cpp index b25465ff83..55dfb4d15d 100644 --- a/src/molecule.cpp +++ b/src/molecule.cpp @@ -508,7 +508,7 @@ void Molecule::read(int flag) // unknown header keyword if (values.matches("^\\s*\\f+\\s+\\S+")) { error->one(FLERR, "Unknown keyword or incorrectly formatted header line: {}", line); - } else { + } else break; } if (nmatch != nwant) error->one(FLERR, "Invalid header line format in molecule file"); From f05c87cd43fda517f664071e0ff8404bc63f8dfc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 21:31:52 -0400 Subject: [PATCH 177/385] use proper const qualifier --- unittest/c-library/test_library_properties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index 043b6c08d9..11c38023ec 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -419,8 +419,8 @@ TEST_F(LibraryProperties, global) EXPECT_NE(sametag, nullptr); auto *tags = (tagint *)lammps_extract_atom(lmp, "id"); - tagint sometags[] = {1, 5, 10, 15, 20}; - for (int &sometag : sometags) { + const tagint sometags[] = {1, 5, 10, 15, 20}; + for (const int &sometag : sometags) { int idx = lammps_map_atom(lmp, (const void *)&sometag); EXPECT_EQ(sometag, tags[idx]); int nextidx = sametag[idx]; From 87060b2d3ef0971b136ce30d2ea05ea6be1bf2af Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 5 Jul 2024 21:37:04 -0400 Subject: [PATCH 178/385] display selected C++ standard as part of the CMake summary output --- cmake/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 617ba7fdb8..c6cb09f325 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -940,6 +940,7 @@ message(STATUS "<<< Compilers and Flags: >>> -- C++ Compiler: ${CMAKE_CXX_COMPILER} Type: ${CMAKE_CXX_COMPILER_ID} Version: ${CMAKE_CXX_COMPILER_VERSION} + C++ Standard: ${CMAKE_CXX_STANDARD} C++ Flags: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTYPE}} Defines: ${DEFINES}") get_target_property(OPTIONS lammps COMPILE_OPTIONS) From fecf38e11677d8e1f80625ba88b6646abbdf7d97 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sat, 6 Jul 2024 00:20:45 -0400 Subject: [PATCH 179/385] move d_type = atomKK->k_type.view() to compute() --- src/KOKKOS/angle_spica_kokkos.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index b630d808e1..c1b76ae14d 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -95,6 +95,7 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) neighborKK->k_anglelist.template sync(); anglelist = neighborKK->k_anglelist.template view(); int nanglelist = neighborKK->nanglelist; + d_type = atomKK->k_type.view(); nlocal = atom->nlocal; newton_bond = force->newton_bond; @@ -357,8 +358,6 @@ void AngleSPICAKokkos::init_style() error->all(FLERR,"Cannot use Kokkos pair style with rRESPA inner/middle"); } - d_type = atomKK->k_type.view(); - int ntypes = atomKK->ntypes; for (int i = 1; i <= ntypes; i++) for (int j = 1; j <= ntypes; j++) { From 9c8f7854adcbc1d68e8fd42c4473face4ae14d01 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 6 Jul 2024 00:50:15 -0400 Subject: [PATCH 180/385] avoid out-of-bounds string character access during completion --- tools/lammps-gui/CMakeLists.txt | 2 +- tools/lammps-gui/codeeditor.cpp | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 141918a319..1e928232f0 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(lammps-gui VERSION 1.5.11 LANGUAGES CXX) +project(lammps-gui VERSION 1.5.12 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) diff --git a/tools/lammps-gui/codeeditor.cpp b/tools/lammps-gui/codeeditor.cpp index 1762b0e496..9df2fc0124 100644 --- a/tools/lammps-gui/codeeditor.cpp +++ b/tools/lammps-gui/codeeditor.cpp @@ -582,7 +582,9 @@ void CodeEditor::keyPressEvent(QKeyEvent *event) if (line[begin].isSpace()) break; --begin; } - if (((cursor.positionInBlock() - begin) > 2) || (line[begin + 1] == '$')) runCompletion(); + if (((cursor.positionInBlock() - begin) > 2) || + ((line.length() > begin + 1) && (line[begin + 1] == '$'))) + runCompletion(); if (current_comp && current_comp->popup()->isVisible() && ((cursor.positionInBlock() - begin) < 2)) { current_comp->popup()->hide(); @@ -620,7 +622,7 @@ void CodeEditor::dropEvent(QDropEvent *event) if (event->mimeData()->hasUrls()) { event->accept(); auto file = event->mimeData()->urls()[0].toLocalFile(); - auto *gui = dynamic_cast(parent()); + auto *gui = dynamic_cast(parent()); if (gui) { moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor); gui->open_file(file); @@ -1093,11 +1095,12 @@ void CodeEditor::insertCompletedCommand(const QString &completion) // special characters as part of a word. auto cursor = textCursor(); auto line = cursor.block().text(); - int begin = cursor.positionInBlock(); - do { + int begin = qMin(cursor.positionInBlock(), line.length() - 1); + + while (begin >= 0) { if (line[begin].isSpace()) break; --begin; - } while (begin >= 0); + } int end = begin + 1; while (end < line.length()) { From fdf9ffee739085e247757592b7698dd79d27b95d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 6 Jul 2024 00:52:27 -0400 Subject: [PATCH 181/385] use auto for type --- unittest/c-library/test_library_properties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index 11c38023ec..52460b6b1e 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -420,7 +420,7 @@ TEST_F(LibraryProperties, global) auto *tags = (tagint *)lammps_extract_atom(lmp, "id"); const tagint sometags[] = {1, 5, 10, 15, 20}; - for (const int &sometag : sometags) { + for (const auto &sometag : sometags) { int idx = lammps_map_atom(lmp, (const void *)&sometag); EXPECT_EQ(sometag, tags[idx]); int nextidx = sametag[idx]; From c3f76dcc8103baba23b414b192648e5563364514 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sat, 6 Jul 2024 01:12:23 -0400 Subject: [PATCH 182/385] cleanup --- src/KOKKOS/angle_spica_kokkos.cpp | 22 +++++----------------- src/KOKKOS/angle_spica_kokkos.h | 9 +++------ 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index c1b76ae14d..e423d1d0b5 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -47,7 +47,7 @@ AngleSPICAKokkos::AngleSPICAKokkos(LAMMPS *lmp) : AngleSPICA(lmp) atomKK = (AtomKokkos *) atom; neighborKK = (NeighborKokkos *) neighbor; execution_space = ExecutionSpaceFromDevice::space; - datamask_read = X_MASK | F_MASK | ENERGY_MASK | VIRIAL_MASK; + datamask_read = X_MASK | F_MASK | TYPE_MASK | ENERGY_MASK | VIRIAL_MASK; datamask_modify = F_MASK | ENERGY_MASK | VIRIAL_MASK; centroidstressflag = CENTROID_NOTAVAIL; @@ -95,7 +95,7 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) neighborKK->k_anglelist.template sync(); anglelist = neighborKK->k_anglelist.template view(); int nanglelist = neighborKK->nanglelist; - d_type = atomKK->k_type.view(); + d_type = atomKK->k_type.template view(); nlocal = atom->nlocal; newton_bond = force->newton_bond; @@ -309,18 +309,14 @@ void AngleSPICAKokkos::allocate() { AngleSPICA::allocate(); - int nangletypes = atomKK->nangletypes; + int nangletypes = atom->nangletypes; k_k = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::k",nangletypes+1); k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",nangletypes+1); - k_repscale = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::repscale",nangletypes+1); - k_setflag = typename ArrayTypes::tdual_int_1d("AngleSPICA::setflag",nangletypes+1); d_k = k_k.template view(); d_theta0 = k_theta0.template view(); - d_repscale = k_repscale.template view(); - d_setflag = k_setflag.template view(); - int ntypes = atomKK->ntypes; + int ntypes = atom->ntypes; k_lj_type = typename ArrayTypes::tdual_int_2d("AngleSPICA::lj_type",ntypes+1,ntypes+1); k_lj1 = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::lj1",ntypes+1,ntypes+1); k_lj2 = typename ArrayTypes::tdual_ffloat_2d("AngleSPICA::lj2",ntypes+1,ntypes+1); @@ -358,7 +354,7 @@ void AngleSPICAKokkos::init_style() error->all(FLERR,"Cannot use Kokkos pair style with rRESPA inner/middle"); } - int ntypes = atomKK->ntypes; + int ntypes = atom->ntypes; for (int i = 1; i <= ntypes; i++) for (int j = 1; j <= ntypes; j++) { k_lj_type.h_view(i,j) = lj_type[i][j]; @@ -400,14 +396,10 @@ void AngleSPICAKokkos::coeff(int narg, char **arg) for (int i = 1; i <= n; i++) { k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; - k_repscale.h_view[i] = repscale[i]; - k_setflag.h_view[i] = setflag[i]; } k_k.template modify(); k_theta0.template modify(); - k_repscale.template modify(); - k_setflag.template modify(); } /* ---------------------------------------------------------------------- @@ -423,14 +415,10 @@ void AngleSPICAKokkos::read_restart(FILE *fp) for (int i = 1; i <= n; i++) { k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; - k_repscale.h_view[i] = repscale[i]; - k_setflag.h_view[i] = setflag[i]; } k_k.template modify(); k_theta0.template modify(); - k_repscale.template modify(); - k_setflag.template modify(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index 75c1010f08..4670bdabf0 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -81,13 +81,10 @@ class AngleSPICAKokkos : public AngleSPICA { int nlocal,newton_bond; int eflag,vflag; - typename ArrayTypes::tdual_ffloat_1d k_k, k_theta0, k_repscale; - typename ArrayTypes::t_ffloat_1d d_k, d_theta0, d_repscale; - - typename ArrayTypes::tdual_int_1d k_setflag; - typename ArrayTypes::t_int_1d d_setflag; - typename ArrayTypes::t_int_1d d_type; + + typename ArrayTypes::tdual_ffloat_1d k_k, k_theta0; + typename ArrayTypes::t_ffloat_1d d_k, d_theta0; typename ArrayTypes::tdual_int_2d k_lj_type; typename ArrayTypes::t_int_2d d_lj_type; From f34b6dacaf900ba81e9e28335f341cce08b5bccf Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 6 Jul 2024 09:55:22 -0400 Subject: [PATCH 183/385] improve fix indent documentation --- doc/src/fix_indent.rst | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/doc/src/fix_indent.rst b/doc/src/fix_indent.rst index e041f9f29b..3e269654ac 100644 --- a/doc/src/fix_indent.rst +++ b/doc/src/fix_indent.rst @@ -68,10 +68,10 @@ material or as an obstacle in a flow. Alternatively, it can be used as a constraining wall around a simulation; see the discussion of the *side* keyword below. -The *gstyle* geometry of the indenter can either be a sphere, a -cylinder, a cone, or a plane. +The *gstyle* keyword selects the geometry of the indenter and it can +either have the value of *sphere*, *cylinder*, *cone*, or *plane*\ . -A spherical indenter exerts a force of magnitude +A spherical indenter (*gstyle* = *sphere*) exerts a force of magnitude .. math:: @@ -82,13 +82,16 @@ distance from the atom to the center of the indenter, and *R* is the radius of the indenter. The force is repulsive and F(r) = 0 for *r* > *R*\ . -A cylindrical indenter exerts the same force, except that *r* is the -distance from the atom to the center axis of the cylinder. The -cylinder extends infinitely along its axis. +A cylindrical indenter (*gstyle* = *cylinder*) follows the same formula +for the force as a sphere, except that *r* is defined the distance +from the atom to the center axis of the cylinder. The cylinder extends +infinitely along its axis. -A conical indenter is similar to a cylindrical indenter except that it -has a finite length (between *lo* and *hi*), and that two different -radii (one at each end, *radlo* and *radhi*) can be defined. +.. versionadded:: 17April2024 + +A conical indenter (*gstyle* = *cone*) is similar to a cylindrical indenter +except that it has a finite length (between *lo* and *hi*), and that two +different radii (one at each end, *radlo* and *radhi*) can be defined. Spherical, cylindrical, and conical indenters account for periodic boundaries in two ways. First, the center point of a spherical @@ -101,15 +104,15 @@ or axis accounts for periodic boundaries. Both of these mean that an indenter can effectively move through and straddle one or more periodic boundaries. -A planar indenter is really an axis-aligned infinite-extent wall -exerting the same force on atoms in the system, where *R* is the -position of the plane and *r-R* is the distance from the plane. If -the *side* parameter of the plane is specified as *lo* then it will -indent from the lo end of the simulation box, meaning that atoms with -a coordinate less than the plane's current position will be pushed -towards the hi end of the box and atoms with a coordinate higher than -the plane's current position will feel no force. Vice versa if *side* -is specified as *hi*\ . +A planar indenter (*gstyle* = *plane*) behaves like an axis-aligned +infinite-extent wall with the same force expression on atoms in the +system as before, but where *R* is the position of the plane and *r-R* +is the distance of an from the plane. If the *side* parameter of the +plane is specified as *lo* then it will indent from the lo end of the +simulation box, meaning that atoms with a coordinate less than the +plane's current position will be pushed towards the hi end of the box +and atoms with a coordinate higher than the plane's current position +will feel no force. Vice versa if *side* is specified as *hi*\ . Any of the 4 quantities defining a spherical indenter's geometry can be specified as an equal-style :doc:`variable `, namely *x*, From 54901eb8a43e70a2cf521d95785454b769890d53 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 6 Jul 2024 09:55:41 -0400 Subject: [PATCH 184/385] remove pointless check --- src/fix_indent.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/fix_indent.cpp b/src/fix_indent.cpp index a8b14940f4..05aaf321a7 100644 --- a/src/fix_indent.cpp +++ b/src/fix_indent.cpp @@ -61,6 +61,7 @@ FixIndent::FixIndent(LAMMPS *lmp, int narg, char **arg) : // read geometry of indenter and optional args + istyle = NONE; int iarg = geometry(narg - 4, &arg[4]) + 4; options(narg - iarg, &arg[iarg]); @@ -474,14 +475,12 @@ int FixIndent::geometry(int narg, char **arg) { if (narg < 0) utils::missing_cmd_args(FLERR, "fix indent", error); - istyle = NONE; xstr = ystr = zstr = rstr = pstr = nullptr; xvalue = yvalue = zvalue = rvalue = pvalue = 0.0; // sphere if (strcmp(arg[0], "sphere") == 0) { - if (istyle != NONE) error->all(FLERR, "Fix indent requires a single geometry keyword"); if (5 > narg) utils::missing_cmd_args(FLERR, "fix indent sphere", error); if (utils::strmatch(arg[1], "^v_")) { @@ -508,7 +507,6 @@ int FixIndent::geometry(int narg, char **arg) // cylinder if (strcmp(arg[0], "cylinder") == 0) { - if (istyle != NONE) error->all(FLERR, "Fix indent requires a single geometry keyword"); if (5 > narg) utils::missing_cmd_args(FLERR, "fix indent cylinder", error); if (strcmp(arg[1], "x") == 0) { @@ -556,7 +554,6 @@ int FixIndent::geometry(int narg, char **arg) // cone if (strcmp(arg[0], "cone") == 0) { - if (istyle != NONE) error->all(FLERR, "Fix indent requires a single geometry keyword"); if (8 > narg) utils::missing_cmd_args(FLERR, "fix indent cone", error); if (strcmp(arg[1], "x") == 0) { @@ -619,7 +616,6 @@ int FixIndent::geometry(int narg, char **arg) // plane if (strcmp(arg[0], "plane") == 0) { - if (istyle != NONE) error->all(FLERR, "Fix indent requires a single geometry keyword"); if (4 > narg) utils::missing_cmd_args(FLERR, "fix indent plane", error); if (strcmp(arg[1], "x") == 0) cdim = 0; @@ -647,7 +643,7 @@ int FixIndent::geometry(int narg, char **arg) // invalid istyle arg - error->all(FLERR, "Unknown fix indent argument: {}", arg[0]); + error->all(FLERR, "Unknown fix indent geometry: {}", arg[0]); return 0; } From b7942ead3fd0765d2992acfab58aa4cbfaaecdba Mon Sep 17 00:00:00 2001 From: Jacob Gissinger Date: Sat, 6 Jul 2024 15:49:46 -0400 Subject: [PATCH 185/385] chunk docs typo --- doc/src/Howto_chunk.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/Howto_chunk.rst b/doc/src/Howto_chunk.rst index 858e8241d1..454e58cfa7 100644 --- a/doc/src/Howto_chunk.rst +++ b/doc/src/Howto_chunk.rst @@ -1,7 +1,7 @@ Use chunks to calculate system properties ========================================= -In LAMMS, "chunks" are collections of atoms, as defined by the +In LAMMPS, "chunks" are collections of atoms, as defined by the :doc:`compute chunk/atom ` command, which assigns each atom to a chunk ID (or to no chunk at all). The number of chunks and the assignment of chunk IDs to atoms can be static or change over From b1db2ddb3fd3189849ce97c6a38d160c07cff69b Mon Sep 17 00:00:00 2001 From: Jacob Gissinger Date: Sat, 6 Jul 2024 15:57:18 -0400 Subject: [PATCH 186/385] store 'nchunk for msd' on first pass because nchunk can be modified elsewhere --- src/compute_msd_chunk.cpp | 5 +++-- src/compute_msd_chunk.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compute_msd_chunk.cpp b/src/compute_msd_chunk.cpp index 6e7436d6ad..59aff980f1 100644 --- a/src/compute_msd_chunk.cpp +++ b/src/compute_msd_chunk.cpp @@ -32,6 +32,7 @@ ComputeMSDChunk::ComputeMSDChunk(LAMMPS *lmp, int narg, char **arg) : { if (narg != 4) error->all(FLERR, "Illegal compute msd/chunk command"); + msdnchunk = 0; array_flag = 1; size_array_cols = 4; size_array_rows = 0; @@ -117,14 +118,14 @@ void ComputeMSDChunk::compute_array() double massone; double unwrap[3]; - int oldnchunk = nchunk; ComputeChunk::compute_array(); int *ichunk = cchunk->ichunk; // first time call, allocate per-chunk arrays // thereafter, require nchunk remain the same - if (!firstflag && (oldnchunk != nchunk)) + if (firstflag) msdnchunk = nchunk; + else if (msdnchunk != nchunk) error->all(FLERR, "Compute msd/chunk nchunk is not static"); // zero local per-chunk values diff --git a/src/compute_msd_chunk.h b/src/compute_msd_chunk.h index aba0c25fcb..38883ee904 100644 --- a/src/compute_msd_chunk.h +++ b/src/compute_msd_chunk.h @@ -35,6 +35,8 @@ class ComputeMSDChunk : public ComputeChunk { double memory_usage() override; private: + int msdnchunk; + char *id_fix; class FixStoreGlobal *fix; From 08cf19955d272ebd8ed5f4ab24ff80fee83f3fea Mon Sep 17 00:00:00 2001 From: Jacob Gissinger Date: Sat, 6 Jul 2024 17:57:18 -0400 Subject: [PATCH 187/385] minor corrections to 'reset_atoms' docs --- doc/src/reset_atoms.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/src/reset_atoms.rst b/doc/src/reset_atoms.rst index 89f9557d7c..0c0bbf43c8 100644 --- a/doc/src/reset_atoms.rst +++ b/doc/src/reset_atoms.rst @@ -32,7 +32,7 @@ Syntax .. code-block:: LAMMPS - reset atoms mol group-ID keyword value ... + reset_atoms mol group-ID keyword value ... * group-ID = ID of group of atoms whose molecule IDs will be reset * zero or more keyword/value pairs can be appended @@ -66,16 +66,16 @@ Description .. versionadded:: 22Dec2022 The *reset_atoms* command resets the values of a specified atom -property. In contrast to the set command, it does this in a +property. In contrast to the *set* command, it does this in a collective manner which resets the values for many atoms in a -self-consistent way. This is often useful when the simulated system -has undergone significant modifications like adding or removing atoms -or molecules, joining data files, changing bonds, or large-scale +self-consistent way. This command is often useful when the simulated +system has undergone significant modifications like adding or removing +atoms or molecules, joining data files, changing bonds, or large-scale diffusion. The new values can be thought of as a *reset*, similar to values atoms would have if a new data file were being read or a new simulation -performed. Note that the set command also resets atom properties to +performed. Note that the *set* command also resets atom properties to new values, but it treats each atom independently. The *property* setting can be *id* or *image* or *mol*. For *id*, the @@ -90,7 +90,7 @@ keyword/value settings are given below. ---------- -*Property id* +Property: *id* Reset atom IDs for the entire system, including all the global IDs stored for bond, angle, dihedral, improper topology data. This will @@ -146,7 +146,7 @@ processor have consecutive IDs, as the :doc:`create_atoms ---------- -*Property image* +Property: *image* Reset the image flags of atoms so that at least one atom in each molecule has an image flag of 0. Molecular topology is respected so @@ -191,7 +191,7 @@ flags. ---------- -*Property mol* +Property: *mol* Reset molecule IDs for a specified group of atoms based on current bond connectivity. This will typically create a new set of molecule @@ -266,7 +266,7 @@ The *image* property can only be used when the atom style supports bonds. Related commands """""""""""""""" -:doc:`compute fragment/atom ` +:doc:`compute fragment/atom `, :doc:`fix bond/react `, :doc:`fix bond/create `, :doc:`fix bond/break `, From 1a30fe53499c579495d370f1fdafeba2dc096ef6 Mon Sep 17 00:00:00 2001 From: Jacob Gissinger Date: Sat, 6 Jul 2024 18:03:43 -0400 Subject: [PATCH 188/385] reset_atoms: one more grammar tweak --- doc/src/reset_atoms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/reset_atoms.rst b/doc/src/reset_atoms.rst index 0c0bbf43c8..3b4ee816d8 100644 --- a/doc/src/reset_atoms.rst +++ b/doc/src/reset_atoms.rst @@ -203,7 +203,7 @@ For purposes of this operation, molecules are identified by the current bond connectivity in the system, which may or may not be consistent with the current molecule IDs. A molecule in this context is a set of atoms connected to each other with explicit bonds. The specific algorithm -used is the one of :doc:`compute fragment/atom ` +used is the one of :doc:`compute fragment/atom `. Once the molecules are identified and a new molecule ID computed for each, this command will update the current molecule ID for all atoms in the group with the new molecule ID. Note that if the group excludes From 62ac8d0ab38da52e95105f7c55bb6c89022f177e Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 02:59:43 -0400 Subject: [PATCH 189/385] fixes --- .../cgspica/sds-monolayer/in.sds-regular | 2 +- src/KOKKOS/angle_spica_kokkos.cpp | 37 ++++++++++++++----- src/KOKKOS/angle_spica_kokkos.h | 9 +++-- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular b/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular index 2f80847fe0..fef6b80eca 100644 --- a/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular +++ b/examples/PACKAGES/cgspica/sds-monolayer/in.sds-regular @@ -5,7 +5,7 @@ dimension 3 atom_style full processors * * 1 -pair_style lj/spica/coul/long 15.0 +pair_style lj/spica/coul/long 15.0 bond_style harmonic angle_style spica special_bonds lj/coul 0.0 0.0 1.0 diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index e423d1d0b5..782517e58a 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -87,14 +87,27 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) d_vatom = k_vatom.template view(); } + atomKK->sync(execution_space,datamask_read); k_k.template sync(); k_theta0.template sync(); + k_repscale.template sync(); + k_lj_type.template sync(); + k_lj1.template sync(); + k_lj2.template sync(); + k_lj3.template sync(); + k_lj4.template sync(); + k_rminsq.template sync(); + k_emin.template sync(); + + if (eflag || vflag) atomKK->modified(execution_space,datamask_modify); + else atomKK->modified(execution_space,F_MASK); x = atomKK->k_x.template view(); f = atomKK->k_f.template view(); neighborKK->k_anglelist.template sync(); anglelist = neighborKK->k_anglelist.template view(); int nanglelist = neighborKK->nanglelist; + atomKK->k_type.template sync(); d_type = atomKK->k_type.template view(); nlocal = atom->nlocal; newton_bond = force->newton_bond; @@ -312,9 +325,13 @@ void AngleSPICAKokkos::allocate() int nangletypes = atom->nangletypes; k_k = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::k",nangletypes+1); k_theta0 = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::theta0",nangletypes+1); + k_repscale = typename ArrayTypes::tdual_ffloat_1d("AngleSPICA::repscale",nangletypes+1); + k_setflag = typename ArrayTypes::tdual_int_1d("AngleSPICA::setflag",nangletypes+1); d_k = k_k.template view(); d_theta0 = k_theta0.template view(); + d_repscale = k_repscale.template view(); + d_setflag = k_setflag.template view(); int ntypes = atom->ntypes; k_lj_type = typename ArrayTypes::tdual_int_2d("AngleSPICA::lj_type",ntypes+1,ntypes+1); @@ -332,7 +349,6 @@ void AngleSPICAKokkos::allocate() d_lj4 = k_lj4.template view(); d_rminsq = k_rminsq.template view(); d_emin = k_emin.template view(); - } /* ---------------------------------------------------------------------- @@ -373,14 +389,6 @@ void AngleSPICAKokkos::init_style() k_lj4.template modify(); k_rminsq.template modify(); k_emin.template modify(); - - k_lj_type.template sync(); - k_lj1.template sync(); - k_lj2.template sync(); - k_lj3.template sync(); - k_lj4.template sync(); - k_rminsq.template sync(); - k_emin.template sync(); } /* ---------------------------------------------------------------------- @@ -396,10 +404,17 @@ void AngleSPICAKokkos::coeff(int narg, char **arg) for (int i = 1; i <= n; i++) { k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; + k_repscale.h_view[i] = repscale[i]; + k_setflag.h_view[i] = setflag[i]; } k_k.template modify(); k_theta0.template modify(); + k_repscale.template modify(); + k_setflag.template modify(); + + Kokkos::printf("*** AngleSPICAKokkos::coeff\n"); + } /* ---------------------------------------------------------------------- @@ -415,10 +430,14 @@ void AngleSPICAKokkos::read_restart(FILE *fp) for (int i = 1; i <= n; i++) { k_k.h_view[i] = k[i]; k_theta0.h_view[i] = theta0[i]; + k_repscale.h_view[i] = repscale[i]; + k_setflag.h_view[i] = setflag[i]; } k_k.template modify(); k_theta0.template modify(); + k_repscale.template modify(); + k_setflag.template modify(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/angle_spica_kokkos.h b/src/KOKKOS/angle_spica_kokkos.h index 4670bdabf0..4865c684a2 100644 --- a/src/KOKKOS/angle_spica_kokkos.h +++ b/src/KOKKOS/angle_spica_kokkos.h @@ -81,10 +81,11 @@ class AngleSPICAKokkos : public AngleSPICA { int nlocal,newton_bond; int eflag,vflag; - typename ArrayTypes::t_int_1d d_type; - - typename ArrayTypes::tdual_ffloat_1d k_k, k_theta0; - typename ArrayTypes::t_ffloat_1d d_k, d_theta0; + typename ArrayTypes::tdual_int_1d k_setflag; + typename ArrayTypes::t_int_1d d_setflag, d_type; + + typename ArrayTypes::tdual_ffloat_1d k_k, k_theta0, k_repscale; + typename ArrayTypes::t_ffloat_1d d_k, d_theta0, d_repscale; typename ArrayTypes::tdual_int_2d k_lj_type; typename ArrayTypes::t_int_2d d_lj_type; From 68231e9ba4cd0a1c05c89307c55e7f7d6be51f9f Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 05:49:03 -0400 Subject: [PATCH 190/385] minor formatting changes --- src/KOKKOS/angle_spica_kokkos.cpp | 2 +- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 10 +++++++--- src/KOKKOS/pair_lj_spica_kokkos.cpp | 3 --- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 782517e58a..227307c26f 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -371,7 +371,7 @@ void AngleSPICAKokkos::init_style() } int ntypes = atom->ntypes; - for (int i = 1; i <= ntypes; i++) + for (int i = 1; i <= ntypes; i++) { for (int j = 1; j <= ntypes; j++) { k_lj_type.h_view(i,j) = lj_type[i][j]; k_lj1.h_view(i,j) = lj1[i][j]; diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp index 1f7573836a..3a2271516e 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -12,6 +12,10 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing author: Mitch Murphy (alphataubio@gmail.com) +------------------------------------------------------------------------- */ + #include "pair_lj_spica_coul_long_kokkos.h" #include "atom_kokkos.h" @@ -101,20 +105,21 @@ void PairLJSPICACoulLongKokkos::compute(int eflag_in, int vflag_in) x = atomKK->k_x.view(); c_x = atomKK->k_x.view(); f = atomKK->k_f.view(); - q = atomKK->k_q.view(); type = atomKK->k_type.view(); nlocal = atom->nlocal; nall = atom->nlocal + atom->nghost; + newton_pair = force->newton_pair; special_lj[0] = force->special_lj[0]; special_lj[1] = force->special_lj[1]; special_lj[2] = force->special_lj[2]; special_lj[3] = force->special_lj[3]; + + q = atomKK->k_q.view(); special_coul[0] = force->special_coul[0]; special_coul[1] = force->special_coul[1]; special_coul[2] = force->special_coul[2]; special_coul[3] = force->special_coul[3]; qqrd2e = force->qqrd2e; - newton_pair = force->newton_pair; // loop over neighbors of my atoms @@ -303,7 +308,6 @@ void PairLJSPICACoulLongKokkos::allocate() PairLJSPICACoulLong::allocate(); int n = atom->ntypes; - memory->destroy(cutsq); memoryKK->create_kokkos(k_cutsq,cutsq,n+1,n+1,"pair:cutsq"); d_cutsq = k_cutsq.template view(); diff --git a/src/KOKKOS/pair_lj_spica_kokkos.cpp b/src/KOKKOS/pair_lj_spica_kokkos.cpp index 70376d1f63..872aed86ac 100644 --- a/src/KOKKOS/pair_lj_spica_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_kokkos.cpp @@ -70,7 +70,6 @@ void PairLJSPICAKokkos::compute(int eflag_in, int vflag_in) eflag = eflag_in; vflag = vflag_in; - if (neighflag == FULL) no_virial_fdotr_compute = 1; ev_init(eflag,vflag,0); @@ -273,8 +272,6 @@ double PairLJSPICAKokkos::init_one(int i, int j) return cutone; } - - namespace LAMMPS_NS { template class PairLJSPICAKokkos; #ifdef LMP_KOKKOS_GPU From 2459b7e9750ac39095ce6accc86150cb71708af0 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 05:58:27 -0400 Subject: [PATCH 191/385] oops --- src/KOKKOS/angle_spica_kokkos.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 227307c26f..0e89c13967 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -380,6 +380,7 @@ void AngleSPICAKokkos::init_style() k_lj4.h_view(i,j) = lj4[i][j]; k_rminsq.h_view(i,j) = rminsq[i][j]; k_emin.h_view(i,j) = emin[i][j]; + } } k_lj_type.template modify(); From bac8885739a0cd9431c3417704973d96e0208874 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 06:19:42 -0400 Subject: [PATCH 192/385] minor changes --- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 1 - src/KOKKOS/pair_lj_spica_kokkos.cpp | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp index 3a2271516e..039f4eba0c 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -26,7 +26,6 @@ #include "force.h" #include "kokkos.h" #include "memory_kokkos.h" -#include "neigh_list.h" #include "neigh_request.h" #include "neighbor.h" #include "respa.h" diff --git a/src/KOKKOS/pair_lj_spica_kokkos.cpp b/src/KOKKOS/pair_lj_spica_kokkos.cpp index 872aed86ac..aa81911e9b 100644 --- a/src/KOKKOS/pair_lj_spica_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_kokkos.cpp @@ -107,6 +107,8 @@ void PairLJSPICAKokkos::compute(int eflag_in, int vflag_in) // loop over neighbors of my atoms + copymode = 1; + EV_FLOAT ev = pair_compute,void >(this,(NeighListKokkos*)list); if (eflag) eng_vdwl += ev.evdwl; @@ -131,8 +133,13 @@ void PairLJSPICAKokkos::compute(int eflag_in, int vflag_in) if (vflag_fdotr) pair_virial_fdotr_compute(this); + copymode = 0; } +/* ---------------------------------------------------------------------- + compute pair force between atoms i and j + ---------------------------------------------------------------------- */ + template template KOKKOS_INLINE_FUNCTION @@ -153,6 +160,10 @@ compute_fpair(const F_FLOAT& rsq, const int& i, const int&j, const int& itype, c return a* ( lj_1*r6inv*b - lj_2 * r2inv); } +/* ---------------------------------------------------------------------- + compute pair potential energy between atoms i and j + ---------------------------------------------------------------------- */ + template template KOKKOS_INLINE_FUNCTION From 2cb3cb3323e4b99a9f202c3bce5984bed2208755 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 11:04:11 -0400 Subject: [PATCH 193/385] merging charmmfsw properly into spica (1st try) --- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 17 ++++++++++------- src/KOKKOS/pair_lj_spica_coul_long_kokkos.h | 14 ++++++++------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp index 039f4eba0c..d833914e4e 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -65,8 +65,8 @@ PairLJSPICACoulLongKokkos::~PairLJSPICACoulLongKokkos() memoryKK->destroy_kokkos(k_eatom,eatom); memoryKK->destroy_kokkos(k_vatom,vatom); memoryKK->destroy_kokkos(k_cutsq,cutsq); - memoryKK->destroy_kokkos(k_cut_lj,cut_lj); - memoryKK->destroy_kokkos(k_cut_ljsq,cut_ljsq); + //memoryKK->destroy_kokkos(k_cut_lj,cut_lj); + //memoryKK->destroy_kokkos(k_cut_ljsq,cut_ljsq); } } @@ -311,9 +311,9 @@ void PairLJSPICACoulLongKokkos::allocate() memoryKK->create_kokkos(k_cutsq,cutsq,n+1,n+1,"pair:cutsq"); d_cutsq = k_cutsq.template view(); - d_cut_lj = typename AT::t_ffloat_2d("pair:cut_lj",n+1,n+1); - d_cut_ljsq = typename AT::t_ffloat_2d("pair:cut_ljsq",n+1,n+1); - d_cut_coulsq = typename AT::t_ffloat_2d("pair:cut_coulsq",n+1,n+1); + //d_cut_lj = typename AT::t_ffloat_2d("pair:cut_lj",n+1,n+1); + //d_cut_ljsq = typename AT::t_ffloat_2d("pair:cut_ljsq",n+1,n+1); + //d_cut_coulsq = typename AT::t_ffloat_2d("pair:cut_coulsq",n+1,n+1); k_params = Kokkos::DualView("PairLJSPICACoulLong::params",n+1,n+1); params = k_params.template view(); @@ -447,6 +447,9 @@ void PairLJSPICACoulLongKokkos::init_style() { PairLJSPICACoulLong::init_style(); + //Kokkos::deep_copy(d_cut_ljsq,cut_ljsq); + Kokkos::deep_copy(d_cut_coulsq,cut_coulsq); + // error if rRESPA with inner levels if (update->whichflag == 1 && utils::strmatch(update->integrate_style,"^respa")) { @@ -481,8 +484,8 @@ double PairLJSPICACoulLongKokkos::init_one(int i, int j) k_params.h_view(i,j).lj3 = lj3[i][j]; k_params.h_view(i,j).lj4 = lj4[i][j]; k_params.h_view(i,j).offset = offset[i][j]; - k_params.h_view(i,j).cutsq = cutone*cutone; - k_params.h_view(i,j).cut_lj = cut_lj[i][j]; + //k_params.h_view(i,j).cutsq = cutone*cutone; + //k_params.h_view(i,j).cut_lj = cut_lj[i][j]; k_params.h_view(i,j).cut_ljsq = cut_ljsq[i][j]; k_params.h_view(i,j).cut_coulsq = cut_coulsq; k_params.h_view(i,j).lj_type = lj_type[i][j]; diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h index 73ebf82b23..02c5d58599 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.h @@ -49,12 +49,12 @@ class PairLJSPICACoulLongKokkos : public PairLJSPICACoulLong { void init_style() override; double init_one(int, int) override; - struct params_lj_coul{ + struct params_lj_coul { KOKKOS_INLINE_FUNCTION - params_lj_coul() {cutsq=0;cut_coulsq=0;cut_lj=0;cut_ljsq=0;lj1=0;lj2=0;lj3=0;lj4=0;offset=0;lj_type=0;}; + params_lj_coul() {cut_ljsq=0;cut_coulsq=0;lj1=0;lj2=0;lj3=0;lj4=0;offset=0;lj_type=0;}; KOKKOS_INLINE_FUNCTION - params_lj_coul(int /*i*/) {cutsq=0;cut_coulsq=0;cut_lj=0;cut_ljsq=0;lj1=0;lj2=0;lj3=0;lj4=0;offset=0;lj_type=0;}; - F_FLOAT cutsq,cut_coulsq,cut_lj,cut_ljsq,lj1,lj2,lj3,lj4,offset; + params_lj_coul(int /*i*/) {cut_ljsq=0;cut_coulsq=0;lj1=0;lj2=0;lj3=0;lj4=0;offset=0;lj_type=0;}; + F_FLOAT cut_ljsq,cut_coulsq,lj1,lj2,lj3,lj4,offset; int lj_type; }; @@ -102,8 +102,10 @@ class PairLJSPICACoulLongKokkos : public PairLJSPICACoulLong { int newton_pair; - typename AT::tdual_ffloat_2d k_cutsq, k_cut_lj, k_cut_ljsq; - typename AT::t_ffloat_2d d_cutsq, d_cut_lj, d_cut_ljsq, d_cut_coulsq; + typename AT::tdual_ffloat_2d k_cutsq; + typename AT::t_ffloat_2d d_cutsq; + typename AT::t_ffloat_2d d_cut_ljsq; + typename AT::t_ffloat_2d d_cut_coulsq; typename AT::t_ffloat_1d_randomread d_rtable, d_drtable, d_ftable, d_dftable, From 9c37e0f0dfd3f6a4db78f11e3dfe1e558618b563 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 15:32:12 -0400 Subject: [PATCH 194/385] add charmmfsw example for kokkos gpu testing --- examples/charmmfsw/charmmff.cmap | 340 +++++++++++++++++++++++++++ examples/charmmfsw/data.charmmfsw.gz | Bin 0 -> 764185 bytes examples/charmmfsw/in.charmmfsw | 47 ++++ 3 files changed, 387 insertions(+) create mode 100644 examples/charmmfsw/charmmff.cmap create mode 100644 examples/charmmfsw/data.charmmfsw.gz create mode 100644 examples/charmmfsw/in.charmmfsw diff --git a/examples/charmmfsw/charmmff.cmap b/examples/charmmfsw/charmmff.cmap new file mode 100644 index 0000000000..6fea0c508f --- /dev/null +++ b/examples/charmmfsw/charmmff.cmap @@ -0,0 +1,340 @@ +#CMAP for C NH1 CT1 C NH1 CT1 C NH1; id=1 +#phi = -180.000000 + 0.130000 0.770000 0.970000 1.250000 2.120000 + 2.720000 2.090000 1.790000 0.780000 -0.690000 + 1.000000 -2.200000 -4.830000 -4.820000 -4.910000 + -3.590000 -2.770000 -2.780000 -2.450000 -2.350000 + -2.340000 -1.520000 -0.950000 -0.040000 + +#phi = -165.000000 + -0.130000 1.380000 1.580000 1.870000 2.400000 + 2.490000 2.440000 1.930000 1.090000 0.640000 + 0.260000 -2.800000 -4.010000 -4.140000 -3.420000 + -2.600000 -2.300000 -1.500000 -1.100000 -0.860000 + -0.640000 -0.210000 -1.080000 -1.120000 + +#phi = -150.000000 + 0.080000 1.420000 1.620000 2.050000 2.650000 + 2.720000 2.320000 1.990000 1.560000 2.460000 + -0.230000 -1.820000 -2.580000 -3.010000 -2.550000 + -1.890000 -1.350000 -0.730000 0.070000 -0.230000 + -0.770000 -1.280000 -1.290000 -0.820000 + +#phi = -135.000000 + 0.930000 1.520000 2.240000 2.550000 3.110000 + 2.920000 2.460000 2.190000 2.060000 1.850000 + 0.120000 -1.180000 -2.000000 -2.280000 -1.960000 + -1.340000 -0.930000 0.020000 0.310000 -0.520000 + -1.150000 -0.980000 -0.570000 -0.440000 + +#phi = -120.000000 + 1.360000 1.960000 2.700000 3.040000 3.700000 + 3.560000 2.640000 2.770000 2.720000 1.630000 + 0.710000 -0.790000 -2.120000 -2.630000 -1.800000 + -0.430000 -0.060000 0.440000 0.910000 -0.550000 + -0.970000 -0.860000 -0.250000 0.450000 + +#phi = -105.000000 + 2.050000 2.540000 2.820000 3.090000 3.370000 + 3.550000 3.070000 2.900000 2.960000 2.120000 + 0.910000 -0.820000 -2.090000 -2.240000 -1.460000 + 0.210000 0.080000 0.770000 1.040000 -0.120000 + -0.320000 -0.160000 0.310000 0.730000 + +#phi = -90.000000 + 1.450000 2.750000 2.740000 3.160000 3.450000 + 3.340000 3.180000 3.900000 3.340000 2.440000 + 0.910000 -0.610000 -1.510000 -1.620000 -0.960000 + -0.020000 0.420000 0.910000 0.460000 0.150000 + -0.070000 0.020000 0.280000 0.750000 + +#phi = -75.000000 + 1.380000 3.350000 2.350000 3.060000 3.810000 + 3.700000 3.580000 4.210000 3.540000 1.690000 + 0.100000 -0.680000 -0.120000 -0.430000 -0.600000 + 0.230000 0.420000 0.300000 0.550000 0.190000 + -0.250000 -0.190000 -0.250000 0.470000 + +#phi = -60.000000 + 0.240000 1.230000 1.720000 3.170000 4.210000 + 4.390000 4.280000 3.670000 2.270000 -0.480000 + -0.410000 -0.040000 -0.360000 -0.820000 -0.170000 + 0.140000 0.270000 0.320000 0.310000 -0.670000 + -0.950000 -1.530000 -1.480000 -0.200000 + +#phi = -45.000000 + -1.180000 0.080000 2.350000 4.210000 5.380000 + 5.390000 4.380000 2.460000 1.120000 0.110000 + 0.010000 -0.150000 -0.800000 -0.580000 0.080000 + 0.270000 -0.050000 0.380000 0.250000 -0.890000 + -1.580000 -1.950000 -1.980000 -2.000000 + +#phi = -30.000000 + -1.170000 1.070000 4.180000 6.740000 6.070000 + 4.810000 2.780000 1.320000 0.770000 -0.010000 + 0.280000 -0.710000 1.310000 1.520000 1.920000 + 2.220000 0.190000 0.530000 0.330000 -1.600000 + -2.850000 -3.550000 -3.280000 -2.660000 + +#phi = -15.000000 + 0.290000 5.590000 3.730000 3.220000 3.270000 + 2.520000 1.590000 1.380000 0.860000 0.660000 + 1.620000 0.850000 0.510000 0.740000 1.020000 + 1.620000 -0.340000 0.180000 -0.610000 -2.560000 + -3.790000 -3.810000 -3.160000 -1.750000 + +#phi = 0.000000 + 2.830000 0.790000 0.320000 0.480000 0.630000 + 0.980000 1.240000 1.670000 1.650000 2.520000 + 1.610000 0.780000 0.120000 0.070000 0.120000 + -1.570000 -1.210000 -1.930000 -2.600000 -3.790000 + -3.930000 -3.620000 -2.680000 -0.920000 + +#phi = 15.000000 + -0.780000 -1.910000 -2.050000 -1.850000 -1.050000 + 0.180000 1.680000 2.220000 1.360000 2.450000 + 1.440000 0.680000 -0.240000 -0.540000 -0.790000 + -2.180000 -3.210000 -4.350000 -3.940000 -3.910000 + -3.460000 -2.770000 1.760000 0.310000 + +#phi = 30.000000 + -2.960000 -3.480000 -3.440000 -2.400000 -1.130000 + 0.340000 1.430000 1.390000 0.970000 2.460000 + 1.520000 0.550000 -0.410000 -1.480000 -3.580000 + -4.130000 -4.560000 -4.440000 -3.580000 -2.960000 + -1.960000 -1.070000 -1.600000 -2.450000 + +#phi = 45.000000 + -4.020000 -3.840000 -3.370000 -2.330000 -0.980000 + 0.360000 0.810000 0.750000 0.500000 1.900000 + 0.770000 -0.420000 -3.290000 -3.910000 -4.520000 + -4.890000 -3.850000 -4.150000 -2.670000 -2.370000 + -2.860000 -3.420000 -3.670000 -3.600000 + +#phi = 60.000000 + -3.350000 -2.980000 -2.320000 -1.240000 -0.260000 + 0.720000 0.670000 0.440000 2.400000 1.630000 + -2.010000 -3.310000 -3.990000 -4.530000 -4.850000 + -3.770000 -3.940000 -3.890000 -2.610000 -3.510000 + -3.760000 -3.640000 -3.450000 -3.340000 + +#phi = 75.000000 + -2.250000 -1.640000 -1.010000 0.040000 0.640000 + 0.820000 0.520000 -0.010000 -0.370000 -1.190000 + -2.390000 -3.380000 -4.500000 -5.590000 -5.510000 + -4.940000 -3.830000 -3.840000 -3.700000 -4.150000 + -4.170000 -3.730000 -3.740000 -2.620000 + +#phi = 90.000000 + -1.720000 -1.180000 -0.430000 0.280000 0.810000 + 0.800000 0.480000 -0.340000 -0.790000 -1.770000 + -2.810000 -3.800000 -5.220000 -6.280000 -6.580000 + -5.640000 -5.060000 -4.020000 -4.150000 -4.470000 + -4.100000 -3.770000 -3.160000 -2.650000 + +#phi = 105.000000 + -1.850000 -1.090000 -0.450000 0.130000 1.010000 + 0.880000 0.490000 -0.220000 -0.860000 -1.680000 + -3.010000 -4.130000 -5.990000 -6.860000 -6.830000 + -5.850000 -3.860000 -4.860000 -4.910000 -4.720000 + -4.600000 -4.090000 -3.270000 -2.410000 + +#phi = 120.000000 + -1.970000 -1.120000 -0.540000 -0.150000 0.760000 + 1.040000 0.760000 0.310000 -0.330000 -1.870000 + -3.370000 -5.010000 -6.120000 -7.050000 -6.980000 + -3.700000 -4.510000 -5.090000 -5.420000 -4.850000 + -4.440000 -4.000000 -3.420000 -2.750000 + +#phi = 135.000000 + -2.110000 -1.170000 -0.320000 -0.010000 0.320000 + 1.090000 0.940000 0.630000 -0.170000 -1.830000 + -3.470000 -4.950000 -6.110000 -1.920000 -4.050000 + -5.000000 -5.000000 -4.840000 -4.890000 -4.300000 + -4.490000 -4.440000 -4.160000 -3.180000 + +#phi = 150.000000 + -1.760000 -0.400000 0.020000 0.360000 0.630000 + 1.260000 1.360000 0.950000 -0.070000 -1.480000 + -3.150000 1.840000 -1.760000 -5.090000 -5.740000 + -5.390000 -4.780000 -4.190000 -4.120000 -4.040000 + -4.130000 -4.030000 -4.030000 -2.940000 + +#phi = 165.000000 + -0.810000 -0.070000 0.380000 0.540000 1.280000 + 1.640000 1.700000 1.520000 0.630000 -1.090000 + -2.740000 -0.740000 -4.560000 -6.410000 -5.890000 + -5.140000 -4.190000 -3.670000 -3.840000 -3.560000 + -3.550000 -3.250000 -2.750000 -1.810000 + + +#CMAP for C NH1 CT2 C NH1 CT2 C NH1; id=2 +#phi = -180.000000 + 0.235350 0.182300 0.177200 0.396800 0.859400 + 1.489700 2.092500 2.297700 1.808600 0.696200 + -0.563300 -1.432700 -1.015100 1.426300 -0.564300 + 0.696200 1.808200 2.301700 2.092600 1.489100 + 0.859500 0.396900 0.176900 0.182400 + +#phi = -165.000000 + 0.020100 -0.203800 -0.269700 0.014200 0.620800 + 1.392400 2.046200 2.188200 1.683900 0.688500 + -0.373700 -0.703500 0.837800 3.704000 -0.730100 + 0.594100 1.713100 2.205800 2.026400 1.529800 + 1.027400 0.623800 0.348400 0.182800 + +#phi = -150.000000 + -0.533600 -0.807400 -0.804600 -0.379800 0.365300 + 1.168000 1.641000 1.618100 1.302200 0.615100 + 0.065700 0.738500 2.959500 -2.036600 -0.934600 + 0.407900 1.517000 1.984800 1.833100 1.435200 + 0.995600 0.562200 0.150600 -0.209000 + +#phi = -135.000000 + -1.208500 -1.429400 -1.319200 -0.817500 -0.112400 + 0.454400 0.737600 0.879300 0.850100 0.670300 + 0.943500 -2.651200 -2.829400 -2.199100 -1.065700 + 0.279600 1.322000 1.668300 1.521300 1.193900 + 0.765300 0.246000 -0.315500 -0.823200 + +#phi = -120.000000 + -1.789100 -1.965500 -1.860700 -1.447900 -0.896500 + -0.401000 -0.015100 0.321300 0.634600 0.976300 + -1.977500 -2.883200 -2.848500 -2.137900 -0.960300 + 0.308700 1.098100 1.245300 1.133600 0.881800 + 0.448200 -0.153900 -0.823700 -1.404300 + +#phi = -105.000000 + -2.246700 -2.487000 -2.473700 -2.135600 -1.577700 + -0.980600 -0.429100 0.144700 0.734000 -0.918300 + -2.299200 -2.882200 -2.668600 -1.847100 -0.719800 + 0.107000 0.496000 0.553500 0.584300 0.494000 + 0.098300 -0.529800 -1.237900 -1.840100 + +#phi = -90.000000 + -2.851100 -3.181100 -3.199500 -2.785300 -2.054300 + -1.242900 -0.476500 0.288100 -0.045300 -1.470600 + -2.558800 -2.869400 -2.450300 -1.582200 -0.930800 + -0.426400 -0.022700 0.000000 -0.097400 -0.136100 + -0.439600 -1.038600 -1.741000 -2.373200 + +#phi = -75.000000 + -3.961800 -4.268200 -4.109000 -3.364700 -2.252200 + -1.140400 -0.209800 0.487300 -0.746200 -2.127700 + -2.932100 -2.898500 -2.247900 -1.730400 -1.177200 + -0.448200 0.034900 -0.073300 -0.531600 -0.933300 + -1.360700 -2.009200 -2.745700 -3.424900 + +#phi = -60.000000 + -5.408000 -5.355100 -4.640100 -3.283200 -1.710200 + -0.423800 0.354400 -0.103700 -1.577700 -2.828300 + -3.151200 -2.649200 -2.183000 -1.761200 -0.981700 + -0.174700 0.262600 0.039200 -0.663000 -1.530700 + -2.478200 -3.465600 -4.334200 -5.011200 + +#phi = -45.000000 + -6.093200 -5.298400 -3.816620 -1.922530 -0.196160 + 0.768200 0.568500 -0.831300 -2.343900 -3.037100 + -2.663700 -2.191100 -2.022900 -1.438500 -0.649000 + 0.077000 0.441500 0.257500 -0.491100 -1.820600 + -3.473100 -4.895200 -5.790700 -6.205900 + +#phi = -30.000000 + -5.258225 -3.675795 -1.631110 0.430085 1.496470 + 0.318200 -0.555100 -1.695500 -2.434200 -2.192600 + -1.691300 -1.890000 -1.708500 -1.206300 -0.567400 + 0.054300 0.497200 0.599600 -0.171000 -2.137600 + -4.237000 -5.584100 -6.135100 -6.067000 + +#phi = -15.000000 + -3.161820 -0.902080 1.432450 -1.452885 -1.560780 + -1.665600 -1.783100 -1.755100 -1.329300 -0.731100 + -1.317000 -1.662800 -1.601200 -1.294900 -0.817300 + -0.197100 0.549500 0.850400 -0.689700 -2.819900 + -4.393000 -5.111500 -5.205690 -4.654785 + +#phi = 0.000000 + 0.034035 -2.349860 -3.412065 -3.620070 -3.450950 + -2.875650 -1.787800 -0.541250 0.410450 -0.372500 + -1.126850 -1.498450 -1.608700 -1.498450 -1.126850 + -0.372500 0.410450 -0.541250 -1.787800 -2.875650 + -3.450950 -3.620070 -3.412065 -2.349860 + +#phi = 15.000000 + -3.162345 -4.654785 -5.205690 -5.111500 -4.393000 + -2.819900 -0.689700 0.850400 0.549500 -0.197100 + -0.817300 -1.294900 -1.601200 -1.662800 -1.317000 + -0.731100 -1.329300 -1.755100 -1.783100 -1.665600 + -1.560780 -1.452885 1.432450 -0.902080 + +#phi = 30.000000 + -5.258220 -6.067000 -6.135100 -5.584100 -4.237000 + -2.137600 -0.171000 0.599600 0.497200 0.054300 + -0.567400 -1.206300 -1.708500 -1.890000 -1.691300 + -2.192600 -2.434200 -1.695500 -0.555100 0.318200 + 1.496470 0.430085 -1.631110 -3.675795 + +#phi = 45.000000 + -6.093300 -6.205900 -5.790700 -4.895200 -3.473100 + -1.820600 -0.491100 0.257500 0.441500 0.077000 + -0.649000 -1.438500 -2.022900 -2.191100 -2.663700 + -3.037100 -2.343900 -0.831300 0.568500 0.768200 + -0.196160 -1.922530 -3.816620 -5.298400 + +#phi = 60.000000 + -5.407500 -5.011200 -4.334200 -3.465600 -2.478200 + -1.530700 -0.663000 0.039200 0.262600 -0.174700 + -0.981700 -1.761200 -2.183000 -2.649200 -3.151200 + -2.828300 -1.577700 -0.103700 0.354400 -0.423800 + -1.710200 -3.283200 -4.640100 -5.355100 + +#phi = 75.000000 + -3.961900 -3.424900 -2.745700 -2.009200 -1.360700 + -0.933300 -0.531600 -0.073300 0.034900 -0.448200 + -1.177200 -1.730400 -2.247900 -2.898500 -2.932100 + -2.127700 -0.746200 0.487300 -0.209800 -1.140400 + -2.252200 -3.364700 -4.109000 -4.268200 + +#phi = 90.000000 + -2.854500 -2.373200 -1.741000 -1.038600 -0.439600 + -0.136100 -0.097400 0.000000 -0.022700 -0.426400 + -0.930800 -1.582200 -2.450300 -2.869400 -2.558800 + -1.470600 -0.045300 0.288100 -0.476500 -1.242900 + -2.054300 -2.785300 -3.199500 -3.181100 + +#phi = 105.000000 + -2.246400 -1.840100 -1.237900 -0.529800 0.098300 + 0.494000 0.584300 0.553500 0.496000 0.107000 + -0.719800 -1.847100 -2.668600 -2.882200 -2.299200 + -0.918300 0.734000 0.144700 -0.429100 -0.980600 + -1.577700 -2.135600 -2.473700 -2.487000 + +#phi = 120.000000 + -1.788800 -1.404300 -0.823700 -0.153900 0.448200 + 0.881800 1.133600 1.245300 1.098100 0.308700 + -0.960300 -2.137900 -2.848500 -2.883200 -1.977500 + 0.976300 0.634600 0.321300 -0.015100 -0.401000 + -0.896500 -1.447900 -1.860700 -1.965500 + +#phi = 135.000000 + -1.208900 -0.823200 -0.315500 0.246000 0.765300 + 1.193900 1.521300 1.668300 1.322000 0.279600 + -1.065700 -2.199100 -2.829400 -2.651200 0.943500 + 0.670300 0.850100 0.879300 0.737600 0.454400 + -0.112400 -0.817500 -1.319200 -1.429400 + +#phi = 150.000000 + -0.533400 -0.209000 0.150600 0.562200 0.995600 + 1.435200 1.833100 1.984800 1.517000 0.407900 + -0.934600 -2.036600 2.959500 0.738500 0.065700 + 0.615100 1.302200 1.618100 1.641000 1.168000 + 0.365300 -0.379800 -0.804600 -0.807400 + +#phi = 165.000000 + 0.019900 0.182800 0.348400 0.623800 1.027400 + 1.529800 2.026400 2.205800 1.713100 0.594100 + -0.730100 3.704000 0.837800 -0.703500 -0.373700 + 0.688500 1.683900 2.188200 2.046200 1.392400 + 0.620800 0.014200 -0.269700 -0.203800 + + diff --git a/examples/charmmfsw/data.charmmfsw.gz b/examples/charmmfsw/data.charmmfsw.gz new file mode 100644 index 0000000000000000000000000000000000000000..0fe7d2df0b12f2f669aa1f69bb92269561da39e6 GIT binary patch literal 764185 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

^-u@Tlz~a}D4(|>dCEL8@^AyFUm-Yjq?G|qH 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 f1pY66zIn{k!X3khJj<3^d=~nn- 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 z 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

WtlT6#uny@ECb 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 literal 92717 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 VI8a-URa6rItngmGLiR)O{{Y5#U(Nsk diff --git a/doc/src/JPG/lammps-gui-running.png b/doc/src/JPG/lammps-gui-running.png index 3cc1589643e481479314614717b4eb9e492ad1bf..5afe17e01468a3f658838d0f36a2f827b7d694f0 100644 GIT binary patch literal 24963 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 Ef&_(wp8x;= diff --git a/doc/src/JPG/lammps-gui-yaml.png b/doc/src/JPG/lammps-gui-yaml.png new file mode 100644 index 0000000000000000000000000000000000000000..fa35d550db023c29fbdfe70bac88a980f1cba9be GIT binary patch literal 174862 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%0Al=<r!TUifss zaL|sqeZ3vYHlfqEKBjv8ekfL=u<+`z+5Cj}I!3O0z=j9|9@35m@m6gtNbG<46y4`+k8!NV@qBwZxK${F{DZ!J z=9j-e+@Nz{H7sCC<7-P=6+F@#!6s^}1 z_(wY>#gadeFiwdaGnh0}R;g zeXl?~&)400Y72`6Tw%ZV+Y?T1?nc(;4{T2kHql*9mt7r{Q=h@TTQske4nFnC5h6-D z3Z*IS*l+l&{zh8T9X*NMdWL9cl=sCL+Mo2QFH#awR^cv6F$BbSP*^vj&qaXbUj}1- zucMWUr2fQ?la#0cQo5zzJvF?0-L&HQiK4&U1(d?PBGuD-b9qC32NgL{MYw168xX)= zGjYVygl_j|)M>f2W)2l3xLWsYJcz&a$q`KM9`?*yV3*esd_sKyo2+c&UbZ!QzV*lv z0s58q*G36{QSZv`;0q3j$Mv?+;mvfz>ZRxTJR6|HQBK5eSvim8{LlbkVe1$bJiv^kJ)0bjPAIe+cMKBgzZ7uU_m(Zu>TN+P-Q;418Cr)S<{(YCUgUyPv0vl*gg}s>UUuo>QMXN zMFqn6uYZ;{=`< za?>sMbs5A-XB)QLi^$Epv&K6>-YKGub+2cX;2|R%0rX)#Kq~y z%&N2=mHK0i?v?TcbfWmP`Pz3AOw@ziAIH`^U39r{44mBf(M0^2sD3KJJd8NR;k?^~ z>uHZP9tMcIi^;chCluSf*aE5NA2+(OTgk*$(8c$HDZf1nIpt1voII&+cTSLX3$s-@ zX>C31CaB9`Zg=0JS0}Tdhn|YORo<=c;B_2;D}%Gk{o}mn+0G9@N6VN(JjIlSg`kLK z-#w>pzdU{vF|lsFW+%LRP4zz>A!-c&?H%Kh@$+1#gN*^r|m;L zOHOF?-bq1J#u<|c*e23?);J_~5_8B2njA5xsc7f1QDC8ZZF)YD)rgz4g8&mOsw=fn zo2=TTSG6PO_rra)XE0kN>%gUdq0!9qjZlByz3jo$OMt?++uCi!&EJl z+EwZDb}pX^i!=Is)u0A;_qcyr?kj)vi=VE;buHS-gr9~2Jj%mn^LT*D1OH_^&JcnE zKI!_BQBlhM23hYNG|zd<_S8s7ZS1cv$RI7Yxd_ywaIIzy)ANNwZB&3E7@03&cs+dS z%QqouX&SGqn_Z&9jW06|4J0264lI8G4$KA{c+5Y4gb4t@3qP>p?=sjl4ja`SUXMOG zjU|H(I3eM4co-^k~c(r~j_=B9*AHi=U>*Z~~SM!&Sdn0E!a%fiDpUBzd5U<>oPqoD( ziZO*a$An3Reb++Q)*eGGE$pGDR#DuevbZY@MJm?}i;ZQI}w)fA2S(X3wC=g0qK>|<@J?~uP9FQ4L=@c~5xgkvR z2Ox%miB-@C$JJeA+4XvIFR}KrbiVh3Bg9LuA4lv_Z3uo&T4(3DIa}bSPZgrqhcdEi zp2OVAY!u1)kc+V(=Q$`OlLEs!GoBM#5aQO1)Q*GWv==AFeQrDatDX;Gn7)tYg$F!| z@FUu;we!<30_3KM@$aq)_Cv{uC9qn#A@6{{UFA}32M;1yNHV@bd!~8fW$6>=GqY2& z0fZ1RvmnD3u1bOEaUFnHww5sfdM(H2Te7=Y2)h^%zh~i3CmZn4g03edM%aRk!7F{7 zA`Iq)>}7uXC7KaDJP?sDP;A=rQ{D%&ZwwS!N?JqsjpjEtFtGr)f%`S7rzJdvyU=O` za<+zfo1do*_sRxnbUn2f;yqa6HUYJ|UB7?2*LV0n1NwA+(pA?%4bNZ&w($Y4(R&U8 zN;Q@@D|Fi@>YTp61-W_YT8}0nFE3`Vw&rtybC0sD+_SFq;L` zDjNn9ToEvQVC$L8&lNK9V3@A5jLOT)`=+0%yP^|=<%8G!xc0Q~?+ZeG3r(j&2NtJE zdF`ulonSdFm~;Kr=lsa7`W&;B+9cf*AZ{LjvJp+=;iB7ZuhT{L;CLZF}-KU+Lc>+1i7r<-LI^^N@5_KX2#CNe?ZN{fiA1(D4#lr z&&g^BP{62&e1I?}*gr_A!Mz7C0T+Z1qEz6v1YUj{jK^eBgpcGG$2eaEUOxp|H~@Fa8g@`o{9J1#Oqf z(iMP*ER2H%xj=>CmFGkG08ZQLE2r>L@eBInE4Rav5hHx6;b{sP|19an-QJ*3cloRa zrkF5_dg4UgN!{s#(mp&-9X4#BG5*|^3-M510sXm_(bM^-;5BBrYEWtWbzR^`HU*IM z8DIP4Ix`0h3gCX(@;9$f&D&1YZKYBqP6Sb7o9nx`x=&wS01yP5!@_lPG^ah}AgkiK z&%E8DHU=D(WY-+}mRa8bE&~BQ=Bu=y!Vv2lp6*DVP@aH}#mkQXpRkEcaHIPgnoM^^ zg6nTonR&aUr6V&7 z3*S03oxd8B4=7TdNt z7q@lICv+t|a=&`R2NVb>4RRj{*^gH=e6?{uN$Qw*-@dq><#-Y&EsikkjmgLV+-#TP zKxl1a>W0RCk<*wqeGTpS)(uQ}_EypnyqE7!n{g_VOs@s~xN{=y5a(je``^IMGF1Py zs|5~bk@)>H3EK?b$9saksNX%y9}5)_5Z(+Y0WJS0-c|A{B7`XN(GD%f|Du0(l(P}E z;a!za*@F+WczGN>EaI2LI$$vuzrbQ(%~^rH;Q#t@eA!TQG$+&_%|dhXvgaqWx5x9Z(|SLMxnPcG&Lg+GNg3*5e_Nx-l|l1yKcEQC{OPFk z{4UP+T?zxqjYNBP=*oAa9`foxI6QC8B{!vC5WOtsKf2#E${z?_{cDNszgcqNZj0?K zT&^x~Q>KR3Ffsi!2vprzQU7ZCO-Y>uehsPmm+INyvJI6cM7Fv4Rt}9ZHQd-gJL5dO z^Wfm{p+;51GR(zUPp*aFr8Dbg$Fq6a`;K%txiaGH4J4d2Y2wP5_Nt4mtN2s zusUY1kiQ2a5|hB&ich+o7BvB1pA}L@3@5$j9qyCg08R`L26Q#UrE}@eR|Vq6`PVLw z{Y4h$r<^|?mS{c4i%`*cr1FFxyPcMR77b;nSmKRcqmp5M&FZ)qEuOU!Tv57rhGfEC zdR(KbD|1UvdYl3ImHJH20$y*dcmbuH=Rnog8T!mV8fy6F*OJ#c%gTgG!xGz_= zCINr>a?XlNwKZce3%b;@4r-$^YO(x(rS`Eg+BlL|=-I_EC0`WYD&<;kKX)081vwBB zvIF#7>%O!b9sMsnBrG6@&2~$6-lJ!vJLtC-V(e>~h)_kn=43{(LZ)tsGZ!hlr2(=X zz%OB?oy9!5zdwwZ6M^+lG@PS)%w_?;ZX6LO^kkT!JdsGBwQLPq528YpD$qlNCe3E& zedFgJ-th8qCWh<0+@=zczV!?qr3xyjL?+@k+Nejrvwm#xH$eWofNeIb+wbd*p8%5^Z~DKT#B$cd7u!o2$nL(C{@GkVz>1Y^gTiG*3DIX$W2)puJLpkO<0J&#Yc z#`(0jm8B(Y+EQc6QQxVuuUFZ5;U~|P&T!mTizGxbr*YeUteTtpJf@UYe2hNW->HTq z5@IS-cL#+5l{ap1n??s=C@ocH2mn;^uC}q*wmkKJIO`f7>28zXQqC6*05xT1t-DK- zFA>k=`>?g&zW@+<@b6|1mWbm5VTp%IoR)GhuIL>-t|7noQ(ZG*bdq%$bhxGJ_Uh{DB6MZItIJIW~Dlxx|2^tV?VbZ3!F8sLl>@9)9 zYetXmtI_}by%02s;+%#3_01=z`86|c+vn)VYKBOP0sUF=a4+k%FP@CE?u|Uur>zHS z1=iAcfOHkf?jBHadewoG&Iq=YW+G{D6%MgLv7IS15R9dKvc|R(1%P2=H|(5Z<1A0S z{iop@@rxnkcvhi41NN3%`xFFHFh)2k@Rj#EadxU@E%nlRyGpdmW(#P07RS@Ev~EEB36K311n-nbABUeLLNq-&L=xa`PZAxzO|FKBB&n z4sbybbGCkave@>V`S+?qUKrGIs^~y@b}-@E+vAab!Ot3JO*~@DGINY}sw)+E9soE9 ze}(VAvu5)jF4j&=@Hp^PeBEi7&4u^=v7K57*}4x#MovvE55bK%jRVSF#fX;Rf7 z7elun(F?vRe7uqFknW33p}`s1J0t=~cCX~aB^;4AH~ykdX-{rt{Pn?e^Ju!UELLFm zPxKHAJIV2rW`S{`N|A_P7w!FSHrtVf)t|OtK;^bS3!JBD3t1;6o5FN~f^=a+*gwnu z{juyKyQ2~JdORpet{cVqXa|Bsw5q9YyZ(NV)4M)Tega%r&TaREn#rsn=-fAY`&>*_ zVdEfW%M~&H3dl+MO-Q^$?XXzTiB6SFZP;DwpyYF>?o`CheUxbQ|H5@mh`**Crj@tP zon!s!`8}temgIHQEIr>6uJ3y;HZX5T*6!e^k+P{Wb~IH%>x>VZTUhS2_Gzq(K+yAH z5r5?|JLu!Fx$X0%*2DL;%QC$mS}sTZOy!_{Ik%iovAF-T01bZ6R?Q{eL-uP7bn)FO znVaBoV-NJ0nNNSUb6V;z{BG(?Jmm1Jpz|##tmd&lf+AV)>ul#N``->Dz&wn17*+Ax z_!`!&@5ixgr2V}7LBBlNqyGbNl&HOoQK(QgaU{+GOF4#ReR7y-=2$e=!L+=x^*Q3V zW>aP5%f2f|EfioLKb^uz;p%Sw1llQ2;_5N9$-s@`m(3AW2G0TkVweL1ib8~@3SxEX zUF1tqjahM2w%|?yVVawT{L0MCNQ?4Nbf)lO`KCtWQ&u%?x5>GR@0d(UQOgQEMc2)Shmt3yDRkIVr(i55aw)NxeNwx-@}(@y)pz@b*TC5{}Ng&GexoTcbf4l_IAlflkTqfEFT6+6fB_Tc1FNV;01-CD6WLaCg5o6!Wl576;v!(#V}PUYU-IS9vYxQGY<8p z(}T&EE^Va!rw zlkTWP${@GUH)!l%AW368MhA2WMU8#{sd|ML_j0H$j|3UCFXs=JZ0j=h$e~oTKh^O^9?_`NL9c#xWHf^U;##V}A$N8{T6Y;j z;a*Mu4Kl*t88R=UJFsgRIfF%9ss6kF)Ad9Ao3tAdUfu2M5&9YuB+mc+7i3usWco_$ z(dGD6H$(q;jTkB@YyY`8NSH?5eI>;o_DpOD0u2(?Mk=#0wr<5nl?Mxd-v)NDLLL zcnH&)Ut6JoxKqtp|qVFtyhJDDJOq zebP`(SI$5rh1%D{gG|`DtJbq`sX5g)0E}XsP9z z@ey$J>WFQ@TkhLVuA_cP@(B`?mb#tDj3Oin>;TW;DC>o?V^;7{8$9R_bpt$zRYWdi zlvl%s;Z5$8HW`&mrX)OynPJdSak=J$@Rff#X3qT(L4XT66WE&ZRaWPY$GCchSkDUt z)yQ3Q^Ye3aII*QdP4D!H;TI z^&Vrn1ID6r@BMthgZDEjQdR59)3n+R4|Pl5;ox`(Em;9|8DQVm+yv_}Qi6*22L`36 zv^noKcjuw(LhUEwZxt9{dhlT7v| zPzz=>w%p&IKD@*d<~AL}zOvG(xiO|so|vZJ-kw%!zk3ZR0TjsBH0JD`Jzj&U3e*aU z-=G$q2{3>I*j@L^iv{jyZ*O;9!P=MWaz&Q*j(%71k(k}m0tcbzAoZwO_oy#8t0&MC z%B<3-xS&unFyT`xMyQ>PYJSxPiO;pzg5eaxC;Rg17-q&Rc~eeZpNNW)NilnCx)_OX zkb`tj(U_a@iI0u!;+st#`g*7qIW59R|NlU480TR^#1rv%YXEj^i$N(kAQN!Gn|BVs zrXEkigSPXGvJ3?L@4yaDcT6?&3T>?ug@vRcxJWK=v`oqYt4koHkD!dN#$9j*V6!bG zws!qyj!ZuC6tlcaau00`aiyRaxWkW4AaN4ROk1ucfam6jXL)^2kRA(m&IqAsmlL`1tA8@Hm>Y@?-zW4; z0Krn5`jVIjmOGFlJ~_Rl>E?4A_)m~K?%X%qe>0Re{-sY%m6nUoWykhO(GPlads;XO z-K{HU-WP|H{@rm(h{#Bt(~iCSzsheMyfPini~(cXt=#n~-%ggR&hi^Yt?guouy0id z6?;xsPgJK~Qm;^_sh31()cQ8MJSbzYh zMR&fm*SoVTEUJhGT^^o2pKwe03HtHj7nv?3oR&%d7>-Ak(WlNR*UeL`7Owrx@`M%b zgflxOu?V4;RaqX;0tIix8{Qu?*Gi6r6$aso& z8W&h<3HVYbso@$Vf;E;1mVPbTp|-+fi1u9c4Pc@(qkQkm`EGRj`mSLV2)WR* z=!t(A?=vjwB89ZyF9qq7cgkj}|;Q{c34 z$9-3rBp}CIy1|7Vc>x};jMKN#oONSVcXO4ryEXV)NLCy>;-awDM6cA%vXwW`9ssx) zEpIQ-YPz4-t7*yAzK$CQT6L%+=~O2Ac1<w#HTTcizpe+#PIFDTG+^@E$ZcU6j_k z{J1^}_DzG^AbQh_nKZxsesEmDB(NR&+(NR)TG6cFURpSoZ_eIlCMuG04K8%_l>4cTI&Pe!^?){JU#@~6#gzc2$kwEOS5Exi&BUE3H!!EM=r}h^u!imDU(@2Cs}N zxi&ZZ*Yv>P2LkFGmar4X?`Z_m%N&?meB3SkJcSmP&um_S>sQuT!FEgJdaB>9Jf@tZ z!U(}hzCKmR`HhR)NZxnpPidrnptMyIO;DJE9;^ygcHu3p;LY4IK1-aMDL$+43$8_(>X+NjUa*va9bpo5~Jg>hot&G_;MP z5S=s((tSU4pvL_k(5_nVNqPbf&LqN*Ok^HS})SHnC~vLLlP>?A}>Djsa(^XIOm69OT*1#aq$hEqa&)jz1y+va1 zdCbV%6^a_Y-mn+07V;#%9JoE;^27OZ89(aw;Z_Moo7 zW?p*Ij}z&*;=i<~ClJ!mzhlpnN&Q=@**+*(1or&U6~^!J<`T0=@c8D!<^{7Tr@u#d zXbS=izIlp6vlYD?VdVvUzyO+-0SdUtKv=+6aVD3O4qJa`I!lXB^Gg&^iNh+NV-2J2 z^!#*Kb@+s*3QAYYkQiak@TM%d)(d(X6sXL2RE$Ta9pv3dv#>n*6vl<$H2?5HRh>*E zd~SdQ{c_OkrS-4$-3vBaHaSo{+4rWc-=o8F#-)vRzsYl8zn#pM=#p*;wkaWd^|1&t zUm716mAiCVd>4U6MnoJ(j!S$~%6ijOQ|1WuA*Y)%V$sBvYliHJBC6?RXK<|)iCZ+- zlF|s@HGUvyzMnepP>o6!+6oH@iC}anOB5YUb{6y0BWweq z1`_19q@0uj7xp`6HAYqh*2X&Fr?EhfGA+uGu+BbE;;fVezwu1VuT~-cIZ1OAxZ+5+ z_D3Bb$rb+DDT^+{VLWS&Nd`&KO{!J=e1A)@tLy4o$q-cLtdWhN_hYS z2_JWBS_zFrg?l1{nFgYOwLgnT>vMZOpS%uW3SU10igz2{_Rn+v6YA<;)7U&wIS5|a ziOylz@!$(ch*wrpkV_zn9=~!E{g;+(9@1kQ|oC8rz9q-@rsJ_ z%R8gd@fbmP_;8)Jme6^m7lhIVwA6|@*ao$qbH4z{r8aq6+}7t@*BI>{7)7H$_z$-v z3R<$QD(98Ru@rsmU86rv#K>L`H6Ero zS<>V3qz;eL&6Nx(gL>{HgzM3>=MVt!Rc54Xk{7xDX~y1e;2OS16@j(4+a%99>Jwp% z@^m${OjF~7ms{EWB8TyxPVIb~Q#%j{_=-UwD$X_QYEG+^D#d3>7nGkfPWLt73J=>f z^4b$J#m3YYfS{?`-8hLs_~EyTRo)_;XCx zPpjNUh-s(*U2w#WNxhb^#G*3_(NAb?lEDx9fCSNRT4{A5O_s#qVg4ASHRx6ZE7M|U>0WLOk~Uv;fU zFtuG%P~X^dEZ*1e@Q517kDfxf{0I(3gR>D)0G)fFgO1*X;TC#SglpxF_wl z|A{j14)2(<8S7B^=~jksuY`r2BVfcP-gavNy=fO<8ZDK+cPQg)~?D4B~`jd}DG^Z~~xaaVzE+Xu#5rc^|H5mej z76HXt34}+hm9q~#%nh~j$9~>&0o*S^l{rXgzap*>IO^+G336**F`_7xO$g6UW=;QS z3`B;j@z}J|v~EdOTy*()hdx-|i&ttTy;LkFk=o+KAm7z!>QTvyytwR_tTi#uy+XR0 z{qvHK#9!b#eLyp{;+6LOn>RO3(o*3eR>E>*kvVNfW@=`Rj;Ntz%j5ZKWS|+t)j>vr zth?rB=Sd_4RoC~!D5{*va~?V#7x!-faOlpwbF$y|atYIOEp=ueuII3yGBXTzhPPe|J;lOP@37-Z0^s?9fPt+6m+bI&4iOWtQufgZgm4Fe# zj=+wn31D&>cbF!xm4!Y%ic++}0W77qE!XHQIgT&+=K2ub_`uV!ksA*GV3V7}Fu|rt z;}JM?pFjza&Ei5|VV~GyjqmTJU%$L*!BY6d2wkj5WQI8#%VtESf)bH21I=WPRK|Ih zVp;hOZ{YdwBsG{nntR{!cAO}NfA?GYzVN^~|d((}PSt z0$$dUqS?3=jOJO3xQz zij0{@Th(@2fS}gY?~GCo>s7s8_wDjX=Y?hGUdtS@-Ld7G4WmPl@S!7`?xR|`!>QY= zch`-pk)>{0W39JBdd*93f_JeDPH04V_{dc@6pt*k*ne+s_qf`->YgeFDr7AO$#HUC zY4q7C*Ke!dR{q8Yxk5cPkFht;Ub5>jDsHivUe zf)<6s*W3bBLU;^>lHuV(0NT*DNQlZcn2NZOpY?u`^FMt_Wib?%+JN<``@)V4e?0P& z7YJzna&e;|(;W|6`y1`a{x_@qnjQ9Ed73(tz(?YVsfiDrol&{+h?0a}Xa>h_@Rh18 zVL=$)Z8B8=1z7nK2Ier@_Zf<5;TaVW9`NFJn+zNjgES0U7wv#t&S^RlvixTC5EGdqUL`pD zV)X%fsl!+M!|%;62k`H6eK6W>HrtxaeV3E#aT10E3k*P0`jl0zt}R`|?l9Qy@y{G= z6+jXO$G2yid$;8JPqBdVJLi*g_EVV-0?bgy=C2_2CmL6X2_|R@{>i6T{h!(IOLFzYqJJ(WE-xYPU-dV;Gbf!#Qd^{)I44dN zj8o(wQ(*ml&4*#cj5tq#l%FNf)zWwwaVt3ln zKYt$R!waFF7^ZHHhruApDGtMU#BT;+S9hc1&a2H19WGQBazR>9ohsUAEFT zst@X%V)^Hx{(U(t3)y$`X@joP2@H~de+Ura;NTFXpHxVGlsW|Tc0)zIj7wq&CI--# zjtyo0{I4Bsf|Y-g8GPF7W;dWLrK(^v@IM9iXObtE_w*aJ4eUb^M1;>ID~P+>=w<$? zn2>;+NPyj9O44?U;s=;T%d_OWxw;U1s*tk$!Lmf)pIhfj<^liiJLCd=6yhy;RU!0L zeb)HL{9ZXr3K{qXfO2Bc`Wj)R7?4%bntO+moJcJDE*1kQ0j%9_@+B7GJD_)60EF+M zPcaGt-H};z16y<)UyYgyyQd&(F)uee;kxl)^n%YHyse9cnV;l|hrqHC+~5U^z1o<- z+d_%=x*DL#i8dIr$7YmO!C+LY=#UQfgsw1yIJ24za0A&sFv_$3CDi{66k4nwCs4mX zcX6yNNDYplDQC%w?zi=;g4?$tuxQ-+a+0OjbzpTc3VM=Y-ZJRuyYl;)8<1vF0CFN_ z(|RYqWnYukXLdXo8VIKX3&SCZtD(iv@epNsla#|?i^JozJIaP3D;Y}lwply%u@y(> zPVx%Vy;}5F7)sMr5bC%b6%GQW&1z-E<{?GeKTV}sl8PmAyf)bZztoYh_E zu^Rn@BL=`5u3ddrX`M#s<=7z};~$gETPU3=3cHA?{kpXbM|B{}Q$=Mvi$2NiYxOP# z!4)N@;nh6x3l{&yn;n$4IK1xrwzw`J&hf;9l(E&xpN_(OV$_rL$3|E*=44GV|Fmr$ z;d}!FRw~mr;xF6o0N>BHuak?ViZ3CK(bj7A)m$lDx#KUt2;Fl~$neraU``5(LGRQ#BEmge7)?n0K2UVr2eAa!N-E_jR1m49G- z^<_z?>qm{eK4|ILs!Cl-ksa&2dih?S zr1JSJ1=8ifFNmoX`iAbOX!bo#PiQdKcS@yrSZ8*+QjSi|Dz|@%H;2RWbY4JF9f=bB z+<0BgvsFnYw(n{wQnhBU^?G)9cb7`LK%bad9xD#Iq}$+^%n;CUEeAm%lx$+$+e-r~ z(FS&hy2VD0f8(ZZOhoN_G3ADL((8RI9a{DN6Hiq5#-Nw}Q_J)DIciwP;JvsTte9dd zwOaBAZ`EO5@$$x6L}jLI%c3t9Dwm@|imX)n7v*1!LI+pneG@j*0t0_pF{;rsUhG|Y z6Y95Ah5A;uu{omX&U^g7SOEG5NCOXPGyloU8j*Ln3$Ch_fNa2ptwM+a2arY!9bNDV z^ED|8;@_<){R@%p)ZGrz0AECU72Bl%HJZHu1;^Sg4KWLq_hUD*kDLbVkxj$4%O7S2 zCXd-;5r|gCVf1kL<%fNjG!zMR13{Jorj8fx7$u4sxJ=bqw?Bd*<uYRb{k~M!&*fgjk;J1s%GqfWqy1o?Wf5hKbSsQOF8wyVMEbfJAWY zm7*#YXgfWoStDs)_bQk+ZTHo$C7jYhZhRisMNI9#Bk#qoGnR=B@JJ^chz@st&8@WfO3e*lR0FQ(z1kOj>>qJ7e@1 z4K;e~v%VHN<3(p5;z7}}`V znQi(%F8;HR%DLIT-X20aJtKTOvHDum2|6C8;~8&oCdm3!QYbjRo!1rI|5Zq2$;D#z za1f8!UeI{7scwJlf)_Q`igj8pDjr$o^vLUaMBEi6;4wEks;uSd7gVO65}4|HK@{2Y zZNt!IR`TuskkRUtocaxF3sm4o$5TgW^^J7NpvQ=+@DJa6R>yCre10GFqUFQujb?4$ zHYnW6OpA+qqwvh3)GY4TJ2J9X2+cE(_%h8#^2`lixVbZD8=cE+v0nAo#^GNCyc<4O zd1ksDSZVe~eu#6tACuMMRny#mP(u!x{tCylA z@Ge1iw%mHUSv}B6R1K*X7wm%eJwAhOmk&^2qB+Uvc#+WTCojii@t||Dd(L0U=9>(U z&%ZCN&Jqb;wA?NXY29Sh+JpD5PIv-8iCRy;Y80(g@f=5ZSk54=?A)1J8@C|9SyrfN z+S|4#eI(3^Gw!{fz+781bt-3qz$4@JtM1aWZ3k055jpU^ZGOGIJ^6cgbjqYoHd1OoBooDw=;;QCx3YDNEFZmXx^nsbk@L!n zvssp*g1xIv%ng7h8YS#;JhUsq)q>C}4Kot=;6A)6mc~NMr%(St@KmJchdPP#s3HL` zyWv7c6gDW#c(cY6{lBmhb@di``a}QeI7-6R7!a^^l?NDXCYpTKSB~&a{Px;#`*%zm zuP}^CKrd)17ut*PT%%??#<5p&y%O}UL`1b3HOWM$M*Nd1V{cJ>e|A4ON@)@)5?tXGF@Q>58RsV{!{#-w6s%p!0ip?fIY3$a-LgG4T-?m>mLcyY;Qg*4JHL(2}`Z9d3;bmNq)* z`ayq7q*~&GISe05csvmcB9T9*faQ)Y6YHI=0gA6z=4;|cUZX)CsRHfvCcZ^au`!;FFC@)&o8*`uNymX=I92Q>smaTeS{ zBtcumeC^_n!8Ke&0`|ayTj&I(geSeibL7Yh?Y8~{lBG2DVeh&K@wW)u(bsc6uM|Ve zoKc9PHjyp<26kHn6v@hsdG$XqPJ=({GoWUnkDx`NwcuxrOTWW)Dsg%LNJ-nYeQfb$ ze)HbX`)>~VnT3MKJVRu>_Nqiusz$qe>h1;430F>`0GfxBLhXI0t}EYO3bm^Mfwk4@ z3r)kL1^NWdnBVh*+?gkjZX%*Fe?tI9bi&om`7k_OE&1%f<)}~EE$6%Ermp0Wd-}mX zBKlO8JE>9t47{A_V)z}2bCPhKa9(*(4sOqjIg$|6#Pl~W)Kf+cpP~~!p=m3VXIAx* z-;$#DY}YDSQj>65ZLX@MKe@8b2ux|zYn8&r5Ne$4bDfqYIzz(ut*{!D)NgO6IRSzi z->jZFevW2YYkOI;2nM$6Sn6rmuLfXo&W-;CLbx<)9gU5++q!{n4s{7>5821PZ5ZfZ zZ#1)oa_dhYI~CbF+ue(r@u{oSsTq^^4bgqBf0!P=W8CwP?p6HOW6!CF``ifhp-BZE zZMOI8$gUpg#u)c{1D>9)=28YTlO_-=N`d=xtKI^FJ=sr7jcc-tn2?Q10F*T+sTayL zH``@SCq;3AOWc>e?p+wLs5n+Hrv-<-5@>G+tg!y32I1JHkcq;8^qK_Br9OY1T z`FK$>9zraL`BA%F6xD`eeS1(<=Ntng8Tq0kQj_b>rqOT}-4-^a2K2eFvWD7lEB&Ki z^7ZvWIaHF7{9n)fpN$iR*QLJxLOR{Y9s~RBoWy3yYckztc>$24;vK?JU~LQ6%%>VT z6J0%kD*pywns)Vf~7V^M4vANtMaP>W40HddCGY5-lT?Y=%67K|9xXcX(0*qlWYZgZZ#9#-84 z&XisQaA_Q21eGNVVo0F_ev%%JE}{WahClhE88z`KONV(#PG$lhf|%gc?K_Wb4-m4l z(VznoNei=M5r7u7PSkMCArx?k4i^{F(Bj_CT)$YL8ad&OhyHfP87(*0=uz1Al9aR4 z&Jo1m77mL=`2~}bQAO(B0a>(O+%GBW&%xJE-OK1@FW&%%mmTqn({NU*4f5SW>1>VF z-@K_rO)AnID2~CSQZbh*dRAL#f%7+`AfCNu&yRg|685UN`k@ig2*FDvHSgYC8b8?X zJpeIGjrHx%oIcFd8(}!hPwpv>n3AixvPpmouEaO7iUuK4L|5b$@9I;=j$M2t936Uf zg7(AJ@_QM`c68`nFe)Bk&{C6#n=Uxw7aV|6oPNg$mdwSH4jcQzukYgKrKf|XRyRR^ z_vsoNZ_>_6^w*{R2*%4^tlVbIWS8oURRY?%Um8yJ3&mF?uk5l`1=%m0nfvKTHSRYv zoalM534AnJ|K95!$hO_F2fvWRtRdMUmKVi}$H)X_j!#7>W521D&r=8d2oRs!Re}g8 z__-6uPVilK;L?PD-edQtX?Q_m^66+c2km72Si6!esA}Qa+vGnmkpGnO z=rL+>i>ppjqJzK4L=ZU0y^GLkApm)P+d;&nItx`J^Bqw>3SZO4c%^hZSt`TK_y+ds zw^=Rj^!pbwF3R&h&y+!ls;<_1p*UfB;krF{?&FH2*oqBQV4kI~lyiwjJ1sLE1u^Uu zgetGx$Nh+Eae8+||7b}2I?jozP2On$IUqn%<$Vh_1fbM;MZGmwmm6iC;EA6FsIp+_srF}T1GApXR#B{+`4zm%?}aI z&84RHz_{L9eO;c+J4Z!}l;i#vA415Z@W&{Y)>QV7++IBScC$YG=qd{xZPxteRR3nD zM{5{8-yAtml7vcQ!Z$GfkRBzaYQJ)v#NRllY3Ye5LeT*();B$qp_Cp!*KOL)?&RFh zN3@(mp~put@iKvbiyl2@I++webbM(&^HQ26>%j5}7suQ)qqZY6@ z|KRbOT_U2y%F|S0{RRUxwD1dJGo+YrO_h>bAsH-IRhSAX>Lp5%+1Y8C8XRN!IigC7 zYV(@fE|vyY$7Y95R_M0kAlx`c+B^v|TACylJi-W*H=B$n5@WOHeond9UXcYYo2LOy zo|a!tMW*d>TzvugM43YCAm}~d^}0x6{-;VcCnsWym+8%30qR$ZM4$3mjTs`@q9sB2 zuEsWenwdo1BO*aw{hML>!OUwi_dg{IsP_*UnVpwxmshWgi&6dkHwh8#JV^vFlS&Iv zFm`(Tl(u?)^ULTZ4xpO|*;eH9>9UPn6oqLSnhLYy>#40MFucf==>|g)a{_4yOwS?8K)`1^@dIF^F5&g(UmtYpmCL7d zkcZhuhdWr|#VaGT!&k<0Z1%%@pf0 zeT{_xzzL||Hea}BuEMw-N7R_Y<7zAUc34}D!Fpz6by<*B8Q#(>D*rPfWRwq@W&tD` ziRkI2Hm&*qD9gEhhv>#T+8f)J@Z<@}(^eAbMYI~N<*Vu#E_Ic*`3P0`J#dspL`JB= zQ4&ogXS-NDZ3tj~_Vm{BjPQ0T>l0=OtSuFwABG-Q_f4_a0=tL2Ud|4~VBTVP>8Z8aOYp7VO_p!{`*}pPm*S#~(=eIOj5gzdpUARYkCx|{s zQTShcK}@JQPpNvi_3ptN8~dZQQe6>E60$92vK0~m&#yv|mnWz&op8;)v1IS7C*TvS zS9<4nW)m3ARC9?0Xwz}H1o#AiQ7dHDGG4|~FSoj1QcFI8K#E`XFE91&SJjYU9+eUA zl<~CBH*Y$$^N&(K7gLFX=Bx}aYvNz=Cb?N$73w`}&6(lfRG=w!zBZzu9)z-;?iZe9 z-k#|soK4QYsrZDRJP1dK3+Y%SXa3&oXf_ppM&ux@Gah+pf&7wiP{^?+Zz~+|ytMtS zm&ToDc7B2QZe5H^JqEaJP@(CMnWLW>=Bit9)nPZG3Q!GR96zoG2p)_+`q6ewR`9*q z#aQHtM<-V2F488Mbw_{&v4zSselj&>r!diVumB$ssD~@q)DR<+XN}#~`!l(Q@08CU zPmXFzx_g!!-@p(sP5hs`DWLx|4d_HH=G&0W32sikkCr9-iMWa%YcMtQla|KMk@I*& z_ad20vQw_-GT7Zborx^w!@w;V@Ms zCCJWyO0e-DNGikOoLyG+f{K-Eu#&6>!=XR?74&--|Vjmm^QnIjJ9;oUN( zf5hs0mB;SPP;J6R*AwM$(s;sZ6F@CpI^ZOS-Y~8+zZh_6aCkvZP2cQtCj}lgU*5`| zD3&pxX4|FE++ky|2waDy49`9lrA`5&6o@PFPWOBh^=+p0Km?fNZbY-%m}Z&maQRQi z7C*qHXi-vP?JyGh6aTGqkBleK=H!r_+r!loXo_1}HZQ94gb)pCOasDfc0v-5Eio!I zg9WhR20u6G73yy|Z@KC9Enl-|B7HjTL&VPt7?1ErWS;jKY9%$Yn_eN ztwMCG&M%YePexe-72i-JTAe^vwugT2<@I^CSzm4(Hq&vxIi+t$+ZwLlFLy0Nu0qLP z#vj#b<&J-^W|6vF_nRtsWE;kq>#6}(XXnOu@R!8lcdoGB`Ml_rCtejeA}2t`Qm&^Y z1_Ge&E*tDrA9273LqgNvUq4mNS5_B%7gyO6u^0`{7R0Zs&2x=IU9eiG8$<0>Kb)HC zjh!JWLa2~4qn1+(j5ukgMuA}b;2cKtx`U|zOX@8 zkB^n!rteT#SoJc#jl4ye6Y4+tQmh~A&CZ5CG1I$S=D&~1YN^LbL>ec20{GMw#2ZiOIff>q;-x}f99 ziM8V;Y&E`|beCTLwdaynKV7ApkQ6U00u^8nzJQ4dD=OaJmuL`=q6Cu41_6uKz=PMs zE*Q;TMC{w?oA7g(U?7aEH6fW#RHD;z7Yj!Z zfXeM7of9bqTfclU7x7tLd!V>M51l?v8+Z8>f*=<6^k8zT&{IQytS)u9Ee~X(cnWzF z;I}l&=mhh5E(=f8QPMdA@aKkEP<83?CDu2a4`(;B`;GJQ{@%qOZpXuXt6r}0P@Kqo zn2&Hx9=Cg*iYg1^Z{C%@Ixapr5E#u9W(yQif=u>%%Y%r8YZ_mOYs7R}dn)chSEyu_ zgL=cp)Je-%=9>a>e^t5rE2H8Ucg%nJWF?K?aC_pe6w)RA8jQ$3U<3f1O$SDdy$j`6 zoE`QMGs--3fwgW7R{FLbe+KPzM^NF0XjcvO>hN0))A@JTtmEV1*jrB_9{<2P)ABe7 z_A<>dyNwrX_dT$|&}47Gq=ERm)-My*1_#AW0{wRfA_gL?dH;@1CsJ{=O8!0A%Dtmb zHX|O5BHkAW+=4XW{hYXbaG7`oeZT~98hmQtA)%~hQpiAGG6Sm0x~AwZe|-lSqy~HA ze0NrOBt^eOvNYb(DnY`Lzy94TvPS>t!3dYq@Z{nyNZ6H~A2;DYEzsel6mqPwS0Mqf zE>A^OxQ-VZrIQR@GxCl^R~Y&7aE`UOr(8+Yp0wE2cP3so5~{)C%l)h6SNiIpb&dO} z;d?_wqTC4@rgCD?2;?Py5g1clR}HuZpsUr1<#Y+sfHVI zJcWuHu70kzR97qVwm1`8cTKrZ@|=N&b3s&|G|tH@mL@aJGFy{OdE z@8?S^7WAd;WgDgA3pHMhV@_6UKhj52Ok@S6b4BR6#Tz}nm$TOPkJ#C*dcZ8)TCG8= z$Q4|^X7nXPcHa#Cdz^#WCzd_K*~0;xk7JR;QB6b~{%7NYeL_?!TDVcvZa!R}wM=t_6}q00G8#y!9K(E0gc zrvoFv;0~J;_{4zrKRhPDLj|QVRZ87Z`pfQpk@I;{rXo!aeW$Di2>v z&)fym!q!DT38_HzPw~y`XrSg{)?4!3QrTOqrlPZOONvB%-o^&{y7+GhD{8PHBjOlo zOl1dyTk~fg0a{DHwFdEM{@obkznF#u(X%CP(UTn1k-w7PyC1x!%vo)HN%^Yr9or4f94Wu?80jLf(R zsjUDP7ibtAwiV&Y=Z_oVOwDwH;k9JISB1LiTu^Y-#A)Tlw@%mIz)niWDBM1%PsuYPYvv+ zP~!N*JodxPoa)Rg>7H#`=h74Tlcz>0E)F?igKIl;acYTtwmotKV~_{h=IGMb){?$z zf@KK>Lji%n(}nW5CDxt%{(*tt1){VS>BgIyZL`uueoqKWl27k@*)-sj`U#Vaa~5;N z<(q=OX*h*l3YnM8uBXN22tl)23r55Fh+^X!VYS|UM6a*!aT&3%NrZN57pTy%2`3#Y z;B#vwF4B@tJNTDNPi<%Ty+5srKQl2TXC$G5XIlov2{^TTGRb_=-;fl&=)#>v|QuDn%lwZ$SxZA($o!Qxtta!{k8dWq`lYu=S^0JW(?k4jZEYb zahY-sr~U<3LhAh-6S~}Y+DryH^~XKnx9*|kpR&4|zK1S?f`V>tZo?Lt-Y6<|BD4Etsr$lINYvvJ{zcz&n;YjSZ^TRKGrDwDex8aDG~Afc>378 z{0}+%zS-n^*bt+L&ehz)FA50;q{z$Q_cby%S4VC7#ArRUpHY&h&SkrRksC<%)FiU4 z=Q~f3Mt<*KEp7YTvTr#aR9CTWoh6~Npo9oz(ECHy)4m>a7E#4|?}YxL@N-$cWTqjm z$3RxDYz%3?-SB&lL>V>Ml(Ar?n7%9hq=hC!xsoa@Y*#XHS4(T91@pRS&E&oIoGN!> z<1NS2VK3l$l~|0RT^$HpSKMy?MM0S!0w4>PZk<_R2pE_6q_o%iyx;Vagpbb!KlT9T zlKCmoOsME0I0V@_nbx7fU@NKNlOm1EXQ*!xt-exST>5$0wilv?Rx(XENJM^yE_(vkWW3f z`r>O-nA;fr-dF8x__*b)`IUY2RgOy+qh`g&PCWu$Zjg*+-@OASx;^Yb$6D;!FVe?k zX+AdWw4O>aL|4fg{<*A>$wu`;omPg4^LFE7op`ba?YRAOoTDLFZ^G=nT7AvrQh7g$yt_t*Nr>*-dqrsF*V|CgK^d0# zbFC2-_=ZPk?dI-#V2!jPE~f?rB-UOag}T!&O+eQq7m9zyWon8y7S&wYskb3mFz-r4 zq*nC%U6|f22dg-t&SQ!D)rRYM{m=`t^Is_T&azKj!lot%Phw5$hQcDdgKn$1V(_PS zM)0E-ebl+SO_@p!{|$Jk7ehLW@!SIZJe<2EH_ZmUB6@IWAI+0Z^TLc4$WO`dg@nL8 z>CaVoQAVj9`HD>^cgN$9v|s@0$YyjrG)- zn-sg5cVUA8*ib{gO^fYu3c!7EwzVvcgJ#$pPaDkY80QCnHEY}%TfFo(j((8z+&n9< z?SrcxkFU{CK~dQ3g2sbB^9|LU$A9bZxXcwQ`P+})eV+baFqT@pCQm!;`TAmVX}Q!* zSa1zq^P@K12?`1@q(e?WqQ!E_cLaIOhK@mBcG8TI+s?Mx(<#HA@0%*oVyh2iHdX(^0nWI%nSvgtT%iRIql*fQ%LvOZ6p*cW4;Nwk_p3-i(qe zTlEl@!bY4p0=p65h^;pL0{3m`h&4{@$z~Jn?U(7DjdND@SHP3qiFr1=t-i@?mL>yv za8shxT07T}RtSW_FqIgPVWcnmCt8_~Nx(cErAzfvJ4MxQ>~4r*;lzo0q{DW_Q2V*> z&y!(Pz%wFtlXKl^TV*BA?*WWYaOqSxtHa0p8>#F&s9z*1yzb3w=~DB~ntNPHKLSk8 zeE)e-#-r8hp0t+$UWCjh9)R8P96is=TQ7~W+Za3xSmnF2>>z919tX$2Wm zRKxnyZ}z&~G=FQXCj}-CoqSCvJh2uqIQE6)gQXgpkq|iuU9$%(Y3|6A1_xLSi6Ofh zv7;18vMG{nV4?u9!I`| z-ySn538AnP{y&bAeoEd3x0va4&PY-%o)R4Ct5^DdX18dXFXdh9L-DJoOP!U&M^6)$ z&lNQ`%k-buL+IGJ`e#k+dv4jt_s--`5hF1%G280PjrP%@q0cJ%@%}!+!fTv^$+D)f zWsoP5OPLL$o@T7~!6C|#p}k_{c`b9kbmv4_@KMc_p_NV3!m7lZlMB2H)XHe9#m3Ii zm}F5Rn4FA9#p^-u^mVZ*EKnjM35rt}XS2#Qx8RZKHl3$iwvv=rV816O?ULhX^%Xs? z;0HqwD7qD`v+=EqR<82};vV*x*L^({nnjB~C-<@O93zYFaa2w<2EzwZL53P|HM(Bs z|NO@gIc*OMN8t;o`bxQhq0%hzp{ZLJmub6gY|sZjP~kvx_!b!sEjH}->3S47KVDwj zIc5!FsWYm@^nzJYFu+){ zD7wY()X`ik?nCi64Hp1ksM~%2#LQgBS%*;D-*<8h0{|DI0|-PsL?Z_LI16()(mg;h zZ7Ce?n8+O@&}Mefb-^3=zm)zrTR8YYdXAAL!-&A%v_+A-9R;axRzMgG1#An{y)vMJ zxi*(R`I9j)*zJ!b+*5i#Ug*lm{OOau*Q$Z3^o{#d{gv`T@h{du8egWd%KW^RNdAb9 zmD8WeO$a~@{8PkzDFW!{@3FH=pJ{v9kW1$>zTVNZF18;YslNpVj7Z&mgQemhBYXGx zzne&XA#=a96u4r%Hs0XVP5m=d!$VNJX{?b89$NWlQ`w(UQr>LD76n1J*Nhspwa7<4 zZScA@8?J*WNr^tWwjz0A_9F@#!)@JSC?jrNd)V0oh1Fl}p&-I_F;=$=IxAOaIrIN< z^^M_?HC?+MPmGB@Nha3BwrzGanb@{%+qP{@Y}>Z2ljnKg@4L=9zq4(x*z*U-9l$){+n{1xf->{U12^VFLcB-KH@wF`jyF zY$q!m;3d)b3b}S)BAZAAS!iPI6iV+<$@S+@gsi*FuB^;0)>(up0MrO7x?(Q+iCObr z@v$q0_XhZXK@QIqZ)M70|GpP>hR4%bRV#tVhlftL2hut^I$x2rB}LSW-X2BO*UCTQr9TX5GgQ$ z7Q$U!PSQZ_vrh*9=NPvrwn(_9FPuG5xck%F7Wt`z$>RQf1|?_$=F!0-8HZy=Wu_;k z$;p=hYf;Ud@Nf$lC+b}WO`0)Ri|2*2>v3msCy0Tz(UT-^r?+8*9acblfhYkYoMy*F zLpgI3&%9SLr=&0rfR6WjHG04m3*U{|Vf#r!F=A9Xkdg2{$pZp}!&DLD)DrNJ&X6fh`Qg#Cegohxys$zt4gn z6Z0wwaMMlLO`nfqvO5z+k?Bwn6W*yk(^6w|t+oN(^$Bh_enI5oX#L-A2|C;#R^}$8 z1(yAdLt;O*KnsAuEzgmhX3dK;3uB>PX}%Q_N@;i-ZEYGm*@RtnO&bGes~0C|+1F)f z62JV*lLu7T~};q!^Ll$Ns(G5 zQlyb;P01SSD7fc)I6;&rGMzTjN-WGQ%umB2(cU!~Z7u`T^pgC^Kd}tO15?`5dNeGn z9;5|K^+^5I_lfodo*p7@{ek(LdwBr~fnInA~B%)iIO zL%UyA7yX+OrsJ>r541i0`eMDUxtR@6Q&aPWiEnLf{rVCa8Odt3ftn$3xV43Zf?@UU-Ef<+vuP^WysvGMlz zkco=qfLCoqnI|;rlMDM{ly+uyRkP1#WDD^M=v0%X_z?D{I_m(n`Io+psQ!W1)a4p0 z-A|P#OISfCOv!0NvSX6Z4XMUVCqd1uHaAt+R_o$k->YM?mJ7SE+yPsHas9L?NJ*{V zO-Gv2W}Iy9>!Dkj=%5gir|GM#tX5p>4#4u0s^o+tR+9@3-lQC=_0+o)akRbuif|3P z<-56AiV^0@KA&lRxY#=_C;aXRi!v1AB!3_k1Rpd6^29-;UoS4y_zMK+J6SS{uEUi= z{ATQrQ34Iu7xv+jVvplQIZU-2D3WnWz1hw{ z4&wvx_zfArFYj9S(3o7!e?Q+5guVXe6nUbT1KK?<$8t9J+@sf~THiKKJj~kYRl&Ac z)PN2PP^8;VyzoOA7a({^E004Mu7G`-6T?&J(_U zAOl-xUXuRJjVu6$-L^oQ%xP(>jYmy2>ZuZ#EMEtHCaF z7=5?`&@v>&(A+M=F0@{VJkBVmc)|g}Aa1OkTMFJc^rTP7yHjT^hXMN*gl-pQ2eJ9VSZLSfTFdT{SeMkl&Q;pkMxD{s z*2!VzcW{1rC3ACgJgnWFosAARR+}9mEiJ9DNXoQ^)y0`EK7BePq7KMbJ=N^aPA?cN zgwIiHqkCHzLo5nIanb^ya5s)K?k}%BrjiaGrSC@@qEDvPy{a3WserW%_c(UVTVeCD3ey8T=PCmFw&Ohh4p>9HC5kHe*2~%1R@-2 zFVEM#A+L1y)0F7}+ifvfEmtI><`G-J3Kgx!JNNgX?^5;D>B6h0+6XQ6sP9(UFc&Wm z^{mmw*qYtNSbC2O$clB2GzecU_@vM`+KD?~fP;w`T^!qlXp7{+bR?{Fsd??sD*zNi zxk<}NsE?UIzWCN(A9(m5NI$$;0uFG4y~#oRz3HG@QSn2smB1y@fy>!GrviT%zU}3P zC$un(D|}l+*@*);q;9Uwxx#I)Pv^l+rqXEZ_#yNI%!}3*GyQvamLCTbK+JpaH`jL` z$({f(;U*AJzIXuB)+B^C6cHCnUJ!PEBV^Ro_K+{JIxsp2M1jPa95l-Z4OV)|cKx*g z+$o@1x5p=77PNk=JO8O9fr|pog<^mPnWH4(Twq>zG;tj47@`| z-m~%H)iGeK|MbXDo9cOB-;W-nRJloF=K10xMS5`;wuBw51I;Hj`W$b}A? zZpuf=G?A&hWeZJlvn_0B&7W~`>Za5RTiU7UWmF5*o%wD@#+E4Pid1dvEuMAl`(@=4 z`IafGr<>IPIdU$$Z>%}_g4v(}YpH<^xt)}+`AUCN17Ix4zKjI#ZGxTNgZ`&akpTe# zwiZAM;l(+M_IR0}OO0C;ukQc!1RT_dPwv})o5@H>jC}swT<{Y_xL5rXnfc!a*{JhO zF7nuMHtk2O72;Td!>$bK7(bk8-la{N098Kemql7XoATuXx%tiJ#ag~@=yTPf-=|=$ zkn!IO$Wc(5+)ScuMj-+z-?avN-8FO5NxO8PdYbK~XEt{iPa%UwO>Ve>Dp$8R1zk-f zjlXILQ@MQp$G$H!=S6=?XBsUwZ-+q5Y`(PD8c~cNS`NLG3>nr~=GBf;!6Wux_X~Hi z4=C672>iEO|9q9pq&4YY5&~AA6sxbqUN8G_}?=- zm4iuT|M%C|P(FhHJ4XN8)T1i_Y|Zwdt0uvdtSmIt|-TLe_6L%ayn7S9ZYzFwHIvPc`=TM7ww$UyQmLLWIz zC9drFJc&*8^ZIj~gpDotJeNA1|P1 zFYnKw>s*goUGOlJnUhLr3g4LZ6u-Q7zGBP*Fc<*%VfP+Ic&qDCsSDmArL3pKDlbL@ zKFMh;st1cymC@Wl*B`v5$kboi+rYq_&SKhsMxq#EDFI6FhL8;^lI+M;Cr^ku?1<-Y zRrW&8gB>N{Q)*h)l91d3qBA`)J7Pq5%;bo;>3>8P8J@KbH5Y4z?5~SatWcJTn#P zS2>p2$ogMwo;oT4zlEB941+ZZkLRoS_8MYn2kmK1TS-8rlV+c&{G5gv0R03fjCab- zUZ~*cSBX9}`?j0C&|#=R#jjTvmc?&hWiHl8toD$QKaeko1aAo-_rs>h;OjoLogZPl zfpBlIjlAg}VxuS78}xu!tLCQhG_5G;?}(1Bw_Ts~h`fKMdckb+Y&#^vr7VvDRrxl_ z`)AT!Dm292VpiwGmY2m;w$jo4?|2r8OEz;sq$n|w>@n-QiB&qQwS{G8erZekA+csK zfoba%xG!!3JUQQ+Vjg}S5z5I56FI?aE1<+z!gk06xz=I1Cd*DiZ6#45sV*iaD4-P* zgBVPdh8*GN%WW^3^d`Sj1DeZnN|%3XT2-i=*3$O@zMGn(CJk1Xkg{Zr)MqqO&GVG5 zL?qt8BfV)W8Q3WYR0sv4Sx@ND*osC}5)VcRy=A|1wLIZ34-A=yN~}={CikD|LY*oh z{8-FK=LjLhmf`?ZWBab>55&GtlmO#orDZaK=^h60-9-hyP`xwt_>w`C6M^Od!w1=SM_eb}@!|rO zcA=H@)1ef4YbP>HlQjJK{-wedAp!)DYvd*}@ue4PwNOJqmN=k=+nU_BE6we!)ZebX zE}MCQfe=bn*27|Q%zNuRZhVtQYW{Nd_Ix&rVM@|~g39t5>O-|7`vpd$2%Vm%zO&a4 z8pkayQ#b7vylKAr*@Ea7&1L43;yzgBWR~93q+F(822=sP05%o ziibm@=rEi(<0wFJxln(rTkhG0rPH?D+J4?Q2#bme>%=XnD%vb^()sdAO7zXo=9f-Y z9USfg;op5q`Et9yN<(d}Q&=njHyK9yy+HvsK?9m@cpuY63G3};b&U;F74Z9>iHR;kLP8;=UmRW&jH%<{ z{oTt8EoM6tcmR^HNdFTA{GojE^bK^fKsSLD!q@x20v?qQ2`UsmGHDD-9dbt$i5p@R z&it|VK02Q-`5OS2Y$_2z=m|QlU+h3pIVBj3FHoT`kN5MEFg!p*HK8;A`$w4)Lw2L< zLC4DHVcFVsfYA?oh*fCc+pWgHC#i>xc{xB@+#naP1_vU!8ihsMrV0v>_-8J67tYGZ7-DDA0v%yn8SCc6X*D)L2zs4V7AB3k3NlQCqTz?TO8nVBQ*8$WkVdCrVcCL$IB7`h zN@O_&)~Tx|tQ?Wpah%Jx-XrDu)9w!5XR7YM+kdK1Zfa$b^~4CYqkARn%rS)sq?hk2 z6H-9HMWXsP8CMQQki!Rwz}WUbS*&;AN(o^C3su)2_Sr6QrF%!63q=5K@`G z!M}Z&+mp%raN+r*dI@bidbvmq1!TRQK(;Q;^? zzi~?fpoR46$U+EN`5FrpRu!gQ1PV$D#I5s@Oq8`XRK{NC9;s6&Mkm+3bgi_t@x9Ab z^)EBC7l$t20ktJ|o7b)t(EyOF;uzyPpMJ&|pD0`;e*0S1B?Je@op%Or!D9^;;A zdrP-3lNVc(1ePDO4i<)Ofp^SW9OWO)=NWk5vQFaqVm#^GzlN?wSCPR^Xw)wbGd(S- zly5mFAg(_8i|9Kt ztB6=Hp-&m6To0>Xc4gkTK>4R>-^Sw1&+R2J~vT;^`JRQ%#EZN;3B1fJR5O_l?EP<&3OY>siMM`RA`XaFvVQ1FH1rG@R&hJ1`a(fG-Zmo}w78AN2)GyX-KbK}dj5im`&t9? z&(HR3h(~rs=F~GE{4}EN;uUdvjf98s4|f|yS?@cB&oZj$5Zh;Vt3Q$>1qq*u*+Qy> zE$mT(Do(jAg)$cBWZzB@?=%asdxd^H8S$n0DBf@@gUb{Bwc<0FEJO8x*0(oCUPpSEMfRQ5bWwmW@&OKthCgj%FStAXou(q-cby zn#0{(bwdX>0DA1hUW>bOpLew>3%@Sk`8oK@d<%La>-0U1?An^CcKi-Oy;piHBq5(u zL{fs@wrq!L#*psu?2IW;eOe%YGU*P6du z$OW&Hb?}uVK>PL#`r~se2P`o$kxrWj;~RKts)lq1uo+m{tJa&2h;h+Lz|a&R^Hubx zw9L0@EEC!<2yfw}hN3W~?&7>n9i-3K5j_%46YZMer1M7?VZJe#O*jHS@32`jj0tw&0Tt&O- z%C4(E`bfYdB9eK=iVUa}5)H}0M_ChagtGk+#-sG@x;_uROY5v!km^N3V-Z0`p2qPR zKAm>hWrNwi=X(-6ujQ*c`5)JD&6L|0`gV7~9yjM~>H17~WgAo_G+4Fma;DZfl<20J z!BXvhChkP|lNwZ4C7@A6yTxRteJ~-JzDNb|(PICcVniQAe&ZinV$WC5%3QPgHrldL z;W1(9)MzD_oZ?=LG)8wwzuPHF%pG6?gUN;J6N6lS&u+ZHz(#a)rv&KENG_&MwAoyc z8O7@$CMJezZh$~S!!wv08l4xA)Jvtztx}XkwI*6^10$jcDI&P2|pk_x zOg}LAj=Jtgg0{AhQ^*9+#yfF#C{x67?-`rqyFti()fL)eg4EIxfh3PXaoK7f&Uo1) z0Be&!hV8U0v$zv!v)BIl9 zK5kNC{qtMM9 zQflZ^UJpIvkrn&sWOWJ`QT8xd)_b8w)eyGdX~!>KCqrb9**V~;XCWiZ^rx*fLl)jY zmfJ!uwiO#`Cfe)IhoEI-cvd$~p6ey6)J;>7NCqd)8@;?F@O7#*-LN%iYt_H$;Bql} ztnHgAY3Ee7*l38kt!C>~4MRr%=^E!?2{h0xnAJ0INUakf_f{2|Y=0LaH=LSfkUo(B zLuaC{4=dd2aXf{+h24SG`6CYVl3bO@Vd;vUZ$X%l56hE<+jQC_7$SSeGzZh_xB#!w z9yQ|#c6D^p2Z7i3Rf*F2p*t);{)NTC3L$H~#xeLkEh7v%Fd1P iu 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 literal 0 HcmV?d00001 diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index 9bc9c935a7..48af3eba98 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -670,19 +670,22 @@ and thus can run LAMMPS directly using the contents of the editor's text buffer as input. It can retrieve and display information from LAMMPS while it is running, display visualizations created with the :doc:`dump image command `, and is adapted specifically for editing -LAMMPS input files through text completion and reformatting, and linking -to the online LAMMPS documentation for known LAMMPS commands and styles. +LAMMPS input files through syntax highlighting, text completion, and +reformatting, and linking to the online LAMMPS documentation for known +LAMMPS commands and styles. -This is similar to what people traditionally would do to run LAMMPS: -using a regular text editor to edit the input and run the necessary -commands, possibly including the text editor, too, from a command line -terminal window. This similarity is a design goal. While making it easy -for beginners to start with LAMMPS, it is also the intention to simplify -the transition to workflows like most experienced LAMMPS users do. +This is similar to what people traditionally would do to run LAMMPS but +all rolled into a single application: that is, using a text editor, +plotting program, and a visualization program to edit the input, run +LAMMPS, process the output into graphs and visualizations from a command +line window. This similarity is a design goal. While making it easy for +beginners to start with LAMMPS, it is also the expectation that LAMMPS +GUI users will eventuall transition to workflows that most experienced +LAMMPS users employ. All features have been extensively exposed to keyboard shortcuts, so that there is also appeal for experienced LAMMPS users for prototyping -and testing simulations setups. +and testing simulation setups. Features ^^^^^^^^ @@ -693,6 +696,7 @@ are in the :doc:`Howto_lammps_gui` tutorial Howto page. Here are a few highlights of LAMMPS GUI - Text editor with syntax highlighting customized for LAMMPS +- Text editor features command completion for known commands and styles - Text editor will switch working directory to folder of file in buffer - Text editor will remember up to 5 recent files - Context specific LAMMPS command help via online documentation @@ -704,9 +708,10 @@ Here are a few highlights of LAMMPS GUI - Thermodynamic output is captured and displayed as line graph in a Chart Window - Indicator for currently executed command - Indicator for line that caused an error -- Visualization of current state in Image Viewer (via :doc:`dump image `) +- Visualization of current state in Image Viewer (via calling :doc:`write_dump image `) +- Capture of images created via :doc:`dump image ` in Slide show window - Many adjustable settings and preferences that are persistent -- Dialog to set variables from the LAMMPS command line +- Dialog to set variables, similar to the LAMMPS command line flag '-v' / '-var' Parallelization ^^^^^^^^^^^^^^^ @@ -721,15 +726,14 @@ Prerequisites and portability LAMMPS GUI is programmed in C++ based on the C++11 standard and using the `Qt GUI framework `_. Currently, Qt version 5.12 or later is required; Qt 5.15LTS is -recommended; support for Qt version 6.x is under active development and -thus far only tested with Qt 6.5LTS on Linux. Building LAMMPS with -CMake is required. +recommended; support for Qt version 6.x is available. Building LAMMPS +with CMake is required. The LAMMPS GUI has been successfully compiled and tested on: - Ubuntu Linux 20.04LTS x86_64 using GCC 9, Qt version 5.12 - Fedora Linux 40 x86\_64 using GCC 14 and Clang 17, Qt version 5.15LTS -- Fedora Linux 40 x86\_64 using GCC 14, Qt version 6.5LTS +- Fedora Linux 40 x86\_64 using GCC 14, Qt version 6.7 - Apple macOS 12 (Monterey) and macOS 13 (Ventura) with Xcode on arm64 and x86\_64, Qt version 5.15LTS - Windows 10 and 11 x86_64 with Visual Studio 2022 and Visual C++ 14.36, Qt version 5.15LTS - Windows 10 and 11 x86_64 with MinGW / GCC 10.0 cross-compiler on Fedora 38, Qt version 5.15LTS @@ -766,17 +770,17 @@ Otherwise, the location of the Qt library installation must be indicated by setting ``-D Qt5_DIR=/path/to/qt5/lib/cmake/Qt5``, which is a path to a folder inside the Qt installation that contains the file ``Qt5Config.cmake``. Similarly, for Qt6 the location of the Qt library -installation can be indicated by setting ``-D Qt6_DIR=/path/to/qt6/lib/cmake/Qt6``, -if necessary. When both, Qt5 and Qt6 are available, Qt6 will be preferred -unless ``-D LAMMPS_GUI_USE_QT5=yes`` is set. +installation can be indicated by setting ``-D +Qt6_DIR=/path/to/qt6/lib/cmake/Qt6``, if necessary. When both, Qt5 and +Qt6 are available, Qt6 will be preferred unless ``-D +LAMMPS_GUI_USE_QT5=yes`` is set. -It should be possible to build the LAMMPS GUI as a standalone -compilation (e.g. when LAMMPS has been compiled with traditional make). -Then the CMake configuration needs to be told where to find the LAMMPS -headers and the LAMMPS library, via ``-D -LAMMPS_SOURCE_DIR=/path/to/lammps/src``. CMake will try to guess a -build folder with the LAMMPS library from that path, but it can also be -set with ``-D LAMMPS_LIB_DIR=/path/to/lammps/lib``. +It is possible to build the LAMMPS GUI as a standalone compilation +(e.g. when LAMMPS has been compiled with traditional make). Then the +CMake configuration needs to be told where to find the LAMMPS headers +and the LAMMPS library, via ``-D LAMMPS_SOURCE_DIR=/path/to/lammps/src``. +CMake will try to guess a build folder with the LAMMPS library from that +path, but it can also be set with ``-D LAMMPS_LIB_DIR=/path/to/lammps/lib``. Rather than linking to the LAMMPS library during compilation, it is also possible to compile the GUI with a plugin loader that will load From 470b106d99e6a36548f5694182ec85ad05c85519 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 17 Jul 2024 15:11:17 -0400 Subject: [PATCH 245/385] small tweaks for more consistency --- doc/src/JPG/lammps-gui-slideshow.png | Bin 68537 -> 52659 bytes tools/lammps-gui/TODO.md | 1 + tools/lammps-gui/lammpsgui.cpp | 4 ++-- tools/lammps-gui/lammpsgui.ui | 4 ++-- tools/lammps-gui/preferences.cpp | 12 ++++++------ 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/src/JPG/lammps-gui-slideshow.png b/doc/src/JPG/lammps-gui-slideshow.png index 21ef80e2109a19582c17d7bedc463b54271884bf..00f95e9c5ad1d7a255ccb65b9f649c316dbd0560 100644 GIT binary patch literal 52659 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 literal 68537 zcmbTdbx>7Z{4cy|R6tTfxR?6vk<-}uDZk#E#r<36T%3;+PGlA@dz0HD%>|9r7g!B6Nd z0@1<$(CuHTy#j#R_$N1(7!MzN$s2fSyV-g9T6)?7270tUww_Q&H&oLB|}7v%(j$^b%s%DWzZ(#yJP$FeF=C z>ao_V(B8;4-ETuK(v6Kyx!ygd4a1j_J)PzbN(rotxL@!*(I1Gf$rW_A6CtK9(xMB) z7i+09hA-}(7AKbF-LIqpv}j$N=GQy(EzoD#qD$+Zu|7xmGT1qlQPI)NYMH;r$9XMf zhBF&>839%<_Dql2f8$(aGT8Y^xw1&EPKVm1LoDDjwIc zd1hK#1@I|xrQi;3d^gf2WqcL4*V5MD8aWqS%i``Buwd`0LS5uz|8=#qU?{DC>fSjk z;PFtNQw3ZPs{Ukcao(uOZ$9k0^CY%TLtOBsQ5tyXErx>1dSa0ub@s!VQui@?b;&U9 zpnZ*;g+Q8D{#k!LI=>sicu|Qg=k##_C#gE!R9h1t@%7l?=X+0{qzT+NIvzW}GZ$y{!99 z+A6tt@?7`%>X|vdBYf(4vyR^J%1bynQI`xXykC+wb7!R{IN;L6Q>>4bv>LglPRNg(1f31s4m26SZwC)T_y%|wDy?7qQo*VCT=O%XKzkT7ok5#ReqaDS5H*VC#_}Mo= zy}OFRQ0K8U3Lq_hBV@OPM)DWxX0Da{XXTqz{_c|XZRN$B!Nq}=aYGdFI5E(pmr-~r@n!S2WB;8{X0<1nUb(>Sx z*j-p$_D-$ctrS&BlXT%WcXgXHD{Xd-@seOwLPUwTnE=ARM& z342!ugU;AXZmGovUo_xn$K|FR^_OYA`k;O7^T+{hN$({1%0Jn2?|=oQt3M!3GAi7D zB8S`%Tsdkt4i>EELzOyZ7tnM9%7jEmaW>dy8)5_Na6B*RshtN6z%MNFOLqMPCa zdBGPI0**bf95;Ad4OglvG%Yll*ojEJ>e0_uR7!cY#jt~p=f3cp=Rm3CdEHy0O}q^S zs^NsF+v%D#;k_kuLC2LeIREAt%~P1?WyX0eA5#rtH zE{3-EKaMXdU>b322ruH>dsW8B=7s8G59<#l=BRNVJpuH9;+`L5^EkMn{&^XWuc)GY z%Vsi^w45Z5qSh}wP8|gpk-Er$eopZmT1hqBJm%y(t&()hsy4-i7LhOUiZ(4IqJKBD(%g$^4dXD{-7#7eCn;l(x8=Wak0?Z2E zU6;gn&M3SO#gPlQW8aVA5}>%RyK+x+n1UZ~ap%q$x)p6D&JHUO(ieAW>Y>_4 zM)JDzZ2Wk1$_IWryBk%&al4O&Vz*{iT)1;@F9QHpvvbB=fpup?hxh2oV}EmZ4|iKr zt6(C7D1e3OnsmG8=@Y4oSNSFH&i>|N<1PYA?hN}&NmTYE$@lrTOD(xww%ncmPG2_{ zv1q(<1AP!kjbQGQiz0(5>&UIB?@{)%JCao`b{i>@^Csd_CSGvF?PPbh=jaH;_x`-l zcPVK1B2qj2Q08Jta2ExLcsy^^;(DF<+=~_~kcuJs#CI{!O=+D2a9HTH({DnN2Jmhx zC~i{U_z(JuCW!mG@}End+p#>kUoCn87b5}gZoZf64Xs-Y_o~2&v9AgeF76<0rJmE8 zJ~>%w3)fRQy#0}d?aO=4FDhQJuAh3x<~ZxiUE;IT%X+Eyb^fi$%dnnlF}hzdl->nI zex#u7cfWuAz7ZAwGa|$zyIR;i{Nbi zh*4Oayc8$oH2`!y>J{|lMlPqA9h+ty$2D+2H+_CzE5#2%HtuBDNAaP(0kH6efqxzJ z03)_^+;;VlEtKVcV5QbJi1yn~14&Lr?zH{iDg8ae4=5WKCg&gT(L?U?rdRkWf!v^* zsn?78f4Zb@S_Yv}G`z!d0k;jJeNR~mgH7KZsKj%4OP$2D>`f}`|2-Jlm@~<(L+gaj z;hB*CxNaDgyem{UAP@%SXn9w4o?0~g(>xq7_2RU5Efuf zU9!e`4&lvP7dTq{ArpD+#vm#&Z|7Ds>#^OiAom1*IntILx;A8=an{*GeUb|NMQWs# zm(SXy1|Mb}8VpvS`!t$7q6B>E`%#wnS}@Gbh-sxo!U&@`8Y!?2b2~~)@&Xz9Md;%C z%-c?{%IL<0UT?-h;^ z{d%D5hCixXylAPPvP;qRoqu12^G+6o{*_u0^uS)SC>d|wLZsR1+r@@d$JwZ_c!0sF z!RCx`pdnr!D$sS>8!iRE-#dyLMG_|+1<*~Vgy@kPL85eA((WDJ4APw_PaPhXhN zo{qrWHODLOFSvo}i=Ty5SZALGa)oxwxrN=#>L4@P0MEUOZ@~ADpHlyRaW=m#87ScN z7Pan=&r6q*PLSkiJ8CXpb{?&Y>b?Bxbbj+(N<&5)W%-Bj4)%5RJ1fWAR7}7kx$}70 z6nMkCnw<%)p=e2S{M(y17(Kapvz-u2Y2l_{Od$fapHy7)9~~4#@@sVbiw52_?F_#} zYCF{{DM{{h0T0KN;GF7Uxk|`PGbIH z_OIYg{qkDzrhiLSt*L_b&2ga>XI1*ws9Dp+pS()TjA~uy-<+53A&**heJ|@bhTZlJ z;RQR%+lMY9()D9&NM=YN{Ps&BZjcJ_8O0`qw>)=Ov5A?^>HO@4mOhFNg^^zSR0{H0 zby-4m`K?pRlBj!4A%U~GHVsxtdpVo1I_@B_Qe%plzJuc^TOA=MusRQRc??$ua}oUCzm8JfStuFB$`H59MAHx0TAs1@wXf>UTQPsOn+-D zpmTYFryQbDUGt(^>~s=0z z=w9pBM6B^>;L4-AN>#}~b(}3e4fjX(tqC)0xVN7Y%rJn(<;lSx+L_SAf#6euk$U^h zMrWz}ys4l&skckQOh>D^IdkEj<22v(s|~S$_Y;|hOw~JVNWfyfb-(L0w9&ZPLK5qE zL;TRq=+d=!MHji5{1%h?x8Mcm{>#xZQ;n&+)%PR00zjAwOXMcYFq}A|mA}99X!E7- z;%&{+{N3L;sasNwJ@D}#OB{CxOJ|7}Ji`J+Y+Z6i)U1}ui%IYDE^1D0S>n&}PQ@AJTG2cbriYt1POdDo=e!-(=nU@m4X&TzIJlq7yNB44u3jR!TW;;m+t>56s6Hk& zmR!``n+PqBV`|5QlR?cdst`e5O>Xn#l*=hqkogh!j?K+rb7W6*oy*y&RLAZR&As$s z&Y1G0+uiXqck6eK20kA}rS}&D0hiH5H0fWZ-D1zrS>~P_5i$d+l>{9&6ra2P%nsn$ zchOV%tcnnuLI>2IE=t<{QKPh&dGEDQ>>b*!iFP1jI!Ak=$Ds?W8Tyr&_bUupa z0wZ91%dO<;9>A@*y9P+l$co$?Y`)R8!7I7mHYZVg8L zcH?e;H69vId2k88`y(6*pOrNn4?k@%1>9#Hk&Gc3{Kflb*Z!tIU6$%Dzv#jEOJXmh z;a-!~#Rntn(m%dqoMZ{X1($iT;OkBI*PM9x>(Zih%H1<*X3V+w^CczTT{*aJ9gaml zLSqK9$sLzQn@rb1-aYZuF%6B?{yXpY2sVPw+SuBJ{V#tl!Y9@P2!rqJ3nTgjCwCU? zyEJjEf}AUh{(L#PdNM#+KTHr6sF?TrlK`cI)08M+;<@;9G+7ZaI&a^8VNS4Q@TaTu z>WUaG)ZJ>A4T1nhT<>$+yB$CWVnVJPGJkz8>} zLq6Luusm^M&%u@q&<6dE(Z6ef8mEyvIzCE?q0-jv2zEZt4ZK#5uNRR2=RVnUinc-#J)7!Hj zhYMhEpdVGe*+7{R-P3gVesaiS@d53zJ>}8gt*w5IY|r!krn@QGj=VoocO#I{y;n5L zreyo?LS!wQ|FYDMypCKm>^NAFy7_azF{;0jH&gFEZrXiwxK%c3XD91ASa@_`PB2I_ zbnmKC?m3e;8PJav5hAc&RUCbTQ}OOYla}&dgkw9F$3PEGHi29NzqnY6|9w zmp-5p!ks^$k{PZF4fghBe zGE6*{?$Uc{W>&lLuGLwc8&`HX(3<7Tc5-^+$lyhp)_jKdoP2a!mXY z;u`gijGy7FsT3pDF4=!%{aM(lD-cWj`~Tk2$Jr;bHpW;Bm+^AG8l(L1u$nu+uBUk@ z6|X|!6-6l+zMLIw);-s|{=Z+|^$3gME=ifg&z#9D;-(I$=B|SM@26zrZ!W}}CRHi4 za4|y&3kVDNQgzm{V-Bov_{bv^S{PeIRe)(}VkciTd{n~C)QiX8XA*XP2qqOrWDZT{ zT_^f&xM|#+k#QY;^Pd|4mecO1C*Y#iU9~ow93p}H758iN5`lN`&I#ZmxSoi)V4uQ* za&^=`Li8&)y93>ZA#!!ce#VdL-41G?B848?%tp_-r|-|dN@^weFygi_8Ps~IRFt# z2$MW7w#O&H;`_xBH;QA7O=IO-(g+FY%Cs<||6rzVY2Pzy>5MwUC!~c2=n^IQVUbo# z_DvB0e9#Oy0igP+UBNdU766NOJ`RdR2Uc)!jumj5Ynq1&i9IgNieGi)TuHoJxJc%^ zWQk`snu7oB-8plN*4v1YA_77bfi4HPq%>+rF|Vbb#mP{Qr*udX07E^GruFiz##f}l z(&y$g)`0xN=?-h>#@p>&aaW@F;D5^#0SC=hb`wC3r!lcrU22-PiWs`oN;HPY_apEsQQ>mZ>=y59^h^)&R|eL68d0B}*B zA;cp(_Sp*lbs{6gN2Y;8r^m>LTImm6h3x?QoawJ+n|vNXy&Myc|KEwL1$aI(x!#6SFaC|{ zjufAL&`N$T6A*3_a-OqL<>{RgSWjJ8Ia>j+b|Cb4<```ewW)YBi3CdV{0qw^x} z;FA{nLFby6_rHxt??>TObUiI-qu(-}Y!ih)jCoG}@MyZ-^|GqDhYB|{* z@XP3MHEgB7Zic~*Z{GTcdjOup`qjB$;YF4(SV?+bV~z~V8V}lpV0F4@V&IF->UVUz ziGJ~=|9ew+x;{EZS|MluZFmLfHRbblaZJbgH|2NBglvSEC(d4fKWWJDK5rLMU?P89 zC4@ywdm3k*DGt5i9~~7C|NXMF-SPAquHo4^fJy5)nW6veI&LwSfB7wz`5wce0mYcI zy77Gd!AzQvuaWPq@6ZR_ZHbUYw_;nAhMh`h=cTJ#WX++<)Gd$H>w~@g-JLS~i83_x zFd9$ZA=KICy6VO2-!x|P)2_kyK}p}mO>rWGR=@9}vZI82QFuHMZsi7B)m#!6H^5Vh*XhfjoFLlehatyX{TaJ#LwRdUWP&UCnR*x(6#zSXU>*I+wU z3~d4N+7qC~x)``5UEe!6ynU&CpX|DpwXyMN81=0bbztK0M0sTOKJ;PqnIv0=Qr<`8#c{!4KF+>0-LWxpE6ABQ}54 z;Zbjd#F1=L0zsaeQ}TiGz3DWP-@JIP@&1;rota8!ydb}<=n)JZH+ZXr#1$@WXwXTV z4wPzG3QWTQdHIV!9p@G&jTnUED+?O_q56hbabYdg%W;LdFuMu1QHjeo>vjdema-Hb zAiT|0d4cglSnG}bkn4F1QS`gO!}D^J{W1^IvtLb>^Oc+}@6Qh^&Vp30udr}haDD}m zBwH^K`tM$R8WO*L@v=hbcf)>7oqq`bXW2Lpq-(2V{t3_NjSNYr?{#1NOR4Dohz2STmIuS10@4Dg?ugSm8m};;RQRQi zDgTTcl#O;>XGF?&S>nZj9*!vdu*d^H#JD=^B!to>;5?R8%oqjRBPH(T;SG17lgrsM z5%Y*6DL{e!&~?E_L{s;czq8!;HTfw&fIpZdEgYB=%WA5&Kh}u zOSRC&hM$*gEV{k|<;u&G>P;+^{1jyJ^o~FK-Tp?+{8d9%om7cdS#-^`ReG)5s9Vp+ zdv5Yugqm>m-BG;u)7vIJz5bfkiPmlAsdIP@>9b?#GYq2sCQj?TTz_s8FZ1^6sb90- zT-T*^PPaOSWxsur8Kqld>Hvg7@Rrfj&;A&+WXXh~p`=$ybAF`8qv&${)Qj|gTtx|3 z#2t4VV#1k#>}nhd%y3kJH`7_mIRxtDqqxdQnXg+8d6 T3`2{0qy}!fc~S%w@}$ ze;u2b*_ zIr{o)=${CqzBLz~*lnB5Rbx3EWL(0ee{H=q!gx;^pZw!kK>I$D`{wPO%a&6MKYVY{ z<{x?5)rSHJ0e1ZlV@mQE1yo|!_G{mrz|ri z1NfWJdqFdXIuh7d95r z1^hq%Ebi@0!5dZq!gXnEx_<sJ3CGgwJaGNt#*e#UK9$r@Gcm<=_Z z5{AtFnwa35{V0QtD}}?e)hl{`bK=%<`g>=`scCNCOU%|#NUg51(Pw|Q;e5f@Twj06 zffS!kAe*P_3(;D2+d=EutTTyxf~{d9BS0Ibn5d(v`Ny**TYZxuUIG?yelX6(EaNb3 zL4zYk(0LT=X5uqr+Xx|&5l~CA&A|UIY9GVf|4!1}+xs*Peq(C_0sS{393F>WT^$`0 zzds+tEm@=Jl?bhWHbQ`JkSwhsveoR0@|`2U>gJWGaW0OBTZg=2I5-9(L?|-Is0jTuNM)kd z06+ep?@SNIE9hxzCM>-EWi5BgWE@!wnS)iTGA9k%h-~70vaXMg0qk_=OQ z3$9J0o7ORtzkkR1C_Q}t6I&sXO;0$k z8~oOX7T>+aGt}1y^INOz*KC9H^XJcBw=HAmTZf}y=7`wmzTNm$rVWlTx9=mC zlUW?ueoH^YwAudc+ux`c)nFVP`$?3SvqxDO{(g^!^}Es#df0K^*whq%MnW4FhXRiN z;b)ex+s>~tQBhGVJ~(nanNi86%O<7>xqWkU^P;+023$BD1*E|Ern#QphP%iC{QeGp zcUn`^emvx0jwR#p?O`P?&-P}LSTyj^QNjECai88j6{EzHiLfL)@{`C=#SHEK_=MDR zM81=cS1KHz9sy%iGOKASC|E(}-FaDCuf|b{D_lE)CGrCbW~>N&Ny>Fz1Pst4zndU9 zHcw{pOe3dKB3ZM9bwAEgA)}HNUa=o|F5_p!!l?LR`^LtG0f*4+6nNA@EZZkUVZJw# zNKg$bLTOerwR;-%=8sRC{Of2&r9bWl0?A5=UsJpaC!x1v!GUcn(AXe?N>vxlGYqXb3#aKtXw9EYG0w(+dUY zPlwF4RzDA?qv+;9OnAS1E+IEdwzca;ARg5v%O;2;>r&}xq^33;g6P-L6RW5&4GZDu zY3kHHUJR&>eXbpIr1o4JH@5i=vkVIbCRjBjsN)qS?K15ist#YI+y||4)+or_wwG9r zdbC(n1Q$R%k*ukVB5l*JTBJ2-qg7d~%Jx#A)x`bPMYK7`$nc~LovtRMJY5v3u5RaO zaIU8Eobl;~f8ciEK4M8Ddl~V1D+%YJ)_}3x2+=fDDnTCkQ37&I{Q_#HQ%Qr2nGLYF)S(wS7E7zgQ;GRvLH*LtcTMqZ}e92^|%Kj`%6Q)utLq(Pq+sT=zIfEBP3hTuvw4JI;%YFXgeWbpTk z+9&qvq^+FRd00~|-5CApiEprsdF8P75Y8)LgU%Fo%N&t6^@_!N|v zr!Ua2#9ERK+IUV?o0jR6mz1zj;zd77xB8LsqXDd7nVFf5t_$ozljG~jw1kH)2*wE} zYYmp(LRNL9L=@@7(gK69tuRF(8{c&<8J}D_l`%t$S)8d!g`HhTDj@KnM`{2)6FZg| z#1wvk9<(_-SeP3d`@*U$6dfbWkR94flzk1fCyVLmVpx<9F)5|l zg6A<9hsaWFv$V4C!Oqst`a@1H0>MT?Qo5PDA8-qyGz$L@c7<1iY6Do_X~cahx5N`{ zGqf_*OXL~S)49u7hmzT})unF#O;+ef2VJ`mWjGKK(G4_0`VIIp_O`c=u5Z;rb+|GH ze`0>#WzI)MC3>2vt(cDv9s38NrfvbtPR__o;@X-CrUgI@h}dTv1I!_)wEWB-TqBAi zEQvBYDIx-ni@!;UVjvJQ;kCdmr;>`fP`q&<7~th{{3ON>OGpeGtdx;`)xYh?*K zB5DtI#|%}4up}3l4e+BseGh-lfa6)Lg0Zo2Uk#Zx*d>yp-q~iKkeBo`$}pm4hpw

9+AGmTJ%w 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%0ALkM|m^b>=3 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, 400); varwindow = new QLabel(QString()); - varwindow->setWindowTitle(QString("LAMMPS-GUI - Current Variables - " + current_file)); + varwindow->setWindowTitle(QString("LAMMPS-GUI - Current Variables")); varwindow->setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png")); varwindow->setMinimumSize(100, 50); varwindow->setText("(none)"); @@ -1264,7 +1264,7 @@ void LammpsGui::help() "LAMMPS specific syntax highlighting. When typing Ctrl-Enter " "or clicking on 'Run LAMMMPS' in the 'Run' menu, LAMMPS will be run " "with the contents of editor buffer as input. The output of the LAMMPS " - "run is captured and displayed in a log window. The thermodynamic data " + "run is captured and displayed in an Output window. The thermodynamic data " "is displayed in a chart window. Both are updated regularly during the " "run, as is a progress bar in the main window. The running simulation " "can be stopped cleanly by typing Ctrl-/ or by clicking on " diff --git a/tools/lammps-gui/lammpsgui.ui b/tools/lammps-gui/lammpsgui.ui index bb9af2e17e..70139bc2eb 100644 --- a/tools/lammps-gui/lammpsgui.ui +++ b/tools/lammps-gui/lammpsgui.ui @@ -336,7 +336,7 @@ - &Log Window + &Output Window Ctrl+Shift+L @@ -347,7 +347,7 @@ - &Chart Window + &Charts Window Ctrl+Shift+C diff --git a/tools/lammps-gui/preferences.cpp b/tools/lammps-gui/preferences.cpp index 426f2306ea..1bd3bc0d52 100644 --- a/tools/lammps-gui/preferences.cpp +++ b/tools/lammps-gui/preferences.cpp @@ -211,23 +211,23 @@ GeneralTab::GeneralTab(QSettings *_settings, LammpsWrapper *_lammps, QWidget *pa auto *cite = new QCheckBox("Include citation details"); cite->setObjectName("cite"); cite->setCheckState(settings->value("cite", false).toBool() ? Qt::Checked : Qt::Unchecked); - auto *logv = new QCheckBox("Show log window by default"); + auto *logv = new QCheckBox("Show Output window by default"); logv->setObjectName("viewlog"); logv->setCheckState(settings->value("viewlog", true).toBool() ? Qt::Checked : Qt::Unchecked); - auto *pltv = new QCheckBox("Show chart window by default"); + auto *pltv = new QCheckBox("Show Charts window by default"); pltv->setObjectName("viewchart"); pltv->setCheckState(settings->value("viewchart", true).toBool() ? Qt::Checked : Qt::Unchecked); - auto *sldv = new QCheckBox("Show slide show window by default"); + auto *sldv = new QCheckBox("Show Slide Show window by default"); sldv->setObjectName("viewslide"); sldv->setCheckState(settings->value("viewslide", true).toBool() ? Qt::Checked : Qt::Unchecked); - auto *logr = new QCheckBox("Replace log window on new run"); + auto *logr = new QCheckBox("Replace Output window on new run"); logr->setObjectName("logreplace"); logr->setCheckState(settings->value("logreplace", true).toBool() ? Qt::Checked : Qt::Unchecked); - auto *imgr = new QCheckBox("Replace image window on new render"); + auto *imgr = new QCheckBox("Replace Image window on new render"); imgr->setObjectName("imagereplace"); imgr->setCheckState(settings->value("imagereplace", true).toBool() ? Qt::Checked : Qt::Unchecked); - auto *pltr = new QCheckBox("Replace chart window on new run"); + auto *pltr = new QCheckBox("Replace Charts window on new run"); pltr->setObjectName("chartreplace"); pltr->setCheckState(settings->value("chartreplace", true).toBool() ? Qt::Checked : Qt::Unchecked); From f877a6f4ce834522a1e4463c8939b624a7e89d5b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 17 Jul 2024 19:13:10 -0400 Subject: [PATCH 246/385] more consistency changes --- doc/src/JPG/lammps-gui-image.png | Bin 125560 -> 146813 bytes tools/lammps-gui/imageviewer.cpp | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/JPG/lammps-gui-image.png b/doc/src/JPG/lammps-gui-image.png index b383e914a523f814dbc93e22293901601e590361..fb3fe609e0324a1c49189e2f07b249932956b12c 100644 GIT binary patch literal 146813 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

  • n1e-&lAjR78b_ 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%0A#;A6J+1Yyvn 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
  • 7aCitYL6LUyu)SCFg)N=!+N!J(*wkO2{y#-a^jEyva|sw>e;JqO%S&lgG0! zuSV(7rB~r8K~KYl2B(uz$Q7 z!SpxEyE(X&-Sm41Zz`jdKB^_@?nI&dn|A#p-RKIB!6rj-WAuQQJUD95)P16)u$~+8 zP);A%PU9;SaOl2K@n-cY0`4CzqJn{r9hyCxe7NtBT8y8zvz;Y-9$^x$z>#wFy~lx< zAfoHD=P*DjUdRvWnaP`7NI%%hBdb5;uiZG0nUAoDzBm5 z)sIo`oKNp?-aIL+FxF`@jp7gKDe7BfUl#U%rIcnpvUynr>|B$bxFE zFSEL^{;un|xNhYiqGZTc*QZU~ir!17(VCpNmzg!1lh55|hW|Ee$YK{gIZ4b&_Y{72 z9VEy$i*EjS-6Rn@W2jz>eo(Jtfb5{q;9W`rA%t9?CBu;fBH+iE*FMlvbQ&l{lG??@ zeq85ye?QV7#a=MHg9E;vYSMSWnhT zaakj2pamwT1THNEjRw4CyQ~%XLm+YcaP`?@Lj`EQR}y4S0avBHLwNqek^^&?hLa!e z&281LhDR6j&K~tsjPy=@xkJ9&r9+P#lz$xguwm-EFrzeaZ;dT zrIP#?J≦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 VmC5E!*CJ!4{|3vun{rFa8vud1-ar5V literal 0 HcmV?d00001 diff --git a/examples/charmmfsw/in.charmmfsw b/examples/charmmfsw/in.charmmfsw new file mode 100644 index 0000000000..2483596556 --- /dev/null +++ b/examples/charmmfsw/in.charmmfsw @@ -0,0 +1,47 @@ +#echo screen +#variable dcdfreq index 5000 +#variable outputname index step5_production +#variable inputname index step4.1_equilibration + +# charmmfsw example generated by https://charmm-gui.org/ +# from PDB structure 1HVN (https://www.rcsb.org/structure/1HVN) +# +# Dependencies: packages MOLECULE / KSPACE / RIGID +# To test with KOKKOS, use -sf kk + +units real +boundary p p p + +newton off +pair_style lj/charmmfsw/coul/long 10 12 +pair_modify mix arithmetic +kspace_style pppm 1e-6 + +atom_style full +bond_style harmonic +angle_style charmm +dihedral_style charmmfsw +special_bonds charmm +improper_style harmonic +timestep 2 + +fix cmap all cmap charmmff.cmap +fix_modify cmap energy yes +read_data data.charmmfsw.gz fix cmap crossterm CMAP + +#variable laststep file ${inputname}.dump +#next laststep +#read_dump ${inputname}.dump ${laststep} x y z vx vy vz ix iy iz box yes replace yes format native + +neighbor 2 bin +neigh_modify delay 5 every 1 + +#include restraints/constraint_angletype +fix 1 all shake 1e-6 500 0 m 1.008 a 142 +fix 2 all npt temp 303.15 303.15 100.0 iso 0.9869233 0.9869233 1000 couple xyz mtk no pchain 0 + +thermo 100 +thermo_style custom step time spcpu cpuremain etotal pe ke temp press vol + +run 1000 + From 06e8f8eab2934bde107a56eedfd18021a7e81aa3 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 15:56:24 -0400 Subject: [PATCH 195/385] cleanup --- examples/charmmfsw/in.charmmfsw | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/examples/charmmfsw/in.charmmfsw b/examples/charmmfsw/in.charmmfsw index 2483596556..f1e3f05121 100644 --- a/examples/charmmfsw/in.charmmfsw +++ b/examples/charmmfsw/in.charmmfsw @@ -1,13 +1,8 @@ -#echo screen -#variable dcdfreq index 5000 -#variable outputname index step5_production -#variable inputname index step4.1_equilibration - # charmmfsw example generated by https://charmm-gui.org/ # from PDB structure 1HVN (https://www.rcsb.org/structure/1HVN) # # Dependencies: packages MOLECULE / KSPACE / RIGID -# To test with KOKKOS, use -sf kk +# To test with KOKKOS: lmp -k on g 1 -sf kk -pk kokkos neigh half -in in.charmmfsw units real boundary p p p @@ -29,14 +24,9 @@ fix cmap all cmap charmmff.cmap fix_modify cmap energy yes read_data data.charmmfsw.gz fix cmap crossterm CMAP -#variable laststep file ${inputname}.dump -#next laststep -#read_dump ${inputname}.dump ${laststep} x y z vx vy vz ix iy iz box yes replace yes format native - neighbor 2 bin neigh_modify delay 5 every 1 -#include restraints/constraint_angletype fix 1 all shake 1e-6 500 0 m 1.008 a 142 fix 2 all npt temp 303.15 303.15 100.0 iso 0.9869233 0.9869233 1000 couple xyz mtk no pchain 0 From c77d2d952d9f6acffde8b3fc9b39ac7fc60ab591 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 16:55:39 -0400 Subject: [PATCH 196/385] Update pair_lj_charmmfsw_coul_long_kokkos.cpp --- src/KOKKOS/pair_lj_charmmfsw_coul_long_kokkos.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/KOKKOS/pair_lj_charmmfsw_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_charmmfsw_coul_long_kokkos.cpp index c07a089a35..23247bf20d 100644 --- a/src/KOKKOS/pair_lj_charmmfsw_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_charmmfsw_coul_long_kokkos.cpp @@ -463,7 +463,6 @@ double PairLJCharmmfswCoulLongKokkos::init_one(int i, int j) k_params.h_view(i,j).lj2 = lj2[i][j]; k_params.h_view(i,j).lj3 = lj3[i][j]; k_params.h_view(i,j).lj4 = lj4[i][j]; - //k_params.h_view(i,j).offset = offset[i][j]; k_params.h_view(i,j).cut_ljsq = cut_ljsq; k_params.h_view(i,j).cut_coulsq = cut_coulsq; From b1a4f08dd24da6b3c7e988612e7fd2a95d7d92a7 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 16:56:00 -0400 Subject: [PATCH 197/385] Update in.charmmfsw --- examples/charmmfsw/in.charmmfsw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/charmmfsw/in.charmmfsw b/examples/charmmfsw/in.charmmfsw index f1e3f05121..fae489e8d7 100644 --- a/examples/charmmfsw/in.charmmfsw +++ b/examples/charmmfsw/in.charmmfsw @@ -31,7 +31,7 @@ fix 1 all shake 1e-6 500 0 m 1.008 a 142 fix 2 all npt temp 303.15 303.15 100.0 iso 0.9869233 0.9869233 1000 couple xyz mtk no pchain 0 thermo 100 -thermo_style custom step time spcpu cpuremain etotal pe ke temp press vol +thermo_style custom step time spcpu cpuremain etotal evdwl ecoul elong edihed pe ke temp press vol run 1000 From aaf25602e3ffc46477c40853966c4f26b522d4c1 Mon Sep 17 00:00:00 2001 From: alphataubio Date: Sun, 7 Jul 2024 17:11:18 -0400 Subject: [PATCH 198/385] add Q_MASK to datamask_read --- src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp index d833914e4e..a205218a82 100644 --- a/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_spica_coul_long_kokkos.cpp @@ -50,7 +50,7 @@ PairLJSPICACoulLongKokkos::PairLJSPICACoulLongKokkos(LAMMPS *lmp) : kokkosable = 1; atomKK = (AtomKokkos *) atom; execution_space = ExecutionSpaceFromDevice::space; - datamask_read = X_MASK | F_MASK | TYPE_MASK | ENERGY_MASK | VIRIAL_MASK; + datamask_read = X_MASK | F_MASK | TYPE_MASK | Q_MASK | ENERGY_MASK | VIRIAL_MASK; datamask_modify = F_MASK | ENERGY_MASK | VIRIAL_MASK; } From 4bc97dc812375f5b157b6514f4362f8fac4cf02e Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Mon, 8 Jul 2024 05:01:23 -0600 Subject: [PATCH 199/385] fix topo labels --- src/KOKKOS/dihedral_hybrid_kokkos.cpp | 96 ++++++++++----------- src/KOKKOS/dihedral_hybrid_kokkos.h | 2 +- src/KOKKOS/improper_hybrid_kokkos.cpp | 117 +++++++++++++------------- src/KOKKOS/improper_hybrid_kokkos.h | 22 ++--- 4 files changed, 121 insertions(+), 116 deletions(-) diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.cpp b/src/KOKKOS/dihedral_hybrid_kokkos.cpp index 4adbb7f18b..d0b9f7d646 100644 --- a/src/KOKKOS/dihedral_hybrid_kokkos.cpp +++ b/src/KOKKOS/dihedral_hybrid_kokkos.cpp @@ -11,7 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -#include "bond_hybrid_kokkos.h" +#include "dihedral_hybrid_kokkos.h" #include "atom_kokkos.h" #include "atom_masks.h" @@ -54,69 +54,71 @@ DihedralHybridKokkos::~DihedralHybridKokkos() void DihedralHybridKokkos::compute(int eflag, int vflag) { - // save ptrs to original bondlist + // save ptrs to original dihedrallist - int nbondlist_orig = neighbor->nbondlist; - neighborKK->k_bondlist.sync_device(); - auto k_bondlist_orig = neighborKK->k_bondlist; - auto d_bondlist_orig = k_bondlist_orig.d_view; - auto d_nbondlist = k_nbondlist.d_view; - auto h_nbondlist = k_nbondlist.h_view; + int ndihedrallist_orig = neighbor->ndihedrallist; + neighborKK->k_dihedrallist.sync_device(); + auto k_dihedrallist_orig = neighborKK->k_dihedrallist; + auto d_dihedrallist_orig = k_dihedrallist_orig.d_view; + auto d_ndihedrallist = k_ndihedrallist.d_view; + auto h_ndihedrallist = k_ndihedrallist.h_view; - // if this is re-neighbor step, create sub-style bondlists - // nbondlist[] = length of each sub-style list - // realloc sub-style bondlist if necessary - // load sub-style bondlist with 3 values from original bondlist + // if this is re-neighbor step, create sub-style dihedrallists + // ndihedrallist[] = length of each sub-style list + // realloc sub-style dihedrallist if necessary + // load sub-style dihedrallist with 3 values from original dihedrallist if (neighbor->ago == 0) { - Kokkos::deep_copy(d_nbondlist,0); + Kokkos::deep_copy(d_ndihedrallist,0); k_map.sync_device(); auto d_map = k_map.d_view; - Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_bondlist_orig(i,2)]; - if (m >= 0) Kokkos::atomic_increment(&d_nbondlist[m]); + Kokkos::parallel_for(ndihedrallist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_dihedrallist_orig(i,2)]; + if (m >= 0) Kokkos::atomic_increment(&d_ndihedrallist[m]); }); - k_nbondlist.modify_device(); - k_nbondlist.sync_host(); + k_ndihedrallist.modify_device(); + k_ndihedrallist.sync_host(); - maxbond_all = 0; + maxdihedral_all = 0; for (int m = 0; m < nstyles; m++) - if (h_nbondlist[m] > maxbond_all) - maxbond_all = h_nbondlist[m] + EXTRA; + if (h_ndihedrallist[m] > maxdihedral_all) + maxdihedral_all = h_ndihedrallist[m] + EXTRA; - if (k_bondlist.d_view.extent(1) < maxbond_all) - MemKK::realloc_kokkos(k_bondlist, "bond_hybrid:bondlist", nstyles, maxbond_all, 3); - auto d_bondlist = k_bondlist.d_view; + if (k_dihedrallist.d_view.extent(1) < maxdihedral_all) + MemKK::realloc_kokkos(k_dihedrallist, "dihedral_hybrid:dihedrallist", nstyles, maxdihedral_all, 3); + auto d_dihedrallist = k_dihedrallist.d_view; - Kokkos::deep_copy(d_nbondlist,0); + Kokkos::deep_copy(d_ndihedrallist,0); - Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_bondlist_orig(i,2)]; + Kokkos::parallel_for(ndihedrallist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_dihedrallist_orig(i,2)]; if (m < 0) return; - const int n = Kokkos::atomic_fetch_add(&d_nbondlist[m],1); - d_bondlist(m,n,0) = d_bondlist_orig(i,0); - d_bondlist(m,n,1) = d_bondlist_orig(i,1); - d_bondlist(m,n,2) = d_bondlist_orig(i,2); + const int n = Kokkos::atomic_fetch_add(&d_ndihedrallist[m],1); + d_dihedrallist(m,n,0) = d_dihedrallist_orig(i,0); + d_dihedrallist(m,n,1) = d_dihedrallist_orig(i,1); + d_dihedrallist(m,n,2) = d_dihedrallist_orig(i,2); + d_dihedrallist(m,n,3) = d_dihedrallist_orig(i,3); + d_dihedrallist(m,n,4) = d_dihedrallist_orig(i,4); }); } // call each sub-style's compute function - // set neighbor->bondlist to sub-style bondlist before call + // set neighbor->dihedrallist to sub-style dihedrallist before call // accumulate sub-style global/peratom energy/virial in hybrid ev_init(eflag, vflag); - k_nbondlist.modify_device(); - k_nbondlist.sync_host(); + k_ndihedrallist.modify_device(); + k_ndihedrallist.sync_host(); for (int m = 0; m < nstyles; m++) { - neighbor->nbondlist = h_nbondlist[m]; - auto k_bondlist_m = Kokkos::subview(k_bondlist,m,Kokkos::ALL,Kokkos::ALL); - k_bondlist_m.modify_device(); - neighborKK->k_bondlist = k_bondlist_m; + neighbor->ndihedrallist = h_ndihedrallist[m]; + auto k_dihedrallist_m = Kokkos::subview(k_dihedrallist,m,Kokkos::ALL,Kokkos::ALL); + k_dihedrallist_m.modify_device(); + neighborKK->k_dihedrallist = k_dihedrallist_m; auto style = styles[m]; atomKK->sync(style->execution_space,style->datamask_read); @@ -142,10 +144,10 @@ void DihedralHybridKokkos::compute(int eflag, int vflag) } } - // restore ptrs to original bondlist + // restore ptrs to original dihedrallist - neighbor->nbondlist = nbondlist_orig; - neighborKK->k_bondlist = k_bondlist_orig; + neighbor->ndihedrallist = ndihedrallist_orig; + neighborKK->k_dihedrallist = k_dihedrallist_orig; } /* ---------------------------------------------------------------------- */ @@ -153,13 +155,13 @@ void DihedralHybridKokkos::compute(int eflag, int vflag) void DihedralHybridKokkos::allocate() { allocated = 1; - int n = atom->nbondtypes; + int n = atom->ndihedraltypes; - memoryKK->create_kokkos(k_map, map, n + 1, "bond:map"); - memory->create(setflag, n + 1, "bond:setflag"); + memoryKK->create_kokkos(k_map, map, n + 1, "dihedral:map"); + memory->create(setflag, n + 1, "dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; - k_nbondlist = DAT::tdual_int_1d("bond:nbondlist", nstyles); + k_ndihedrallist = DAT::tdual_int_1d("dihedral:ndihedrallist", nstyles); } /* ---------------------------------------------------------------------- */ @@ -193,7 +195,7 @@ void DihedralHybridKokkos::init_style() for (int m = 0; m < nstyles; m++) { if (!styles[m]->kokkosable) - error->all(FLERR,"Must use only Kokkos-enabled bond styles with bond_style hybrid/kk"); + error->all(FLERR,"Must use only Kokkos-enabled dihedral styles with dihedral_style hybrid/kk"); if (styles[m]->execution_space == Host) lmp->kokkos->allow_overlap = 0; @@ -208,7 +210,7 @@ double DihedralHybridKokkos::memory_usage() { double bytes = (double) maxeatom * sizeof(double); bytes += (double) maxvatom * 6 * sizeof(double); - for (int m = 0; m < nstyles; m++) bytes += (double) maxbond_all * 3 * sizeof(int); + for (int m = 0; m < nstyles; m++) bytes += (double) maxdihedral_all * 3 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.h b/src/KOKKOS/dihedral_hybrid_kokkos.h index 8b090d46c2..29a3d29689 100644 --- a/src/KOKKOS/dihedral_hybrid_kokkos.h +++ b/src/KOKKOS/dihedral_hybrid_kokkos.h @@ -23,7 +23,7 @@ DihedralStyle(hybrid/kk/host,DihedralHybridKokkos); #ifndef LMP_BOND_HYBRID_KOKKOS_H #define LMP_BOND_HYBRID_KOKKOS_H -#include "bond_hybrid.h" +#include "dihedral_hybrid.h" #include "kokkos_type.h" namespace LAMMPS_NS { diff --git a/src/KOKKOS/improper_hybrid_kokkos.cpp b/src/KOKKOS/improper_hybrid_kokkos.cpp index d63ebccac6..4d571b3eae 100644 --- a/src/KOKKOS/improper_hybrid_kokkos.cpp +++ b/src/KOKKOS/improper_hybrid_kokkos.cpp @@ -11,7 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -#include "bond_hybrid_kokkos.h" +#include "improper_hybrid_kokkos.h" #include "atom_kokkos.h" #include "atom_masks.h" @@ -30,7 +30,7 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ -BondHybridKokkos::BondHybridKokkos(LAMMPS *lmp) : BondHybrid(lmp) +ImproperHybridKokkos::ImproperHybridKokkos(LAMMPS *lmp) : ImproperHybrid(lmp) { kokkosable = 1; @@ -45,78 +45,81 @@ BondHybridKokkos::BondHybridKokkos(LAMMPS *lmp) : BondHybrid(lmp) /* ---------------------------------------------------------------------- */ -BondHybridKokkos::~BondHybridKokkos() +ImproperHybridKokkos::~ImproperHybridKokkos() { deallocate(); } /* ---------------------------------------------------------------------- */ -void BondHybridKokkos::compute(int eflag, int vflag) +void ImproperHybridKokkos::compute(int eflag, int vflag) { - // save ptrs to original bondlist - int nbondlist_orig = neighbor->nbondlist; - neighborKK->k_bondlist.sync_device(); - auto k_bondlist_orig = neighborKK->k_bondlist; - auto d_bondlist_orig = k_bondlist_orig.d_view; - auto d_nbondlist = k_nbondlist.d_view; - auto h_nbondlist = k_nbondlist.h_view; + // save ptrs to original improperlist - // if this is re-neighbor step, create sub-style bondlists - // nbondlist[] = length of each sub-style list - // realloc sub-style bondlist if necessary - // load sub-style bondlist with 3 values from original bondlist + int nimproperlist_orig = neighbor->nimproperlist; + neighborKK->k_improperlist.sync_device(); + auto k_improperlist_orig = neighborKK->k_improperlist; + auto d_improperlist_orig = k_improperlist_orig.d_view; + auto d_nimproperlist = k_nimproperlist.d_view; + auto h_nimproperlist = k_nimproperlist.h_view; + + // if this is re-neighbor step, create sub-style improperlists + // nimproperlist[] = length of each sub-style list + // realloc sub-style improperlist if necessary + // load sub-style improperlist with 3 values from original improperlist if (neighbor->ago == 0) { - Kokkos::deep_copy(d_nbondlist,0); + Kokkos::deep_copy(d_nimproperlist,0); k_map.sync_device(); auto d_map = k_map.d_view; - Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_bondlist_orig(i,2)]; - if (m >= 0) Kokkos::atomic_increment(&d_nbondlist[m]); + Kokkos::parallel_for(nimproperlist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_improperlist_orig(i,2)]; + if (m >= 0) Kokkos::atomic_increment(&d_nimproperlist[m]); }); - k_nbondlist.modify_device(); - k_nbondlist.sync_host(); + k_nimproperlist.modify_device(); + k_nimproperlist.sync_host(); - maxbond_all = 0; + maximproper_all = 0; for (int m = 0; m < nstyles; m++) - if (h_nbondlist[m] > maxbond_all) - maxbond_all = h_nbondlist[m] + EXTRA; + if (h_nimproperlist[m] > maximproper_all) + maximproper_all = h_nimproperlist[m] + EXTRA; - if (k_bondlist.d_view.extent(1) < maxbond_all) - MemKK::realloc_kokkos(k_bondlist, "bond_hybrid:bondlist", nstyles, maxbond_all, 3); - auto d_bondlist = k_bondlist.d_view; + if (k_improperlist.d_view.extent(1) < maximproper_all) + MemKK::realloc_kokkos(k_improperlist, "improper_hybrid:improperlist", nstyles, maximproper_all, 3); + auto d_improperlist = k_improperlist.d_view; - Kokkos::deep_copy(d_nbondlist,0); + Kokkos::deep_copy(d_nimproperlist,0); - Kokkos::parallel_for(nbondlist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_bondlist_orig(i,2)]; + Kokkos::parallel_for(nimproperlist_orig,LAMMPS_LAMBDA(int i) { + const int m = d_map[d_improperlist_orig(i,2)]; if (m < 0) return; - const int n = Kokkos::atomic_fetch_add(&d_nbondlist[m],1); - d_bondlist(m,n,0) = d_bondlist_orig(i,0); - d_bondlist(m,n,1) = d_bondlist_orig(i,1); - d_bondlist(m,n,2) = d_bondlist_orig(i,2); + const int n = Kokkos::atomic_fetch_add(&d_nimproperlist[m],1); + d_improperlist(m,n,0) = d_improperlist_orig(i,0); + d_improperlist(m,n,1) = d_improperlist_orig(i,1); + d_improperlist(m,n,2) = d_improperlist_orig(i,2); + d_improperlist(m,n,3) = d_improperlist_orig(i,3); + d_improperlist(m,n,4) = d_improperlist_orig(i,4); }); } // call each sub-style's compute function - // set neighbor->bondlist to sub-style bondlist before call + // set neighbor->improperlist to sub-style improperlist before call // accumulate sub-style global/peratom energy/virial in hybrid ev_init(eflag, vflag); - k_nbondlist.modify_device(); - k_nbondlist.sync_host(); + k_nimproperlist.modify_device(); + k_nimproperlist.sync_host(); for (int m = 0; m < nstyles; m++) { - neighbor->nbondlist = h_nbondlist[m]; - auto k_bondlist_m = Kokkos::subview(k_bondlist,m,Kokkos::ALL,Kokkos::ALL); - k_bondlist_m.modify_device(); - neighborKK->k_bondlist = k_bondlist_m; + neighbor->nimproperlist = h_nimproperlist[m]; + auto k_improperlist_m = Kokkos::subview(k_improperlist,m,Kokkos::ALL,Kokkos::ALL); + k_improperlist_m.modify_device(); + neighborKK->k_improperlist = k_improperlist_m; auto style = styles[m]; atomKK->sync(style->execution_space,style->datamask_read); @@ -142,29 +145,29 @@ void BondHybridKokkos::compute(int eflag, int vflag) } } - // restore ptrs to original bondlist + // restore ptrs to original improperlist - neighbor->nbondlist = nbondlist_orig; - neighborKK->k_bondlist = k_bondlist_orig; + neighbor->nimproperlist = nimproperlist_orig; + neighborKK->k_improperlist = k_improperlist_orig; } /* ---------------------------------------------------------------------- */ -void BondHybridKokkos::allocate() +void ImproperHybridKokkos::allocate() { allocated = 1; - int n = atom->nbondtypes; + int n = atom->nimpropertypes; - memoryKK->create_kokkos(k_map, map, n + 1, "bond:map"); - memory->create(setflag, n + 1, "bond:setflag"); + memoryKK->create_kokkos(k_map, map, n + 1, "improper:map"); + memory->create(setflag, n + 1, "improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; - k_nbondlist = DAT::tdual_int_1d("bond:nbondlist", nstyles); + k_nimproperlist = DAT::tdual_int_1d("improper:nimproperlist", nstyles); } /* ---------------------------------------------------------------------- */ -void BondHybridKokkos::deallocate() +void ImproperHybridKokkos::deallocate() { if (!allocated) return; @@ -178,22 +181,22 @@ void BondHybridKokkos::deallocate() set coeffs for one type ---------------------------------------------------------------------- */ -void BondHybridKokkos::coeff(int narg, char **arg) +void ImproperHybridKokkos::coeff(int narg, char **arg) { - BondHybrid::coeff(narg,arg); + ImproperHybrid::coeff(narg,arg); k_map.modify_host(); } /* ---------------------------------------------------------------------- */ -void BondHybridKokkos::init_style() +void ImproperHybridKokkos::init_style() { - BondHybrid::init_style(); + ImproperHybrid::init_style(); for (int m = 0; m < nstyles; m++) { if (!styles[m]->kokkosable) - error->all(FLERR,"Must use only Kokkos-enabled bond styles with bond_style hybrid/kk"); + error->all(FLERR,"Must use only Kokkos-enabled improper styles with improper_style hybrid/kk"); if (styles[m]->execution_space == Host) lmp->kokkos->allow_overlap = 0; @@ -204,11 +207,11 @@ void BondHybridKokkos::init_style() memory usage ------------------------------------------------------------------------- */ -double BondHybridKokkos::memory_usage() +double ImproperHybridKokkos::memory_usage() { double bytes = (double) maxeatom * sizeof(double); bytes += (double) maxvatom * 6 * sizeof(double); - for (int m = 0; m < nstyles; m++) bytes += (double) maxbond_all * 3 * sizeof(int); + for (int m = 0; m < nstyles; m++) bytes += (double) maximproper_all * 3 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; diff --git a/src/KOKKOS/improper_hybrid_kokkos.h b/src/KOKKOS/improper_hybrid_kokkos.h index 217beaca5f..f2a80f6a0c 100644 --- a/src/KOKKOS/improper_hybrid_kokkos.h +++ b/src/KOKKOS/improper_hybrid_kokkos.h @@ -13,9 +13,9 @@ #ifdef BOND_CLASS // clang-format off -BondStyle(hybrid/kk,BondHybridKokkos); -BondStyle(hybrid/kk/device,BondHybridKokkos); -BondStyle(hybrid/kk/host,BondHybridKokkos); +ImproperStyle(hybrid/kk,ImproperHybridKokkos); +ImproperStyle(hybrid/kk/device,ImproperHybridKokkos); +ImproperStyle(hybrid/kk/host,ImproperHybridKokkos); // clang-format on #else @@ -23,30 +23,30 @@ BondStyle(hybrid/kk/host,BondHybridKokkos); #ifndef LMP_BOND_HYBRID_KOKKOS_H #define LMP_BOND_HYBRID_KOKKOS_H -#include "bond_hybrid.h" +#include "improper_hybrid.h" #include "kokkos_type.h" namespace LAMMPS_NS { -class BondHybridKokkos : public BondHybrid { +class ImproperHybridKokkos : public ImproperHybrid { friend class Force; public: - BondHybridKokkos(class LAMMPS *); - ~BondHybridKokkos() override; + ImproperHybridKokkos(class LAMMPS *); + ~ImproperHybridKokkos() override; void compute(int, int) override; void coeff(int, char **) override; void init_style() override; double memory_usage() override; private: - int maxbond_all; + int maximproper_all; class NeighborKokkos *neighborKK; - DAT::tdual_int_1d k_map; // which style each bond type points to - DAT::tdual_int_1d k_nbondlist; // # of bonds in sub-style bondlists - DAT::tdual_int_3d k_bondlist; // bondlist for each sub-style + DAT::tdual_int_1d k_map; // which style each improper type points to + DAT::tdual_int_1d k_nimproperlist; // # of impropers in sub-style improperlists + DAT::tdual_int_3d k_improperlist; // improperlist for each sub-style void allocate() override; void deallocate() override; From 7673a904d148854ba2ce26e41b27dbf285c7ea51 Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Mon, 8 Jul 2024 05:05:06 -0600 Subject: [PATCH 200/385] update variable for consistency w/ non-kokkos --- src/KOKKOS/angle_hybrid_kokkos.cpp | 8 ++++---- src/KOKKOS/bond_hybrid_kokkos.cpp | 8 ++++---- src/KOKKOS/dihedral_hybrid_kokkos.cpp | 8 ++++---- src/KOKKOS/improper_hybrid_kokkos.cpp | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/KOKKOS/angle_hybrid_kokkos.cpp b/src/KOKKOS/angle_hybrid_kokkos.cpp index 8293e31b91..4f2e26746c 100644 --- a/src/KOKKOS/angle_hybrid_kokkos.cpp +++ b/src/KOKKOS/angle_hybrid_kokkos.cpp @@ -154,11 +154,11 @@ void AngleHybridKokkos::compute(int eflag, int vflag) void AngleHybridKokkos::allocate() { allocated = 1; - int n = atom->nangletypes; + int np1 = atom->nangletypes + 1; - memoryKK->create_kokkos(k_map, map, n + 1, "angle:map"); - memory->create(setflag, n + 1, "angle:setflag"); - for (int i = 1; i <= n; i++) setflag[i] = 0; + memoryKK->create_kokkos(k_map, map, np1, "angle:map"); + memory->create(setflag, np1, "angle:setflag"); + for (int i = 1; i <= np1; i++) setflag[i] = 0; k_nanglelist = DAT::tdual_int_1d("angle:nanglelist", nstyles); } diff --git a/src/KOKKOS/bond_hybrid_kokkos.cpp b/src/KOKKOS/bond_hybrid_kokkos.cpp index d63ebccac6..8a391808c9 100644 --- a/src/KOKKOS/bond_hybrid_kokkos.cpp +++ b/src/KOKKOS/bond_hybrid_kokkos.cpp @@ -153,11 +153,11 @@ void BondHybridKokkos::compute(int eflag, int vflag) void BondHybridKokkos::allocate() { allocated = 1; - int n = atom->nbondtypes; + int np1 = atom->nbondtypes + 1; - memoryKK->create_kokkos(k_map, map, n + 1, "bond:map"); - memory->create(setflag, n + 1, "bond:setflag"); - for (int i = 1; i <= n; i++) setflag[i] = 0; + memoryKK->create_kokkos(k_map, map, np1, "bond:map"); + memory->create(setflag, np1, "bond:setflag"); + for (int i = 1; i <= np1; i++) setflag[i] = 0; k_nbondlist = DAT::tdual_int_1d("bond:nbondlist", nstyles); } diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.cpp b/src/KOKKOS/dihedral_hybrid_kokkos.cpp index d0b9f7d646..4570f316a4 100644 --- a/src/KOKKOS/dihedral_hybrid_kokkos.cpp +++ b/src/KOKKOS/dihedral_hybrid_kokkos.cpp @@ -155,11 +155,11 @@ void DihedralHybridKokkos::compute(int eflag, int vflag) void DihedralHybridKokkos::allocate() { allocated = 1; - int n = atom->ndihedraltypes; + int np1 = atom->ndihedraltypes + 1; - memoryKK->create_kokkos(k_map, map, n + 1, "dihedral:map"); - memory->create(setflag, n + 1, "dihedral:setflag"); - for (int i = 1; i <= n; i++) setflag[i] = 0; + memoryKK->create_kokkos(k_map, map, np1, "dihedral:map"); + memory->create(setflag, np1, "dihedral:setflag"); + for (int i = 1; i <= np1; i++) setflag[i] = 0; k_ndihedrallist = DAT::tdual_int_1d("dihedral:ndihedrallist", nstyles); } diff --git a/src/KOKKOS/improper_hybrid_kokkos.cpp b/src/KOKKOS/improper_hybrid_kokkos.cpp index 4d571b3eae..1384d8648d 100644 --- a/src/KOKKOS/improper_hybrid_kokkos.cpp +++ b/src/KOKKOS/improper_hybrid_kokkos.cpp @@ -156,11 +156,11 @@ void ImproperHybridKokkos::compute(int eflag, int vflag) void ImproperHybridKokkos::allocate() { allocated = 1; - int n = atom->nimpropertypes; + int np1 = atom->nimpropertypes + 1; - memoryKK->create_kokkos(k_map, map, n + 1, "improper:map"); - memory->create(setflag, n + 1, "improper:setflag"); - for (int i = 1; i <= n; i++) setflag[i] = 0; + memoryKK->create_kokkos(k_map, map, np1, "improper:map"); + memory->create(setflag, np1, "improper:setflag"); + for (int i = 1; i <= np1; i++) setflag[i] = 0; k_nimproperlist = DAT::tdual_int_1d("improper:nimproperlist", nstyles); } From d0e5640a75c0659d818d47c0bf80c0a327eb8d74 Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Mon, 8 Jul 2024 05:05:36 -0600 Subject: [PATCH 201/385] add cvflag check, update mem usage --- src/KOKKOS/angle_hybrid_kokkos.cpp | 10 +++++++++- src/KOKKOS/dihedral_hybrid_kokkos.cpp | 10 +++++++++- src/KOKKOS/improper_hybrid_kokkos.cpp | 10 +++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/KOKKOS/angle_hybrid_kokkos.cpp b/src/KOKKOS/angle_hybrid_kokkos.cpp index 4f2e26746c..ffcc20538f 100644 --- a/src/KOKKOS/angle_hybrid_kokkos.cpp +++ b/src/KOKKOS/angle_hybrid_kokkos.cpp @@ -141,6 +141,13 @@ void AngleHybridKokkos::compute(int eflag, int vflag) for (int i = 0; i < n; i++) for (int j = 0; j < 6; j++) vatom[i][j] += vatom_substyle[i][j]; } + if (cvflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double **cvatom_substyle = styles[m]->cvatom; + for (int i = 0; i < n; i++) + for (int j = 0; j < 9; j++) cvatom[i][j] += cvatom_substyle[i][j]; + } } // restore ptrs to original anglelist @@ -209,7 +216,8 @@ double AngleHybridKokkos::memory_usage() { double bytes = (double) maxeatom * sizeof(double); bytes += (double) maxvatom * 6 * sizeof(double); - for (int m = 0; m < nstyles; m++) bytes += (double) maxangle_all * 3 * sizeof(int); + bytes += (double) maxcvatom * 9 * sizeof(double); + for (int m = 0; m < nstyles; m++) bytes += (double) maxangle_all * 4 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.cpp b/src/KOKKOS/dihedral_hybrid_kokkos.cpp index 4570f316a4..5e7c9ac8b8 100644 --- a/src/KOKKOS/dihedral_hybrid_kokkos.cpp +++ b/src/KOKKOS/dihedral_hybrid_kokkos.cpp @@ -142,6 +142,13 @@ void DihedralHybridKokkos::compute(int eflag, int vflag) for (int i = 0; i < n; i++) for (int j = 0; j < 6; j++) vatom[i][j] += vatom_substyle[i][j]; } + if (cvflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double **cvatom_substyle = styles[m]->cvatom; + for (int i = 0; i < n; i++) + for (int j = 0; j < 9; j++) cvatom[i][j] += cvatom_substyle[i][j]; + } } // restore ptrs to original dihedrallist @@ -210,7 +217,8 @@ double DihedralHybridKokkos::memory_usage() { double bytes = (double) maxeatom * sizeof(double); bytes += (double) maxvatom * 6 * sizeof(double); - for (int m = 0; m < nstyles; m++) bytes += (double) maxdihedral_all * 3 * sizeof(int); + bytes += (double) maxcvatom * 9 * sizeof(double); + for (int m = 0; m < nstyles; m++) bytes += (double) maxdihedral_all * 5 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; diff --git a/src/KOKKOS/improper_hybrid_kokkos.cpp b/src/KOKKOS/improper_hybrid_kokkos.cpp index 1384d8648d..3d4790c818 100644 --- a/src/KOKKOS/improper_hybrid_kokkos.cpp +++ b/src/KOKKOS/improper_hybrid_kokkos.cpp @@ -143,6 +143,13 @@ void ImproperHybridKokkos::compute(int eflag, int vflag) for (int i = 0; i < n; i++) for (int j = 0; j < 6; j++) vatom[i][j] += vatom_substyle[i][j]; } + if (cvflag_atom) { + int n = atom->nlocal; + if (force->newton_bond) n += atom->nghost; + double **cvatom_substyle = styles[m]->cvatom; + for (int i = 0; i < n; i++) + for (int j = 0; j < 9; j++) cvatom[i][j] += cvatom_substyle[i][j]; + } } // restore ptrs to original improperlist @@ -211,7 +218,8 @@ double ImproperHybridKokkos::memory_usage() { double bytes = (double) maxeatom * sizeof(double); bytes += (double) maxvatom * 6 * sizeof(double); - for (int m = 0; m < nstyles; m++) bytes += (double) maximproper_all * 3 * sizeof(int); + bytes += (double) maxcvatom * 9 * sizeof(double); + for (int m = 0; m < nstyles; m++) bytes += (double) maximproper_all * 5 * sizeof(int); for (int m = 0; m < nstyles; m++) if (styles[m]) bytes += styles[m]->memory_usage(); return bytes; From 8f6cf085e871f4cb1a1aadca6b5f4f7a307b16b3 Mon Sep 17 00:00:00 2001 From: jtclemm Date: Tue, 9 Jul 2024 15:06:18 -0600 Subject: [PATCH 202/385] syncing table in build_packages/extra --- doc/src/Build_package.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/Build_package.rst b/doc/src/Build_package.rst index 63ccac534d..b70a1ca4d1 100644 --- a/doc/src/Build_package.rst +++ b/doc/src/Build_package.rst @@ -62,6 +62,7 @@ packages: * :ref:`POEMS ` * :ref:`PYTHON ` * :ref:`QMMM ` + * :ref:`RHEO ` * :ref:`SCAFACOS ` * :ref:`VORONOI ` * :ref:`VTK ` From b9e263b1d1f0df20cb2e56fae1dcc09fe7be871e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 10 Jul 2024 16:17:33 -0400 Subject: [PATCH 203/385] re-add empty row between special and regular pair styles --- doc/src/Commands_pair.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/src/Commands_pair.rst b/doc/src/Commands_pair.rst index f83f2539a3..c0747b83d4 100644 --- a/doc/src/Commands_pair.rst +++ b/doc/src/Commands_pair.rst @@ -35,6 +35,10 @@ OPT. * * * + * + * + * + * * :doc:`adp (ko) ` * :doc:`agni (o) ` * :doc:`aip/water/2dm (t) ` From e51e0c1fb7a3729c2dfa5732247d5c5d9d2376b1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 11 Jul 2024 11:37:42 -0400 Subject: [PATCH 204/385] re-order entries --- doc/src/pair_coul.rst | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/doc/src/pair_coul.rst b/doc/src/pair_coul.rst index 14cc4851f6..2a011dc2d2 100644 --- a/doc/src/pair_coul.rst +++ b/doc/src/pair_coul.rst @@ -2,6 +2,8 @@ .. index:: pair_style coul/cut/gpu .. index:: pair_style coul/cut/kk .. index:: pair_style coul/cut/omp +.. index:: pair_style coul/cut/global +.. index:: pair_style coul/cut/global/omp .. index:: pair_style coul/debye .. index:: pair_style coul/debye/gpu .. index:: pair_style coul/debye/kk @@ -11,8 +13,6 @@ .. index:: pair_style coul/dsf/kk .. index:: pair_style coul/dsf/omp .. index:: pair_style coul/exclude -.. index:: pair_style coul/cut/global -.. index:: pair_style coul/cut/global/omp .. index:: pair_style coul/long .. index:: pair_style coul/long/omp .. index:: pair_style coul/long/kk @@ -33,6 +33,11 @@ pair_style coul/cut command Accelerator Variants: *coul/cut/gpu*, *coul/cut/kk*, *coul/cut/omp* +pair_style coul/cut/global command +================================== + +Accelerator Variants: *coul/cut/omp* + pair_style coul/debye command ============================= @@ -46,11 +51,6 @@ Accelerator Variants: *coul/dsf/gpu*, *coul/dsf/kk*, *coul/dsf/omp* pair_style coul/exclude command =============================== -pair_style coul/cut/global command -================================== - -Accelerator Variants: *coul/cut/omp* - pair_style coul/long command ============================ @@ -79,16 +79,17 @@ pair_style tip4p/long command Accelerator Variants: *tip4p/long/omp* + Syntax """""" .. code-block:: LAMMPS pair_style coul/cut cutoff + pair_style coul/cut/global cutoff pair_style coul/debye kappa cutoff pair_style coul/dsf alpha cutoff pair_style coul/exclude cutoff - pair_style coul/cut/global cutoff pair_style coul/long cutoff pair_style coul/wolf alpha cutoff pair_style coul/streitz cutoff keyword alpha @@ -152,6 +153,11 @@ the 2 atoms, and :math:`\epsilon` is the dielectric constant which can be set by the :doc:`dielectric ` command. The cutoff :math:`r_c` truncates the interaction distance. +Pair style *coul/cut/global* computes the same Coulombic interactions +as style *coul/cut* except that it allows only a single global cutoff +and thus makes it compatible for use in combination with long-range +coulomb styles in :doc:`hybrid pair styles `. + ---------- Style *coul/debye* adds an additional exp() damping factor to the @@ -262,11 +268,6 @@ Streitz-Mintmire parameterization for the material being modeled. ---------- -Pair style *coul/cut/global* computes the same Coulombic interactions -as style *coul/cut* except that it allows only a single global cutoff -and thus makes it compatible for use in combination with long-range -coulomb styles in :doc:`hybrid pair styles `. - Pair style *coul/exclude* computes Coulombic interactions like *coul/cut* but **only** applies them to excluded pairs using a scaling factor of :math:`\gamma - 1.0` with :math:`\gamma` being the factor assigned From 9e917412c923673428813633f21cb6a7c73a6e8f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 11 Jul 2024 12:39:42 -0400 Subject: [PATCH 205/385] fix typo and rewrap lines --- doc/src/Packages_details.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index e759e3bd18..a62e7e41b3 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -1323,18 +1323,19 @@ KSPACE package **Contents:** -A variety of long-range Coulombic solvers, as well as pair styles -which compute the corresponding short-range pairwise Coulombic -interactions. These include Ewald, particle-particle particle-mesh -(PPPM), and multilevel summation method (MSM) solvers. +A variety of long-range Coulombic solvers, as well as pair styles which +compute the corresponding short-range pairwise Coulombic interactions. +These include Ewald, particle-particle particle-mesh (PPPM), and +multilevel summation method (MSM) solvers. **Install:** -Building with this package requires a 1d FFT library be present on -your system for use by the PPPM solvers. This can be the KISS FFT -library provided with LAMMPS, third party libraries like FFTW, or a -vendor-supplied FFT library. See the :doc:`Build settings ` page for details on how to select -different FFT options for your LAMPMS build. +Building with this package requires a 1d FFT library be present on your +system for use by the PPPM solvers. This can be the KISS FFT library +provided with LAMMPS, third party libraries like FFTW, or a +vendor-supplied FFT library. See the :doc:`Build settings +` page for details on how to select different FFT +options for your LAMMPS build. **Supporting info:** From c1c1d32136f3af8242a6ba6417cc9f7c89c38746 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 11 Jul 2024 13:32:56 -0400 Subject: [PATCH 206/385] The post_force callback should also be called during "setup" --- src/PYTHON/fix_python_invoke.cpp | 7 +++++++ src/PYTHON/fix_python_invoke.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/PYTHON/fix_python_invoke.cpp b/src/PYTHON/fix_python_invoke.cpp index 786c48568d..281379cda4 100644 --- a/src/PYTHON/fix_python_invoke.cpp +++ b/src/PYTHON/fix_python_invoke.cpp @@ -105,6 +105,13 @@ void FixPythonInvoke::end_of_step() /* ---------------------------------------------------------------------- */ +void FixPythonInvoke::setup(int vflag) +{ + post_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + void FixPythonInvoke::post_force(int vflag) { if (update->ntimestep % nevery != 0) return; diff --git a/src/PYTHON/fix_python_invoke.h b/src/PYTHON/fix_python_invoke.h index 12f463501f..09382e5780 100644 --- a/src/PYTHON/fix_python_invoke.h +++ b/src/PYTHON/fix_python_invoke.h @@ -30,6 +30,7 @@ class FixPythonInvoke : public Fix { FixPythonInvoke(class LAMMPS *, int, char **); ~FixPythonInvoke() override; int setmask() override; + void setup(int) override; void end_of_step() override; void post_force(int) override; From a55092dc26527aa4f4225fcb8f7b05626ff2a393 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 11 Jul 2024 13:39:44 -0400 Subject: [PATCH 207/385] rewrap docs --- doc/src/fix_store_force.rst | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/doc/src/fix_store_force.rst b/doc/src/fix_store_force.rst index 487d4f0352..acce05fbf8 100644 --- a/doc/src/fix_store_force.rst +++ b/doc/src/fix_store_force.rst @@ -23,11 +23,12 @@ Examples Description """"""""""" -Store the forces on atoms in the group at the point during each -timestep when the fix is invoked, as described below. This is useful -for storing forces before constraints or other boundary conditions are -computed which modify the forces, so that unmodified forces can be -:doc:`written to a dump file ` or accessed by other :doc:`output commands ` that use per-atom quantities. +Store the forces on atoms in the group at the point during each timestep +when the fix is invoked, as described below. This is useful for storing +forces before constraints or other boundary conditions are computed +which modify the forces, so that unmodified forces can be :doc:`written +to a dump file ` or accessed by other :doc:`output commands +` that use per-atom quantities. This fix is invoked at the point in the velocity-Verlet timestepping immediately after :doc:`pair `, :doc:`bond `, @@ -36,12 +37,13 @@ immediately after :doc:`pair `, :doc:`bond `, forces have been calculated. It is the point in the timestep when various fixes that compute constraint forces are calculated and potentially modify the force on each atom. Examples of such fixes are -:doc:`fix shake `, :doc:`fix wall `, and :doc:`fix indent `. +:doc:`fix shake `, :doc:`fix wall `, and :doc:`fix +indent `. .. note:: - The order in which various fixes are applied which operate at - the same point during the timestep, is the same as the order they are + The order in which various fixes are applied which operate at the + same point during the timestep, is the same as the order they are specified in the input script. Thus normally, if you want to store per-atom forces due to force field interactions, before constraints are applied, you should list this fix first within that set of fixes, @@ -52,8 +54,9 @@ potentially modify the force on each atom. Examples of such fixes are Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options -are relevant to this fix. +No information about this fix is written to :doc:`binary restart files +`. None of the :doc:`fix_modify ` options are +relevant to this fix. This fix produces a per-atom array which can be accessed by various :doc:`output commands `. The number of columns for each @@ -61,7 +64,8 @@ atom is 3, and the columns store the x,y,z forces on each atom. The per-atom values be accessed on any timestep. No parameter of this fix can be used with the *start/stop* keywords of -the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. +the :doc:`run ` command. This fix is not invoked during +:doc:`energy minimization `. Restrictions """""""""""" From 47af1775c2278c2a4c949ef6cfc7f90f323234c4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 11 Jul 2024 15:02:03 -0400 Subject: [PATCH 208/385] update test since we have now one invocation also during setup --- unittest/python/test_python_package.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittest/python/test_python_package.cpp b/unittest/python/test_python_package.cpp index f998ebbcd8..7d3382d46f 100644 --- a/unittest/python/test_python_package.cpp +++ b/unittest/python/test_python_package.cpp @@ -342,7 +342,7 @@ TEST_F(FixPythonInvokeTest, post_force) if (line == "PYTHON_POST_FORCE") ++count; } - ASSERT_EQ(count, 5); + ASSERT_EQ(count, 6); } } // namespace LAMMPS_NS From 0e6ff7d70a0aa0c18acd315b0227151f5670b25d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 11 Jul 2024 15:02:38 -0400 Subject: [PATCH 209/385] only call post_force() if it was selected as callback. --- src/PYTHON/fix_python_invoke.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PYTHON/fix_python_invoke.cpp b/src/PYTHON/fix_python_invoke.cpp index 281379cda4..7fd3ad88f7 100644 --- a/src/PYTHON/fix_python_invoke.cpp +++ b/src/PYTHON/fix_python_invoke.cpp @@ -107,7 +107,7 @@ void FixPythonInvoke::end_of_step() void FixPythonInvoke::setup(int vflag) { - post_force(vflag); + if (selected_callback == POST_FORCE) post_force(vflag); } /* ---------------------------------------------------------------------- */ From 06511a6e77442fb1b2421c33202a7ddcd621987f Mon Sep 17 00:00:00 2001 From: Jacob Gissinger Date: Thu, 11 Jul 2024 19:17:09 -0400 Subject: [PATCH 210/385] couple more doc tweaks --- doc/src/Howto_chunk.rst | 16 ++++++++-------- doc/src/read_data.rst | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/src/Howto_chunk.rst b/doc/src/Howto_chunk.rst index 454e58cfa7..f8655b745d 100644 --- a/doc/src/Howto_chunk.rst +++ b/doc/src/Howto_chunk.rst @@ -148,14 +148,14 @@ Example calculations with chunks Here are examples using chunk commands to calculate various properties: -(1) Average velocity in each of 1000 2d spatial bins: +1. Average velocity in each of 1000 2d spatial bins: .. code-block:: LAMMPS compute cc1 all chunk/atom bin/2d x 0.0 0.1 y lower 0.01 units reduced fix 1 all ave/chunk 100 10 1000 cc1 vx vy file tmp.out -(2) Temperature in each spatial bin, after subtracting a flow +2. Temperature in each spatial bin, after subtracting a flow velocity: .. code-block:: LAMMPS @@ -164,7 +164,7 @@ velocity: compute vbias all temp/profile 1 0 0 y 10 fix 1 all ave/chunk 100 10 1000 cc1 temp bias vbias file tmp.out -(3) Center of mass of each molecule: +3. Center of mass of each molecule: .. code-block:: LAMMPS @@ -172,7 +172,7 @@ velocity: compute myChunk all com/chunk cc1 fix 1 all ave/time 100 1 100 c_myChunk[*] file tmp.out mode vector -(4) Total force on each molecule and ave/max across all molecules: +4. Total force on each molecule and ave/max across all molecules: .. code-block:: LAMMPS @@ -183,7 +183,7 @@ velocity: thermo 1000 thermo_style custom step temp v_xave v_xmax -(5) Histogram of cluster sizes: +5. Histogram of cluster sizes: .. code-block:: LAMMPS @@ -192,16 +192,16 @@ velocity: compute size all property/chunk cc1 count fix 1 all ave/histo 100 1 100 0 20 20 c_size mode vector ave running beyond ignore file tmp.histo -(6) An example for using a per-chunk value to apply per-atom forces to +6. An example for using a per-chunk value to apply per-atom forces to compress individual polymer chains (molecules) in a mixture, is explained on the :doc:`compute chunk/spread/atom ` command doc page. -(7) An example for using one set of per-chunk values for molecule +7. An example for using one set of per-chunk values for molecule chunks, to create a second set of micelle-scale chunks (clustered molecules, due to hydrophobicity), is explained on the :doc:`compute reduce/chunk ` command doc page. -(8) An example for using one set of per-chunk values (dipole moment +8. An example for using one set of per-chunk values (dipole moment vectors) for molecule chunks, spreading the values to each atom in each chunk, then defining a second set of chunks as spatial bins, and using the :doc:`fix ave/chunk ` command to calculate an diff --git a/doc/src/read_data.rst b/doc/src/read_data.rst index dd2f42e2a8..88060a105b 100644 --- a/doc/src/read_data.rst +++ b/doc/src/read_data.rst @@ -12,7 +12,7 @@ Syntax * file = name of data file to read in * zero or more keyword/arg pairs may be appended -* keyword = *add* or *offset* or *shift* or *extra/atom/types* or *extra/bond/types* or *extra/angle/types* or *extra/dihedral/types* or *extra/improper/types* or *extra/bond/per/atom* or *extra/angle/per/atom* or *extra/dihedral/per/atom* or *extra/improper/per/atom* or *group* or *nocoeff* or *fix* +* keyword = *add* or *offset* or *shift* or *extra/atom/types* or *extra/bond/types* or *extra/angle/types* or *extra/dihedral/types* or *extra/improper/types* or *extra/bond/per/atom* or *extra/angle/per/atom* or *extra/dihedral/per/atom* or *extra/improper/per/atom* or *extra/special/per/atom* or *group* or *nocoeff* or *fix* .. parsed-literal:: From a0fb12c265024b6e05b4c4057b6065be77ef2d1c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 12 Jul 2024 23:42:42 -0400 Subject: [PATCH 211/385] disentangle the fix deform and fix deform/pressure pages somewhere for easier reading --- doc/src/fix_deform.rst | 48 ++++++---------------------- doc/src/fix_deform_pressure.rst | 55 ++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index 2c76463369..c5832d1729 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -4,9 +4,6 @@ fix deform command ================== -:doc:`fix deform/pressure ` command -======================================================== - Accelerator Variants: *deform/kk* Syntax @@ -14,12 +11,11 @@ Syntax .. code-block:: LAMMPS - fix ID group-ID fix_style N parameter style args ... keyword value ... + fix ID group-ID deform N parameter style args ... keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* fix_style = *deform* or *deform/pressure* * N = perform box deformation every this many timesteps -* one or more parameter/style/args sequences of arguments may be appended +* one or more parameter/args sequences may be appended .. parsed-literal:: @@ -46,12 +42,6 @@ Syntax *variable* values = v_name1 v_name2 v_name1 = variable with name1 for box length change as function of time v_name2 = variable with name2 for change rate as function of time - *pressure* values = target gain (ONLY available in :doc:`fix deform/pressure ` command) - target = target pressure (pressure units) - gain = proportional gain constant (1/(time * pressure) or 1/time units) - *pressure/mean* values = target gain (ONLY available in :doc:`fix deform/pressure ` command) - target = target pressure (pressure units) - gain = proportional gain constant (1/(time * pressure) or 1/time units) *xy*, *xz*, *yz* args = style value style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* or *variable* @@ -64,8 +54,6 @@ Syntax effectively an engineering shear strain rate *erate* value = R R = engineering shear strain rate (1/time units) - *erate/rescale* value = R (ONLY available in :doc:`fix deform/pressure ` command) - R = engineering shear strain rate (1/time units) *trate* value = R R = true shear strain rate (1/time units) *wiggle* values = A Tp @@ -74,9 +62,6 @@ Syntax *variable* values = v_name1 v_name2 v_name1 = variable with name1 for tilt change as function of time v_name2 = variable with name2 for change rate as function of time - *pressure* values = target gain (ONLY available in :doc:`fix deform/pressure ` command) - target = target pressure (pressure units) - gain = proportional gain constant (1/(time * pressure) or 1/time units) * zero or more keyword/value pairs may be appended * keyword = *remap* or *flip* or *units* or *couple* or *vol/balance/p* or *max/rate* or *normalize/pressure* @@ -92,15 +77,6 @@ Syntax *units* value = *lattice* or *box* lattice = distances are defined in lattice units box = distances are defined in simulation box units - *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* (ONLY available in :doc:`fix deform/pressure ` command) - couple pressure values of various dimensions - *vol/balance/p* value = *yes* or *no* (ONLY available in :doc:`fix deform/pressure ` command) - Modifies the behavior of the *volume* option to try and balance pressures - *max/rate* value = *rate* (ONLY available in :doc:`fix deform/pressure ` command) - rate = maximum strain rate for pressure control - *normalize/pressure* value = *yes* or *no* (ONLY available in :doc:`fix deform/pressure ` command) - Modifies pressure controls such that the deviation in pressure is normalized by the target pressure - Examples """""""" @@ -112,8 +88,6 @@ Examples fix 1 all deform 1 xy erate 0.001 remap v fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 -See examples for :doc:`fix deform/pressure ` on its doc page - Description """"""""""" @@ -123,17 +97,13 @@ run. Orthogonal simulation boxes have 3 adjustable parameters adjustable parameters (x,y,z,xy,xz,yz). Any or all of them can be adjusted independently and simultaneously. -The fix deform command allows use of all the arguments listed above, -except those flagged as available ONLY for the :doc:`fix -deform/pressure ` command, which are -pressure-based controls. The fix deform/pressure command allows use -of all the arguments listed above. - -The rest of this doc page explains the options common to both -commands. The :doc:`fix deform/pressure ` doc -page explains the options available ONLY with the fix deform/pressure -command. Note that a simulation can define only a single deformation -command: fix deform or fix deform/pressure. +The :doc:`fix deform/pressure ` command extends +this command with additional keywords and arguments. The rest of this +page explains the options common to both commands. The :doc:`fix +deform/pressure ` page explains the options +available ONLY with the fix deform/pressure command. Note that a +simulation can define only a single deformation command: fix deform or +fix deform/pressure. Both these fixes can be used to perform non-equilibrium MD (NEMD) simulations of a continuously strained system. See the :doc:`fix diff --git a/doc/src/fix_deform_pressure.rst b/doc/src/fix_deform_pressure.rst index 25ad5bfeca..d99a7611c4 100644 --- a/doc/src/fix_deform_pressure.rst +++ b/doc/src/fix_deform_pressure.rst @@ -13,29 +13,66 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * deform/pressure = style name of this fix command * N = perform box deformation every this many timesteps -* one or more parameter/arg sequences may be appended +* one or more parameter/args sequences may be appended .. parsed-literal:: parameter = *x* or *y* or *z* or *xy* or *xz* or *yz* or *box* *x*, *y*, *z* args = style value(s) style = *final* or *delta* or *scale* or *vel* or *erate* or *trate* or *volume* or *wiggle* or *variable* or *pressure* or *pressure/mean* + *final* values = lo hi + lo hi = box boundaries at end of run (distance units) + *delta* values = dlo dhi + dlo dhi = change in box boundaries at end of run (distance units) + *scale* values = factor + factor = multiplicative factor for change in box length at end of run + *vel* value = V + V = change box length at this velocity (distance/time units), + effectively an engineering strain rate + *erate* value = R + R = engineering strain rate (1/time units) + *trate* value = R + R = true strain rate (1/time units) + *volume* value = none = adjust this dim to preserve volume of system + *wiggle* values = A Tp + A = amplitude of oscillation (distance units) + Tp = period of oscillation (time units) + *variable* values = v_name1 v_name2 + v_name1 = variable with name1 for box length change as function of time + v_name2 = variable with name2 for change rate as function of time *pressure* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) *pressure/mean* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) - NOTE: All other styles are documented by the :doc:`fix deform ` command *xy*, *xz*, *yz* args = style value style = *final* or *delta* or *vel* or *erate* or *trate* or *wiggle* or *variable* or *pressure* or *erate/rescale* + *final* value = tilt + tilt = tilt factor at end of run (distance units) + *delta* value = dtilt + dtilt = change in tilt factor at end of run (distance units) + *vel* value = V + V = change tilt factor at this velocity (distance/time units), + effectively an engineering shear strain rate + *erate* value = R + R = engineering shear strain rate (1/time units) + *erate/rescale* value = R + R = engineering shear strain rate (1/time units) + *trate* value = R + R = true shear strain rate (1/time units) + *wiggle* values = A Tp + A = amplitude of oscillation (distance units) + Tp = period of oscillation (time units) + *variable* values = v_name1 v_name2 + v_name1 = variable with name1 for tilt change as function of time + v_name2 = variable with name2 for change rate as function of time *pressure* values = target gain target = target pressure (pressure units) gain = proportional gain constant (1/(time * pressure) or 1/time units) *erate/rescale* value = R R = engineering shear strain rate (1/time units) - NOTE: All other styles are documented by the :doc:`fix deform ` command *box* = style value style = *volume* or *pressure* @@ -49,6 +86,15 @@ Syntax .. parsed-literal:: + *remap* value = *x* or *v* or *none* + x = remap coords of atoms in group into deforming box + v = remap velocities of atoms in group when they cross periodic boundaries + none = no remapping of x or v + *flip* value = *yes* or *no* + allow or disallow box flips when it becomes highly skewed + *units* value = *lattice* or *box* + lattice = distances are defined in lattice units + box = distances are defined in simulation box units *couple* value = *none* or *xyz* or *xy* or *yz* or *xz* couple pressure values of various dimensions *vol/balance/p* value = *yes* or *no* @@ -57,7 +103,6 @@ Syntax rate = maximum strain rate for pressure control *normalize/pressure* value = *yes* or *no* Modifies pressure controls such that the deviation in pressure is normalized by the target pressure - NOTE: All other keywords are documented by the :doc:`fix deform ` command Examples """""""" @@ -79,7 +124,7 @@ pressure-based controls implemented by this command. All arguments described on the :doc:`fix deform ` doc page also apply to this fix unless otherwise noted below. The rest of this -doc page explains the arguments specific to this fix. Note that a +page explains the arguments specific to this fix only. Note that a simulation can define only a single deformation command: fix deform or fix deform/pressure. From 1912083935919792e278d247dfc76e3d7bb2882c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 12 Jul 2024 23:43:14 -0400 Subject: [PATCH 212/385] add warning about overflowing image flags and how to prevent that --- doc/src/fix_deform.rst | 18 ++++++++++++++++++ doc/src/fix_deform_pressure.rst | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index c5832d1729..829e4947eb 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -113,6 +113,24 @@ simulation of a continuously extended system (extensional flow) can be modeled using the :ref:`UEF package ` and its :doc:`fix commands `. +.. admonition:: Inconsistent trajectories due to image flags + :class: warning + + When running long simulations while shearing the box or using a high + shearing rate, it is possible that the image flags used for storing + unwrapped atom positions will "wrap around". When LAMMPS is compiled + with the default settings, case image flags are limited to a range of + :math:`-512 \le i \le 511`, which will overflow when atoms starting + at zero image flag value have passed through a periodic box dimension + more than 512 times. + + Changing the :ref:`size of LAMMPS integer types ` to the + "bigbig" setting can make this overflow much less likely, since it + increases the image flag value range to :math:`- 1,048,576 \le i \le + 1\,048\,575` + +---------- + For the *x*, *y*, *z* parameters, the associated dimension cannot be shrink-wrapped. For the *xy*, *yz*, *xz* parameters, the associated second dimension cannot be shrink-wrapped. Dimensions not varied by diff --git a/doc/src/fix_deform_pressure.rst b/doc/src/fix_deform_pressure.rst index d99a7611c4..f2881c5e28 100644 --- a/doc/src/fix_deform_pressure.rst +++ b/doc/src/fix_deform_pressure.rst @@ -128,6 +128,22 @@ page explains the arguments specific to this fix only. Note that a simulation can define only a single deformation command: fix deform or fix deform/pressure. +.. admonition:: Inconsistent trajectories due to image flags + :class: warning + + When running long simulations while shearing the box or using a high + shearing rate, it is possible that the image flags used for storing + unwrapped atom positions will "wrap around". When LAMMPS is compiled + with the default settings, case image flags are limited to a range of + :math:`-512 \le i \le 511`, which will overflow when atoms starting + at zero image flag value have passed through a periodic box dimension + more than 512 times. + + Changing the :ref:`size of LAMMPS integer types ` to the + "bigbig" setting can make this overflow much less likely, since it + increases the image flag value range to :math:`- 1,048,576 \le i \le + 1\,048\,575` + ---------- For the *x*, *y*, and *z* parameters, this is the meaning of the From 58513320d3332a32a0f6ffb330fdce8d56dd6e5e Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sat, 13 Jul 2024 15:33:56 -0600 Subject: [PATCH 213/385] core files: replace sprintf with snprintf --- src/dump_atom.cpp | 8 ++++-- src/dump_cfg.cpp | 32 ++++++++++++---------- src/dump_custom.cpp | 17 ++++++------ src/dump_grid.cpp | 13 +++++---- src/dump_local.cpp | 15 +++++----- src/dump_xyz.cpp | 4 +-- src/variable.cpp | 2 +- unittest/fortran/wrap_extract_variable.cpp | 6 ++-- 8 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/dump_atom.cpp b/src/dump_atom.cpp index dfacf8f2da..2238a3a81d 100644 --- a/src/dump_atom.cpp +++ b/src/dump_atom.cpp @@ -674,7 +674,9 @@ int DumpAtom::convert_image(int n, double *mybuf) memory->grow(sbuf,maxsbuf,"dump:sbuf"); } - offset += sprintf(&sbuf[offset],format, + offset += snprintf(&sbuf[offset], + maxsbuf - offset, + format, static_cast (mybuf[m]), static_cast (mybuf[m+1]), mybuf[m+2],mybuf[m+3],mybuf[m+4], @@ -700,7 +702,9 @@ int DumpAtom::convert_noimage(int n, double *mybuf) memory->grow(sbuf,maxsbuf,"dump:sbuf"); } - offset += sprintf(&sbuf[offset],format, + offset += snprintf(&sbuf[offset], + maxsbuf - offset, + format, static_cast (mybuf[m]), static_cast (mybuf[m+1]), mybuf[m+2],mybuf[m+3],mybuf[m+4]); diff --git a/src/dump_cfg.cpp b/src/dump_cfg.cpp index e5af83a3c6..0d22ece2c3 100644 --- a/src/dump_cfg.cpp +++ b/src/dump_cfg.cpp @@ -166,23 +166,24 @@ int DumpCFG::convert_string(int n, double *mybuf) } for (j = 0; j < size_one; j++) { + const auto maxsize = maxsbuf - offset; if (j == 0) { - offset += sprintf(&sbuf[offset],"%f \n",mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,"%f \n",mybuf[m]); } else if (j == 1) { - offset += sprintf(&sbuf[offset],"%s \n",typenames[(int) mybuf[m]]); + offset += snprintf(&sbuf[offset],maxsize,"%s \n",typenames[(int) mybuf[m]]); } else if (j >= 2) { if (vtype[j] == Dump::INT) - offset += sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); else if (vtype[j] == Dump::DOUBLE) - offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],mybuf[m]); else if (vtype[j] == Dump::STRING) - offset += sprintf(&sbuf[offset],vformat[j],typenames[(int) mybuf[m]]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],typenames[(int) mybuf[m]]); else if (vtype[j] == Dump::BIGINT) - offset += sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); } m++; } - offset += sprintf(&sbuf[offset],"\n"); + offset += snprintf(&sbuf[offset],maxsbuf-offset,"\n"); } } else if (unwrapflag == 1) { @@ -195,29 +196,30 @@ int DumpCFG::convert_string(int n, double *mybuf) } for (j = 0; j < size_one; j++) { + const auto maxsize = maxsbuf - offset; if (j == 0) { - offset += sprintf(&sbuf[offset],"%f \n",mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,"%f \n",mybuf[m]); } else if (j == 1) { - offset += sprintf(&sbuf[offset],"%s \n",typenames[(int) mybuf[m]]); + offset += snprintf(&sbuf[offset],maxsize,"%s \n",typenames[(int) mybuf[m]]); } else if (j >= 2 && j <= 4) { unwrap_coord = (mybuf[m] - 0.5)/UNWRAPEXPAND + 0.5; - offset += sprintf(&sbuf[offset],vformat[j],unwrap_coord); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],unwrap_coord); } else if (j >= 5) { if (vtype[j] == Dump::INT) offset += - sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); else if (vtype[j] == Dump::DOUBLE) - offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],mybuf[m]); else if (vtype[j] == Dump::STRING) offset += - sprintf(&sbuf[offset],vformat[j],typenames[(int) mybuf[m]]); + snprintf(&sbuf[offset],maxsize,vformat[j],typenames[(int) mybuf[m]]); else if (vtype[j] == Dump::BIGINT) offset += - sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); } m++; } - offset += sprintf(&sbuf[offset],"\n"); + offset += snprintf(&sbuf[offset],maxsbuf - offset,"\n"); } } diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index abdc46c55a..fdba2e5477 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -1358,20 +1358,21 @@ int DumpCustom::convert_string(int n, double *mybuf) } for (j = 0; j < nfield; j++) { + const auto maxsize = maxsbuf - offset; if (vtype[j] == Dump::INT) - offset += sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); else if (vtype[j] == Dump::DOUBLE) - offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],mybuf[m]); else if (vtype[j] == Dump::STRING) - offset += sprintf(&sbuf[offset],vformat[j],typenames[(int) mybuf[m]]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],typenames[(int) mybuf[m]]); else if (vtype[j] == Dump::STRING2) - offset += sprintf(&sbuf[offset],vformat[j],atom->lmap->typelabel[(int) mybuf[m]-1].c_str()); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],atom->lmap->typelabel[(int) mybuf[m]-1].c_str()); else if (vtype[j] == Dump::BIGINT) - offset += sprintf(&sbuf[offset],vformat[j], + offset += snprintf(&sbuf[offset],maxsize,vformat[j], static_cast (mybuf[m])); m++; } - offset += sprintf(&sbuf[offset],"\n"); + offset += snprintf(&sbuf[offset],maxsbuf-offset,"\n"); } return offset; @@ -1909,9 +1910,9 @@ int DumpCustom::modify_param(int narg, char **arg) if (ptr == nullptr) error->all(FLERR,"Dump_modify int format does not contain d character"); char str[8]; - sprintf(str,"%s",BIGINT_FORMAT); + snprintf(str,8,"%s",BIGINT_FORMAT); *ptr = '\0'; - sprintf(format_bigint_user,"%s%s%s",format_int_user,&str[1],ptr+1); + snprintf(format_bigint_user,n,"%s%s%s",format_int_user,&str[1],ptr+1); *ptr = 'd'; } else if (strcmp(arg[1],"float") == 0) { diff --git a/src/dump_grid.cpp b/src/dump_grid.cpp index ac42a85b01..b052712e95 100644 --- a/src/dump_grid.cpp +++ b/src/dump_grid.cpp @@ -590,15 +590,16 @@ int DumpGrid::convert_string(int n, double *mybuf) } for (j = 0; j < nfield; j++) { + const auto maxsize = maxsbuf - offset; if (vtype[j] == Dump::INT) - offset += sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); else if (vtype[j] == Dump::DOUBLE) - offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],mybuf[m]); else if (vtype[j] == Dump::BIGINT) - offset += sprintf(&sbuf[offset],vformat[j], static_cast (mybuf[m])); + offset += snprintf(&sbuf[offset],maxsize,vformat[j], static_cast (mybuf[m])); m++; } - offset += sprintf(&sbuf[offset],"\n"); + offset += snprintf(&sbuf[offset],maxsbuf-offset,"\n"); } return offset; @@ -776,9 +777,9 @@ int DumpGrid::modify_param(int narg, char **arg) if (ptr == nullptr) error->all(FLERR,"Dump_modify int format does not contain d character"); char str[8]; - sprintf(str,"%s",BIGINT_FORMAT); + snprintf(str,8,"%s",BIGINT_FORMAT); *ptr = '\0'; - sprintf(format_bigint_user,"%s%s%s",format_int_user,&str[1],ptr+1); + snprintf(format_bigint_user,n,"%s%s%s",format_int_user,&str[1],ptr+1); *ptr = 'd'; } else if (strcmp(arg[1],"float") == 0) { diff --git a/src/dump_local.cpp b/src/dump_local.cpp index 8d546634b6..bcf2a3a757 100644 --- a/src/dump_local.cpp +++ b/src/dump_local.cpp @@ -264,9 +264,9 @@ int DumpLocal::modify_param(int narg, char **arg) if (ptr == nullptr) error->all(FLERR, "Dump_modify int format does not contain d character"); char str[8]; - sprintf(str,"%s",BIGINT_FORMAT); + snprintf(str,8,"%s",BIGINT_FORMAT); *ptr = '\0'; - sprintf(format_bigint_user,"%s%s%s",format_int_user,&str[1],ptr+1); + snprintf(format_bigint_user,n,"%s%s%s",format_int_user,&str[1],ptr+1); *ptr = 'd'; } else if (strcmp(arg[1],"float") == 0) { @@ -387,17 +387,18 @@ int DumpLocal::convert_string(int n, double *mybuf) } for (j = 0; j < size_one; j++) { + const auto maxsize = maxsbuf - offset; if (vtype[j] == Dump::INT) - offset += sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); else if (vtype[j] == Dump::DOUBLE) - offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],mybuf[m]); else if (vtype[j] == Dump::BIGINT) - offset += sprintf(&sbuf[offset],vformat[j],static_cast (mybuf[m])); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],static_cast (mybuf[m])); else - offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]); + offset += snprintf(&sbuf[offset],maxsize,vformat[j],mybuf[m]); m++; } - offset += sprintf(&sbuf[offset],"\n"); + offset += snprintf(&sbuf[offset],maxsbuf-offset,"\n"); } return offset; diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index 018fa754d7..84a8ead6fd 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -85,7 +85,7 @@ void DumpXYZ::init_style() typenames = new char*[ntypes+1]; for (int itype = 1; itype <= ntypes; itype++) { typenames[itype] = new char[12]; - sprintf(typenames[itype],"%d",itype); + snprintf(typenames[itype],12,"%d",itype); } } @@ -206,7 +206,7 @@ int DumpXYZ::convert_string(int n, double *mybuf) memory->grow(sbuf,maxsbuf,"dump:sbuf"); } - offset += sprintf(&sbuf[offset], format, typenames[static_cast (mybuf[m+1])], + offset += snprintf(&sbuf[offset], maxsbuf-offset, format, typenames[static_cast (mybuf[m+1])], mybuf[m+2], mybuf[m+3], mybuf[m+4]); m += size_one; } diff --git a/src/variable.cpp b/src/variable.cpp index 823a68a506..f308ed6efc 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -1025,7 +1025,7 @@ char *Variable::retrieve(const char *name) error->all(FLERR, "Variable {}: format variable {} has incompatible style", names[ivar],data[ivar][0]); double answer = compute_equal(jvar); - sprintf(data[ivar][2],data[ivar][1],answer); + snprintf(data[ivar][2],VALUELENGTH,data[ivar][1],answer); str = data[ivar][2]; } else if (style[ivar] == GETENV) { diff --git a/unittest/fortran/wrap_extract_variable.cpp b/unittest/fortran/wrap_extract_variable.cpp index b1f79e149a..cf8b3bd5c0 100644 --- a/unittest/fortran/wrap_extract_variable.cpp +++ b/unittest/fortran/wrap_extract_variable.cpp @@ -121,7 +121,7 @@ TEST_F(LAMMPS_extract_variable, loop_pad) char str[10]; char *fstr; for (i = 1; i <= 10; i++) { - std::sprintf(str, "%02d", i); + std::snprintf(str, 10, "%02d", i); fstr = f_lammps_extract_variable_loop_pad(); EXPECT_STREQ(fstr, str); std::free(fstr); @@ -170,7 +170,7 @@ TEST_F(LAMMPS_extract_variable, format) char str[16]; char *fstr; for (i = 1; i <= 10; i++) { - std::sprintf(str, "%.6G", std::exp(i)); + std::snprintf(str, 16, "%.6G", std::exp(i)); fstr = f_lammps_extract_variable_format(); EXPECT_STREQ(fstr, str); std::free(fstr); @@ -185,7 +185,7 @@ TEST_F(LAMMPS_extract_variable, format_pad) char str[16]; char *fstr; for (i = 1; i <= 10; i++) { - std::sprintf(str, "%08.6G", std::exp(i)); + std::snprintf(str, 16, "%08.6G", std::exp(i)); fstr = f_lammps_extract_variable_format_pad(); EXPECT_STREQ(fstr, str); std::free(fstr); From fb9a36c2f4a7f820408f5c8af89c340190db968b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 13 Jul 2024 19:12:46 -0400 Subject: [PATCH 214/385] do not update the chart window when LAMMPS is not in a minimization or run --- tools/lammps-gui/lammpsgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 1d132003b2..578cdb3876 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -811,8 +811,8 @@ void LammpsGui::logupdate() step = (int)*(int64_t *)ptr; } - // extract cached thermo data - if (chartwindow) { + // extract cached thermo data when LAMMPS is executing a minimize or run command + if (chartwindow && lammps.is_running()) { // thermo data is not yet valid during setup void *ptr = lammps.last_thermo("setup", 0); if (ptr && *(int *)ptr) return; From 970f518939d0f31fb1d0dd1ee5670d961ae2e08d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 06:25:03 -0400 Subject: [PATCH 215/385] avoid out of range access --- tools/lammps-gui/chartviewer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/lammps-gui/chartviewer.cpp b/tools/lammps-gui/chartviewer.cpp index 919a3bf5fe..22f8e2f32b 100644 --- a/tools/lammps-gui/chartviewer.cpp +++ b/tools/lammps-gui/chartviewer.cpp @@ -138,7 +138,8 @@ void ChartWindow::quit() void ChartWindow::reset_zoom() { int choice = columns->currentData().toInt(); - charts[choice]->reset_zoom(); + if ((choice >= 0) && (choice < charts.size())) + charts[choice]->reset_zoom(); } void ChartWindow::stop_run() From 6fedb6a1b8d94c4eb0c66ce3746479134d6bab84 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 06:48:21 -0400 Subject: [PATCH 216/385] fix compilation issue with latest QUIP/libAtoms code --- cmake/Modules/Packages/ML-QUIP.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/ML-QUIP.cmake b/cmake/Modules/Packages/ML-QUIP.cmake index 5cb5a0967e..9106ff54ef 100644 --- a/cmake/Modules/Packages/ML-QUIP.cmake +++ b/cmake/Modules/Packages/ML-QUIP.cmake @@ -27,7 +27,7 @@ if(DOWNLOAD_QUIP) else() message(FATAL_ERROR "The ${CMAKE_Fortran_COMPILER_ID} Fortran compiler is not (yet) supported for building QUIP") endif() - set(temp "${temp}CFLAGS += -fPIC \nCPLUSPLUSFLAGS += -fPIC\nAR_ADD=src\n") + set(temp "${temp}CFLAGS += -fPIC -Wno-return-mismatch \nCPLUSPLUSFLAGS += -fPIC -Wno-return-mismatch\nAR_ADD=src\n") set(temp "${temp}MATH_LINKOPTS=") foreach(flag ${BLAS_LIBRARIES}) set(temp "${temp} ${flag}") From acd7bd111d833a5109f77d42bca5ee76b001aab8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 06:51:58 -0400 Subject: [PATCH 217/385] remove dead code --- src/REAXFF/fix_reaxff_bonds.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/REAXFF/fix_reaxff_bonds.h b/src/REAXFF/fix_reaxff_bonds.h index 2316bfe171..f36c2c718e 100644 --- a/src/REAXFF/fix_reaxff_bonds.h +++ b/src/REAXFF/fix_reaxff_bonds.h @@ -50,7 +50,6 @@ class FixReaxFFBonds : public Fix { int nint(const double &); double memory_usage() override; - bigint nvalid, nextvalid(); struct _reax_list *lists; class PairReaxFF *reaxff; class NeighList *list; From 1d6959efe637c16df96bd9f860979cde4b8f426b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 06:57:37 -0400 Subject: [PATCH 218/385] only print fix reaxff/bonds output during setup the first time --- src/REAXFF/fix_reaxff_bonds.cpp | 6 +++++- src/REAXFF/fix_reaxff_bonds.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/REAXFF/fix_reaxff_bonds.cpp b/src/REAXFF/fix_reaxff_bonds.cpp index 653f207e90..a5ce478c1d 100644 --- a/src/REAXFF/fix_reaxff_bonds.cpp +++ b/src/REAXFF/fix_reaxff_bonds.cpp @@ -44,6 +44,7 @@ FixReaxFFBonds::FixReaxFFBonds(LAMMPS *lmp, int narg, char **arg) : ntypes = atom->ntypes; nmax = atom->nmax; compressed = 0; + first_flag = true; nevery = utils::inumeric(FLERR,arg[3],false,lmp); @@ -94,7 +95,10 @@ int FixReaxFFBonds::setmask() void FixReaxFFBonds::setup(int /*vflag*/) { - end_of_step(); + // only print output during setup() at the very beginning + // to avoid duplicate outputs when using multiple run statements + if (first_flag) end_of_step(); + first_flag = false; } /* ---------------------------------------------------------------------- */ diff --git a/src/REAXFF/fix_reaxff_bonds.h b/src/REAXFF/fix_reaxff_bonds.h index f36c2c718e..91ce2531bf 100644 --- a/src/REAXFF/fix_reaxff_bonds.h +++ b/src/REAXFF/fix_reaxff_bonds.h @@ -40,6 +40,7 @@ class FixReaxFFBonds : public Fix { tagint **neighid; double **abo; FILE *fp; + bool first_flag; void allocate(); void destroy(); From 1fe1aa06830d5655b9d150f1c8ee22ad76a62939 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 10:28:22 -0400 Subject: [PATCH 219/385] lower default update interval to 10ms --- doc/src/Howto_lammps_gui.rst | 7 ++++--- tools/lammps-gui/lammpsgui.cpp | 2 +- tools/lammps-gui/preferences.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/src/Howto_lammps_gui.rst b/doc/src/Howto_lammps_gui.rst index 165ed84d95..6faac96ce9 100644 --- a/doc/src/Howto_lammps_gui.rst +++ b/doc/src/Howto_lammps_gui.rst @@ -571,11 +571,12 @@ General Settings: size for the text editor and log font of the application can be set. - *GUI update interval:* Allows to set the time interval between GUI and data updates during a LAMMPS run in milliseconds. The default is - to update the GUI every 100 milliseconds. This is good for most cases. - For LAMMPS runs that run very fast, however, data may be missed and + to update the GUI every 10 milliseconds. This is good for most cases. + For LAMMPS runs that run *very* fast, however, data may be missed and through lowering this interval, this can be corrected. However, this will make the GUI use more resources, which may be a problem on some - computers with slower CPUs. The default value is 100 milliseconds. + computers with slower CPUs and a small number of CPU cores. This + setting may be changed to a value between 1 and 1000 milliseconds. Accelerators: ^^^^^^^^^^^^^ diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 578cdb3876..c2000c8969 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -1088,7 +1088,7 @@ void LammpsGui::do_run(bool use_buffer) logupdater = new QTimer(this); connect(logupdater, &QTimer::timeout, this, &LammpsGui::logupdate); - logupdater->start(settings.value("updfreq", "100").toInt()); + logupdater->start(settings.value("updfreq", "10").toInt()); } void LammpsGui::render_image() diff --git a/tools/lammps-gui/preferences.cpp b/tools/lammps-gui/preferences.cpp index 71910346fb..426f2306ea 100644 --- a/tools/lammps-gui/preferences.cpp +++ b/tools/lammps-gui/preferences.cpp @@ -260,7 +260,7 @@ GeneralTab::GeneralTab(QSettings *_settings, LammpsWrapper *_lammps, QWidget *pa auto *freqval = new QSpinBox; freqval->setRange(1, 1000); freqval->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType); - freqval->setValue(settings->value("updfreq", "100").toInt()); + freqval->setValue(settings->value("updfreq", "10").toInt()); freqval->setObjectName("updfreq"); freqlayout->addWidget(freqlabel); freqlayout->addWidget(freqval); From 7cfc34e45d13cba41fa85fb55ab45d3fe4cb95a8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 14:08:19 -0400 Subject: [PATCH 220/385] the source_suffix option is supposed to be a map --- doc/utils/sphinx-config/conf.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/utils/sphinx-config/conf.py.in b/doc/utils/sphinx-config/conf.py.in index 337485e689..4dda51b09c 100644 --- a/doc/utils/sphinx-config/conf.py.in +++ b/doc/utils/sphinx-config/conf.py.in @@ -69,7 +69,7 @@ images_config = { templates_path = ['_templates'] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = {'.rst': 'restructuredtext'} # The encoding of source files. #source_encoding = 'utf-8-sig' From 6f8bedd01c852225ea73dcbfdf00eeedef6198ee Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 14:14:13 -0400 Subject: [PATCH 221/385] sync minimum sphinx version with requirements file --- doc/utils/sphinx-config/conf.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/utils/sphinx-config/conf.py.in b/doc/utils/sphinx-config/conf.py.in index 4dda51b09c..e2451cd4f1 100644 --- a/doc/utils/sphinx-config/conf.py.in +++ b/doc/utils/sphinx-config/conf.py.in @@ -41,7 +41,7 @@ sys.path.append(os.path.join(LAMMPS_DOC_DIR, 'utils', 'sphinx-config', '_themes' # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = '5.2.0' +needs_sphinx = '5.3.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom From d7792956d6d3c3b8f2dc417a5584a3fdf4672d09 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sun, 14 Jul 2024 14:19:57 -0600 Subject: [PATCH 222/385] bugfix for unittest/fortran/wrap_configuration.cpp --- unittest/fortran/wrap_configuration.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittest/fortran/wrap_configuration.cpp b/unittest/fortran/wrap_configuration.cpp index 0161a80125..91a10d0687 100644 --- a/unittest/fortran/wrap_configuration.cpp +++ b/unittest/fortran/wrap_configuration.cpp @@ -39,7 +39,7 @@ int f_lammps_has_id(const char *, const char *); int f_lammps_id_count(const char *); char *f_lammps_id_name(const char *, int); int f_lammps_plugin_count(); -int f_lammps_plugin_name(); +int f_lammps_plugin_name(int, const char*, const char*); } namespace LAMMPS_NS { @@ -347,7 +347,7 @@ TEST_F(LAMMPS_configuration, plugins) #else int nplugins = f_lammps_plugin_count(); for (int n = 0; n < nplugins; n++) { - lammpsplugin_t *plugin = plugin_get_info(n); + auto *plugin = plugin_get_info(n); EXPECT_EQ(f_lammps_plugin_name(n + 1, plugin->style, plugin->name), 1); } #endif From 207d1e20b9b92dd5c53d7c161b5f8d5825f0bb5a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 18:23:59 -0400 Subject: [PATCH 223/385] warn about problematic compiler versions and C++ standard combinations --- cmake/CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c6cb09f325..ea559ee926 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -164,6 +164,22 @@ if(MSVC) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() +# warn about potentially problematic GCC compiler versions +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if (CMAKE_CXX_STANDARD GREATER_EQUAL 17) + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) + message(WARNING "Using ${CMAKE_CXX_COMPILER_ID} compiler version ${CMAKE_CXX_COMPILER_VERSION} " + "with C++17 is not recommended. Please use ${CMAKE_CXX_COMPILER_ID} compiler version 9.x or later") + endif() + endif() + if (CMAKE_CXX_STANDARD GREATER_EQUAL 11) + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) + message(WARNING "Using ${CMAKE_CXX_COMPILER_ID} compiler version ${CMAKE_CXX_COMPILER_VERSION} " + "with C++11 is not recommended. Please use ${CMAKE_CXX_COMPILER_ID} compiler version 5.x or later") + endif() + endif() +endif() + # export all symbols when building a .dll file on windows if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND BUILD_SHARED_LIBS) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) From 1b5c42e1b7b4b639340e970b550a5b921a61aa1c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 15 Jul 2024 18:48:18 -0400 Subject: [PATCH 224/385] add shortcut button for save buffer --- tools/lammps-gui/lammpsgui.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index c2000c8969..952be3c7da 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -239,15 +239,19 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) : lammpsstatus->setToolTip("LAMMPS instance is active"); lammpsstatus->hide(); + auto *lammpssave = new QPushButton(QIcon(":/icons/document-save.png"), ""); auto *lammpsrun = new QPushButton(QIcon(":/icons/system-run.png"), ""); auto *lammpsstop = new QPushButton(QIcon(":/icons/process-stop.png"), ""); auto *lammpsimage = new QPushButton(QIcon(":/icons/emblem-photos.png"), ""); + lammpssave->setToolTip("Save edit buffer to file"); lammpsrun->setToolTip("Run LAMMPS on input"); lammpsstop->setToolTip("Stop LAMMPS"); lammpsimage->setToolTip("Create snapshot image"); + ui->statusbar->addWidget(lammpssave); ui->statusbar->addWidget(lammpsrun); ui->statusbar->addWidget(lammpsstop); ui->statusbar->addWidget(lammpsimage); + connect(lammpssave, &QPushButton::released, this, &LammpsGui::save); connect(lammpsrun, &QPushButton::released, this, &LammpsGui::run_buffer); connect(lammpsstop, &QPushButton::released, this, &LammpsGui::stop_run); connect(lammpsimage, &QPushButton::released, this, &LammpsGui::render_image); @@ -854,7 +858,7 @@ void LammpsGui::logupdate() for (int i = 0; i < ncols; ++i) { int datatype = -1; double data = 0.0; - void *ptr = lammps.last_thermo("type", i); + void *ptr = lammps.last_thermo("type", i); if (ptr) datatype = *(int *)ptr; ptr = lammps.last_thermo("data", i); if (ptr) { @@ -1243,8 +1247,8 @@ void LammpsGui::about() font.setPointSizeF(font.pointSizeF() * 0.75); msg.setFont(font); - auto *minwidth = new QSpacerItem(700, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); - auto *layout = (QGridLayout *)msg.layout(); + auto *minwidth = new QSpacerItem(700, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + auto *layout = (QGridLayout *)msg.layout(); layout->addItem(minwidth, layout->rowCount(), 0, 1, layout->columnCount()); msg.exec(); From a9a896c6779317fb6bbbfc5313085da6861ea12b Mon Sep 17 00:00:00 2001 From: jtclemm Date: Mon, 15 Jul 2024 17:19:51 -0600 Subject: [PATCH 225/385] Small doc changes, renaming status variable --- doc/src/Howto_rheo.rst | 33 ++++++++++++----------- examples/rheo/oxidation/in.rheo.oxidation | 3 +-- src/RHEO/atom_vec_rheo.cpp | 28 +++++++++---------- src/RHEO/atom_vec_rheo.h | 2 +- src/RHEO/atom_vec_rheo_thermal.cpp | 28 +++++++++---------- src/RHEO/atom_vec_rheo_thermal.h | 2 +- src/RHEO/bond_rheo_shell.cpp | 2 +- src/RHEO/compute_rheo_grad.cpp | 2 +- src/RHEO/compute_rheo_interface.cpp | 4 +-- src/RHEO/compute_rheo_kernel.cpp | 2 +- src/RHEO/compute_rheo_property_atom.cpp | 32 ++++++---------------- src/RHEO/compute_rheo_property_atom.h | 3 +-- src/RHEO/compute_rheo_surface.cpp | 10 +++---- src/RHEO/compute_rheo_vshift.cpp | 4 +-- src/RHEO/fix_rheo.cpp | 10 +++---- src/RHEO/fix_rheo_oxidation.cpp | 4 +-- src/RHEO/fix_rheo_thermal.cpp | 16 +++++------ src/RHEO/pair_rheo.cpp | 2 +- src/RHEO/pair_rheo_solid.cpp | 6 ++--- src/atom.cpp | 10 +++---- src/atom.h | 4 +-- src/set.cpp | 4 +-- 22 files changed, 97 insertions(+), 114 deletions(-) diff --git a/doc/src/Howto_rheo.rst b/doc/src/Howto_rheo.rst index 7c62d09ab1..34c0f7b6a1 100644 --- a/doc/src/Howto_rheo.rst +++ b/doc/src/Howto_rheo.rst @@ -2,25 +2,26 @@ Reproducing hydrodynamics and elastic objects (RHEO) ==================================================== The RHEO package is a hybrid implementation of smoothed particle -hydrodynamics (SPH) for fluid flow, coupled to the :doc:`BPM package ` -to model solid elements. RHEO combines these methods to enable mesh-free modeling -of multi-phase material systems. The SPH solver supports many advanced options -including reproducing kernels, particle shifting, free surface identification, -and solid surface reconstruction. To model fluid-solid systems, the status of -particles can dynamically change between a fluid and solid state, e.g. during -melting/solidification, which determines how they interact and their physical -behavior. The package is designed with modularity in mind, so one can easily -turn various features on/off, adjust physical details of the system, or -develop new capabilities. For instance, the numerics associated with -calculating gradients, reproducing kernels, etc. are separated into distinct -classes to simplify the development of new integration schemes which can call -these calculations. Additional numerical details can be found in +hydrodynamics (SPH) for fluid flow, which can couple to the :doc:`BPM package +` to model solid elements. RHEO combines these methods to enable +mesh-free modeling of multi-phase material systems. Its SPH solver supports +many advanced options including reproducing kernels, particle shifting, free +surface identification, and solid surface reconstruction. To model fluid-solid +systems, the status of particles can dynamically change between a fluid and +solid state, e.g. during melting/solidification, which determines how they +interact and their physical behavior. The package is designed with modularity +in mind, so one can easily turn various features on/off, adjust physical +details of the system, or develop new capabilities. For instance, the numerics +associated with calculating gradients, reproducing kernels, etc. are separated +into distinctclasses to simplify the development of new integration schemes +which can call these calculations. Additional numerical details can be found in :ref:`(Palermo) ` and :ref:`(Clemmer) `. -Note, if you simply want to run a traditional SPH simulation, the SPH package -is likely better suited for your application. It has fewer advanced features -and therefore benefits from improved performance. +Note, if you simply want to run a traditional SPH simulation, the :ref:`SPH package +` package is likely better suited for your application. It has fewer advanced +features and therefore benefits from improved performance. The :ref:`MACHDYN +` package for solids may also be relevant for fluid-solid problems. ---------- diff --git a/examples/rheo/oxidation/in.rheo.oxidation b/examples/rheo/oxidation/in.rheo.oxidation index d8b4b1a464..57bd71b917 100644 --- a/examples/rheo/oxidation/in.rheo.oxidation +++ b/examples/rheo/oxidation/in.rheo.oxidation @@ -87,7 +87,6 @@ fix 11 all enforce2d compute surf all rheo/property/atom surface compute rho all rheo/property/atom rho compute phase all rheo/property/atom phase -compute status all rheo/property/atom status compute temp all rheo/property/atom temperature compute eng all rheo/property/atom energy compute nbond_shell all rheo/property/atom nbond/shell @@ -98,6 +97,6 @@ compute nbond_solid all nbond/atom bond/type 1 thermo 200 thermo_style custom step time ke press atoms -#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond_solid c_nbond_shell c_rho c_surf c_status +#dump 1 all custom 200 atomDump id type x y vx vy fx fy c_phase c_temp c_eng c_nbond_solid c_nbond_shell c_rho c_surf run 40000 diff --git a/src/RHEO/atom_vec_rheo.cpp b/src/RHEO/atom_vec_rheo.cpp index 92f5ca05a4..0cbebff008 100644 --- a/src/RHEO/atom_vec_rheo.cpp +++ b/src/RHEO/atom_vec_rheo.cpp @@ -33,7 +33,7 @@ AtomVecRHEO::AtomVecRHEO(LAMMPS *lmp) : AtomVec(lmp) mass_type = PER_TYPE; forceclearflag = 1; - atom->status_flag = 1; + atom->rheo_status_flag = 1; atom->pressure_flag = 1; atom->rho_flag = 1; atom->viscosity_flag = 1; @@ -43,17 +43,17 @@ AtomVecRHEO::AtomVecRHEO(LAMMPS *lmp) : AtomVec(lmp) // order of fields in a string does not matter // except: fields_data_atom & fields_data_vel must match data file - fields_grow = {"status", "rho", "drho", "pressure", "viscosity"}; - fields_copy = {"status", "rho", "drho", "pressure", "viscosity"}; - fields_comm = {"status", "rho"}; - fields_comm_vel = {"status", "rho"}; + fields_grow = {"rheo_status", "rho", "drho", "pressure", "viscosity"}; + fields_copy = {"rheo_status", "rho", "drho", "pressure", "viscosity"}; + fields_comm = {"rheo_status", "rho"}; + fields_comm_vel = {"rheo_status", "rho"}; fields_reverse = {"drho"}; - fields_border = {"status", "rho"}; - fields_border_vel = {"status", "rho"}; - fields_exchange = {"status", "rho"}; - fields_restart = {"status", "rho"}; - fields_create = {"status", "rho", "drho", "pressure", "viscosity"}; - fields_data_atom = {"id", "type", "status", "rho", "x"}; + fields_border = {"rheo_status", "rho"}; + fields_border_vel = {"rheo_status", "rho"}; + fields_exchange = {"rheo_status", "rho"}; + fields_restart = {"rheo_status", "rho"}; + fields_create = {"rheo_status", "rho", "drho", "pressure", "viscosity"}; + fields_data_atom = {"id", "type", "rheo_status", "rho", "x"}; fields_data_vel = {"id", "v"}; setup_fields(); @@ -66,7 +66,7 @@ AtomVecRHEO::AtomVecRHEO(LAMMPS *lmp) : AtomVec(lmp) void AtomVecRHEO::grow_pointers() { - status = atom->status; + rheo_status = atom->rheo_status; pressure = atom->pressure; rho = atom->rho; drho = atom->drho; @@ -111,7 +111,7 @@ void AtomVecRHEO::data_atom_post(int ilocal) int AtomVecRHEO::property_atom(const std::string &name) { - if (name == "status") return 0; + if (name == "rheo_status") return 0; if (name == "pressure") return 1; if (name == "rho") return 2; if (name == "drho") return 3; @@ -133,7 +133,7 @@ void AtomVecRHEO::pack_property_atom(int index, double *buf, int nvalues, int gr if (index == 0) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) - buf[n] = status[i]; + buf[n] = rheo_status[i]; else buf[n] = 0.0; n += nvalues; diff --git a/src/RHEO/atom_vec_rheo.h b/src/RHEO/atom_vec_rheo.h index 62a7b1a630..8eaa01f7be 100644 --- a/src/RHEO/atom_vec_rheo.h +++ b/src/RHEO/atom_vec_rheo.h @@ -36,7 +36,7 @@ class AtomVecRHEO : virtual public AtomVec { void pack_property_atom(int, double *, int, int) override; private: - int *status; + int *rheo_status; double *pressure, *rho, *drho, *viscosity; }; diff --git a/src/RHEO/atom_vec_rheo_thermal.cpp b/src/RHEO/atom_vec_rheo_thermal.cpp index f541e2a0cb..426c059570 100644 --- a/src/RHEO/atom_vec_rheo_thermal.cpp +++ b/src/RHEO/atom_vec_rheo_thermal.cpp @@ -33,7 +33,7 @@ AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) mass_type = PER_TYPE; forceclearflag = 1; - atom->status_flag = 1; + atom->rheo_status_flag = 1; atom->conductivity_flag = 1; atom->temperature_flag = 1; atom->esph_flag = 1; @@ -47,17 +47,17 @@ AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) // order of fields in a string does not matter // except: fields_data_atom & fields_data_vel must match data file - fields_grow = {"status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_copy = {"status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_comm = {"status", "rho", "esph"}; - fields_comm_vel = {"status", "rho", "esph"}; + fields_grow = {"rheo_status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_copy = {"rheo_status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_comm = {"rheo_status", "rho", "esph"}; + fields_comm_vel = {"rheo_status", "rho", "esph"}; fields_reverse = {"drho", "heatflow"}; - fields_border = {"status", "rho", "esph"}; - fields_border_vel = {"status", "rho", "esph"}; - fields_exchange = {"status", "rho", "esph"}; - fields_restart = {"status", "rho", "esph"}; - fields_create = {"status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; - fields_data_atom = {"id", "type", "status", "rho", "esph", "x"}; + fields_border = {"rheo_status", "rho", "esph"}; + fields_border_vel = {"rheo_status", "rho", "esph"}; + fields_exchange = {"rheo_status", "rho", "esph"}; + fields_restart = {"rheo_status", "rho", "esph"}; + fields_create = {"rheo_status", "rho", "drho", "temperature", "esph", "heatflow", "conductivity", "pressure", "viscosity"}; + fields_data_atom = {"id", "type", "rheo_status", "rho", "esph", "x"}; fields_data_vel = {"id", "v"}; setup_fields(); @@ -70,7 +70,7 @@ AtomVecRHEOThermal::AtomVecRHEOThermal(LAMMPS *lmp) : AtomVec(lmp) void AtomVecRHEOThermal::grow_pointers() { - status = atom->status; + rheo_status = atom->rheo_status; conductivity = atom->conductivity; temperature = atom->temperature; esph = atom->esph; @@ -123,7 +123,7 @@ void AtomVecRHEOThermal::data_atom_post(int ilocal) int AtomVecRHEOThermal::property_atom(const std::string &name) { - if (name == "status") return 0; + if (name == "rheo_status") return 0; if (name == "rho") return 1; if (name == "drho") return 2; if (name == "temperature") return 3; @@ -149,7 +149,7 @@ void AtomVecRHEOThermal::pack_property_atom(int index, double *buf, int nvalues, if (index == 0) { for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) - buf[n] = status[i]; + buf[n] = rheo_status[i]; else buf[n] = 0.0; n += nvalues; diff --git a/src/RHEO/atom_vec_rheo_thermal.h b/src/RHEO/atom_vec_rheo_thermal.h index 29a764bea9..eaf944ca96 100644 --- a/src/RHEO/atom_vec_rheo_thermal.h +++ b/src/RHEO/atom_vec_rheo_thermal.h @@ -36,7 +36,7 @@ class AtomVecRHEOThermal : virtual public AtomVec { void pack_property_atom(int, double *, int, int) override; private: - int *status; + int *rheo_status; double *conductivity, *temperature, *heatflow, *esph; double *pressure, *rho, *drho, *viscosity; }; diff --git a/src/RHEO/bond_rheo_shell.cpp b/src/RHEO/bond_rheo_shell.cpp index 81e5ba02d1..258d047086 100644 --- a/src/RHEO/bond_rheo_shell.cpp +++ b/src/RHEO/bond_rheo_shell.cpp @@ -182,7 +182,7 @@ void BondRHEOShell::compute(int eflag, int vflag) double **v = atom->v; double **f = atom->f; tagint *tag = atom->tag; - int *status = atom->status; + int *status = atom->rheo_status; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; diff --git a/src/RHEO/compute_rheo_grad.cpp b/src/RHEO/compute_rheo_grad.cpp index 216fcb1978..cdf90e1dc5 100644 --- a/src/RHEO/compute_rheo_grad.cpp +++ b/src/RHEO/compute_rheo_grad.cpp @@ -144,7 +144,7 @@ void ComputeRHEOGrad::compute_peratom() double *rho = atom->rho; double *energy = atom->esph; double *viscosity = atom->viscosity; - int *status = atom->status; + int *status = atom->rheo_status; int *type = atom->type; double *mass = atom->mass; int newton = force->newton; diff --git a/src/RHEO/compute_rheo_interface.cpp b/src/RHEO/compute_rheo_interface.cpp index ec8c10f276..8ccd4e6a3b 100644 --- a/src/RHEO/compute_rheo_interface.cpp +++ b/src/RHEO/compute_rheo_interface.cpp @@ -120,7 +120,7 @@ void ComputeRHEOInterface::compute_peratom() double **x = atom->x; int *type = atom->type; int newton = force->newton; - int *status = atom->status; + int *status = atom->rheo_status; double *rho = atom->rho; inum = list->inum; @@ -290,7 +290,7 @@ void ComputeRHEOInterface::unpack_reverse_comm(int n, int *list, double *buf) { int i, k, j, m; double *rho = atom->rho; - int *status = atom->status; + int *status = atom->rheo_status; m = 0; for (i = 0; i < n; i++) { j = list[i]; diff --git a/src/RHEO/compute_rheo_kernel.cpp b/src/RHEO/compute_rheo_kernel.cpp index a5865b894a..4558ddccc8 100644 --- a/src/RHEO/compute_rheo_kernel.cpp +++ b/src/RHEO/compute_rheo_kernel.cpp @@ -586,7 +586,7 @@ void ComputeRHEOKernel::compute_peratom() int *type = atom->type; double *mass = atom->mass; double *rho = atom->rho; - int *status = atom->status; + int *status = atom->rheo_status; tagint *tag = atom->tag; int *ilist, *jlist, *numneigh, **firstneigh; diff --git a/src/RHEO/compute_rheo_property_atom.cpp b/src/RHEO/compute_rheo_property_atom.cpp index 533822bbdd..7a450e7708 100644 --- a/src/RHEO/compute_rheo_property_atom.cpp +++ b/src/RHEO/compute_rheo_property_atom.cpp @@ -92,8 +92,9 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a for (int iarg = 3; iarg < narg; iarg++) { if (strcmp(arg[iarg], "phase") == 0) { pack_choice[i] = &ComputeRHEOPropertyAtom::pack_phase; - } else if (strcmp(arg[iarg], "rho") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_rho; + } else if (strcmp(arg[iarg], "status") == 0) { + // Short hand for "rheo_status" + pack_choice[i] = &ComputeRHEOPropertyAtom::pack_status; } else if (strcmp(arg[iarg], "chi") == 0) { interface_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_chi; @@ -111,8 +112,6 @@ ComputeRHEOPropertyAtom::ComputeRHEOPropertyAtom(LAMMPS *lmp, int narg, char **a } else if (strcmp(arg[iarg], "pressure") == 0) { pressure_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_pressure; - } else if (strcmp(arg[iarg], "viscosity") == 0) { - pack_choice[i] = &ComputeRHEOPropertyAtom::pack_viscosity; } else if (strcmp(arg[iarg], "cv") == 0) { thermal_flag = 1; pack_choice[i] = &ComputeRHEOPropertyAtom::pack_cv; @@ -265,7 +264,7 @@ double ComputeRHEOPropertyAtom::memory_usage() void ComputeRHEOPropertyAtom::pack_phase(int n) { - int *status = atom->status; + int *status = atom->rheo_status; int *mask = atom->mask; int nlocal = atom->nlocal; @@ -278,14 +277,14 @@ void ComputeRHEOPropertyAtom::pack_phase(int n) /* ---------------------------------------------------------------------- */ -void ComputeRHEOPropertyAtom::pack_rho(int n) +void ComputeRHEOPropertyAtom::pack_status(int n) { - double *rho = atom->rho; + int *status = atom->rheo_status; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = rho[i]; + if (mask[i] & groupbit) buf[n] = status[i]; else buf[n] = 0.0; n += nvalues; } @@ -310,7 +309,7 @@ void ComputeRHEOPropertyAtom::pack_chi(int n) void ComputeRHEOPropertyAtom::pack_surface(int n) { - int *status = atom->status; + int *status = atom->rheo_status; int *mask = atom->mask; int nlocal = atom->nlocal; @@ -420,21 +419,6 @@ void ComputeRHEOPropertyAtom::pack_pressure(int n) /* ---------------------------------------------------------------------- */ -void ComputeRHEOPropertyAtom::pack_viscosity(int n) -{ - int *mask = atom->mask; - double *viscosity = atom->viscosity; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (mask[i] & groupbit) buf[n] = viscosity[i]; - else buf[n] = 0.0; - n += nvalues; - } -} - -/* ---------------------------------------------------------------------- */ - void ComputeRHEOPropertyAtom::pack_viscous_stress(int n) { double **gradv = compute_grad->gradv; diff --git a/src/RHEO/compute_rheo_property_atom.h b/src/RHEO/compute_rheo_property_atom.h index b3d247b102..4b1ebf2313 100644 --- a/src/RHEO/compute_rheo_property_atom.h +++ b/src/RHEO/compute_rheo_property_atom.h @@ -45,7 +45,7 @@ class ComputeRHEOPropertyAtom : public Compute { FnPtrPack *pack_choice; // ptrs to pack functions void pack_phase(int); - void pack_rho(int); + void pack_status(int); void pack_chi(int); void pack_surface(int); void pack_surface_r(int); @@ -56,7 +56,6 @@ class ComputeRHEOPropertyAtom : public Compute { void pack_shift_v(int); void pack_gradv(int); void pack_pressure(int); - void pack_viscosity(int); void pack_viscous_stress(int); void pack_total_stress(int); void pack_nbond_shell(int); diff --git a/src/RHEO/compute_rheo_surface.cpp b/src/RHEO/compute_rheo_surface.cpp index 69b0ebd108..c3a3774cdc 100644 --- a/src/RHEO/compute_rheo_surface.cpp +++ b/src/RHEO/compute_rheo_surface.cpp @@ -106,7 +106,7 @@ void ComputeRHEOSurface::compute_peratom() int nlocal = atom->nlocal; double **x = atom->x; - int *status = atom->status; + int *status = atom->rheo_status; int newton = force->newton; int dim = domain->dimension; int *mask = atom->mask; @@ -312,7 +312,7 @@ int ComputeRHEOSurface::pack_reverse_comm(int n, int first, double *buf) { int i,a,b,k,m,last; int dim = domain->dimension; - int *status = atom->status; + int *status = atom->rheo_status; m = 0; last = first + n; @@ -336,7 +336,7 @@ void ComputeRHEOSurface::unpack_reverse_comm(int n, int *list, double *buf) { int i,a,b,k,j,m; int dim = domain->dimension; - int *status = atom->status; + int *status = atom->rheo_status; int tmp1; double tmp2; @@ -367,7 +367,7 @@ int ComputeRHEOSurface::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j,a,b,k,m; - int *status = atom->status; + int *status = atom->rheo_status; m = 0; for (i = 0; i < n; i++) { @@ -387,7 +387,7 @@ int ComputeRHEOSurface::pack_forward_comm(int n, int *list, double *buf, void ComputeRHEOSurface::unpack_forward_comm(int n, int first, double *buf) { int i, k, a, b, m, last; - int *status = atom->status; + int *status = atom->rheo_status; m = 0; last = first + n; diff --git a/src/RHEO/compute_rheo_vshift.cpp b/src/RHEO/compute_rheo_vshift.cpp index b01912111f..c06ef533ac 100644 --- a/src/RHEO/compute_rheo_vshift.cpp +++ b/src/RHEO/compute_rheo_vshift.cpp @@ -102,7 +102,7 @@ void ComputeRHEOVShift::compute_peratom() int inum, *ilist, *numneigh, **firstneigh; int *type = atom->type; - int *status = atom->status; + int *status = atom->rheo_status; int *mask = atom->mask; double **x = atom->x; double **v = atom->v; @@ -231,7 +231,7 @@ void ComputeRHEOVShift::correct_surfaces() int i, a, b; - int *status = atom->status; + int *status = atom->rheo_status; int *mask = atom->mask; double **nsurface = compute_surface->nsurface; diff --git a/src/RHEO/fix_rheo.cpp b/src/RHEO/fix_rheo.cpp index cd0ca1069a..f70b9e121f 100644 --- a/src/RHEO/fix_rheo.cpp +++ b/src/RHEO/fix_rheo.cpp @@ -86,7 +86,7 @@ FixRHEO::FixRHEO(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR, "fix rheo command requires atom_style with density"); if (atom->viscosity_flag != 1) error->all(FLERR, "fix rheo command requires atom_style with viscosity"); - if (atom->status_flag != 1) + if (atom->rheo_status_flag != 1) error->all(FLERR, "fix rheo command requires atom_style with status"); if (narg < 5) @@ -235,7 +235,7 @@ void FixRHEO::init() if (modify->get_fix_by_style("^rheo$").size() > 1) error->all(FLERR, "Can only specify one instance of fix rheo"); - if (atom->status_flag != 1) + if (atom->rheo_status_flag != 1) error->all(FLERR,"fix rheo command requires atom property status"); if (atom->rho_flag != 1) error->all(FLERR,"fix rheo command requires atom property rho"); @@ -309,7 +309,7 @@ void FixRHEO::initial_integrate(int /*vflag*/) int *type = atom->type; int *mask = atom->mask; - int *status = atom->status; + int *status = atom->rheo_status; double **x = atom->x; double **v = atom->v; double **f = atom->f; @@ -432,7 +432,7 @@ void FixRHEO::pre_force(int /*vflag*/) // Remove temporary options int *mask = atom->mask; - int *status = atom->status; + int *status = atom->rheo_status; int nall = atom->nlocal + atom->nghost; for (int i = 0; i < nall; i++) if (mask[i] & groupbit) @@ -467,7 +467,7 @@ void FixRHEO::final_integrate() double *rmass = atom->rmass; int *type = atom->type; int *mask = atom->mask; - int *status = atom->status; + int *status = atom->rheo_status; int rmass_flag = atom->rmass_flag; int dim = domain->dimension; diff --git a/src/RHEO/fix_rheo_oxidation.cpp b/src/RHEO/fix_rheo_oxidation.cpp index 74d1bbab57..a51f2feb95 100644 --- a/src/RHEO/fix_rheo_oxidation.cpp +++ b/src/RHEO/fix_rheo_oxidation.cpp @@ -163,7 +163,7 @@ void FixRHEOOxidation::post_integrate() int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; int *mask = atom->mask; - int *status = atom->status; + int *status = atom->rheo_status; double *rsurface = compute_surface->rsurface; double **x = atom->x; @@ -255,7 +255,7 @@ void FixRHEOOxidation::post_integrate() void FixRHEOOxidation::post_force(int /*vflag*/) { - int *status = atom->status; + int *status = atom->rheo_status; int *num_bond = atom->num_bond; for (int i = 0; i < atom->nlocal; i++) if (num_bond[i] != 0) diff --git a/src/RHEO/fix_rheo_thermal.cpp b/src/RHEO/fix_rheo_thermal.cpp index dbb59f12f7..daa5b347a7 100644 --- a/src/RHEO/fix_rheo_thermal.cpp +++ b/src/RHEO/fix_rheo_thermal.cpp @@ -326,7 +326,7 @@ void FixRHEOThermal::initial_integrate(int /*vflag*/) if (!fix_rheo->shift_flag) return; int i, a; - int *status = atom->status; + int *status = atom->rheo_status; double *energy = atom->esph; double **grade = compute_grad->grade; double **vshift = compute_vshift->vshift; @@ -351,7 +351,7 @@ void FixRHEOThermal::post_integrate() int i, itype; double cvi, Tci, Ti, Li; - int *status = atom->status; + int *status = atom->rheo_status; double *energy = atom->esph; double *temperature = atom->temperature; double *heatflow = atom->heatflow; @@ -466,7 +466,7 @@ void FixRHEOThermal::pre_force(int /*vflag*/) double *energy = atom->esph; double *temperature = atom->temperature; int *type = atom->type; - int *status = atom->status; + int *status = atom->rheo_status; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; @@ -494,7 +494,7 @@ void FixRHEOThermal::pre_force(int /*vflag*/) void FixRHEOThermal::final_integrate() { - int *status = atom->status; + int *status = atom->rheo_status; double *energy = atom->esph; double *heatflow = atom->heatflow; @@ -520,7 +520,7 @@ void FixRHEOThermal::break_bonds() int m, n, nmax, i, j, melti, meltj; tagint *tag = atom->tag; - int *status = atom->status; + int *status = atom->rheo_status; int **bond_type = atom->bond_type; tagint **bond_atom = atom->bond_atom; int *num_bond = atom->num_bond; @@ -649,7 +649,7 @@ void FixRHEOThermal::create_bonds() tagint *tag = atom->tag; tagint **bond_atom = atom->bond_atom; - int *status = atom->status; + int *status = atom->rheo_status; int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; double **x = atom->x; @@ -754,7 +754,7 @@ int FixRHEOThermal::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i, j, k, m; - int *status = atom->status; + int *status = atom->rheo_status; double **x = atom->x; m = 0; @@ -773,7 +773,7 @@ int FixRHEOThermal::pack_forward_comm(int n, int *list, double *buf, void FixRHEOThermal::unpack_forward_comm(int n, int first, double *buf) { int i, k, m, last; - int *status = atom->status; + int *status = atom->rheo_status; double **x = atom->x; m = 0; last = first + n; diff --git a/src/RHEO/pair_rheo.cpp b/src/RHEO/pair_rheo.cpp index b9beaf8383..9ebf884b6e 100644 --- a/src/RHEO/pair_rheo.cpp +++ b/src/RHEO/pair_rheo.cpp @@ -110,7 +110,7 @@ void PairRHEO::compute(int eflag, int vflag) double *heatflow = atom->heatflow; double *special_lj = force->special_lj; int *type = atom->type; - int *status = atom->status; + int *status = atom->rheo_status; tagint *tag = atom->tag; double **fp_store, *chi; diff --git a/src/RHEO/pair_rheo_solid.cpp b/src/RHEO/pair_rheo_solid.cpp index 1c8654b3c4..070cabaf86 100644 --- a/src/RHEO/pair_rheo_solid.cpp +++ b/src/RHEO/pair_rheo_solid.cpp @@ -74,7 +74,7 @@ void PairRHEOSolid::compute(int eflag, int vflag) double **v = atom->v; double **f = atom->f; int *type = atom->type; - int *status = atom->status; + int *status = atom->rheo_status; int nlocal = atom->nlocal; int newton_pair = force->newton_pair; double *special_lj = force->special_lj; @@ -223,7 +223,7 @@ void PairRHEOSolid::init_style() if (comm->ghost_velocity == 0) error->all(FLERR,"Pair rheo/solid requires ghost atoms store velocity"); - if (!atom->status_flag) + if (!atom->rheo_status_flag) error->all(FLERR,"Pair rheo/solid requires atom_style rheo"); neighbor->add_request(this); @@ -328,7 +328,7 @@ double PairRHEOSolid::single(int i, int j, int itype, int jtype, double rsq, dou if (rsq > cutsq[itype][jtype]) return 0.0; - int *status = atom->status; + int *status = atom->rheo_status; if (!(status[i] & STATUS_SOLID)) return 0.0; if (!(status[j] & STATUS_SOLID)) return 0.0; diff --git a/src/atom.cpp b/src/atom.cpp index 09aaa4f1d8..9af945367b 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -200,7 +200,7 @@ Atom::Atom(LAMMPS *_lmp) : Pointers(_lmp), atom_style(nullptr), avec(nullptr), a // RHEO package - status = nullptr; + rheo_status = nullptr; conductivity = nullptr; pressure = nullptr; viscosity = nullptr; @@ -538,7 +538,7 @@ void Atom::peratom_create() // RHEO package - add_peratom("status",&status,INT,0); + add_peratom("rheo_status",&rheo_status,INT,0); add_peratom("conductivity",&conductivity,DOUBLE,0); add_peratom("pressure",&pressure,DOUBLE,0); add_peratom("viscosity",&viscosity,DOUBLE,0); @@ -648,7 +648,7 @@ void Atom::set_atomflag_defaults() temperature_flag = heatflow_flag = 0; vfrac_flag = spin_flag = eradius_flag = ervel_flag = erforce_flag = 0; cs_flag = csforce_flag = vforce_flag = ervelforce_flag = etag_flag = 0; - status_flag = conductivity_flag = pressure_flag = viscosity_flag = 0; + rheo_status_flag = conductivity_flag = pressure_flag = viscosity_flag = 0; rho_flag = esph_flag = cv_flag = vest_flag = 0; dpd_flag = edpd_flag = tdpd_flag = 0; sp_flag = 0; @@ -3065,7 +3065,7 @@ void *Atom::extract(const char *name) // RHEO package - if (strcmp(name,"status") == 0) return (void *) status; + if (strcmp(name,"rheo_status") == 0) return (void *) rheo_status; if (strcmp(name,"conductivity") == 0) return (void *) conductivity; if (strcmp(name,"pressure") == 0) return (void *) pressure; if (strcmp(name,"viscosity") == 0) return (void *) viscosity; @@ -3194,7 +3194,7 @@ int Atom::extract_datatype(const char *name) // RHEO package - if (strcmp(name,"status") == 0) return LAMMPS_INT; + if (strcmp(name,"rheo_status") == 0) return LAMMPS_INT; if (strcmp(name,"conductivity") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"pressure") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"viscosity") == 0) return LAMMPS_DOUBLE; diff --git a/src/atom.h b/src/atom.h index 568d78afb2..bd5b352cd0 100644 --- a/src/atom.h +++ b/src/atom.h @@ -157,7 +157,7 @@ class Atom : protected Pointers { // RHEO package - int *status; + int *rheo_status; double *conductivity; double *pressure; double *viscosity; @@ -197,7 +197,7 @@ class Atom : protected Pointers { int temperature_flag, heatflow_flag; int vfrac_flag, spin_flag, eradius_flag, ervel_flag, erforce_flag; int cs_flag, csforce_flag, vforce_flag, ervelforce_flag, etag_flag; - int status_flag, conductivity_flag, pressure_flag, viscosity_flag; + int rheo_status_flag, conductivity_flag, pressure_flag, viscosity_flag; int rho_flag, esph_flag, cv_flag, vest_flag; int dpd_flag, edpd_flag, tdpd_flag; int mesont_flag; diff --git a/src/set.cpp b/src/set.cpp index cd48ba2bfe..93d5068ef3 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -526,7 +526,7 @@ void Set::command(int narg, char **arg) if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "set rheo/status", error); if (utils::strmatch(arg[iarg+1],"^v_")) varparse(arg[iarg+1],1); else ivalue = utils::inumeric(FLERR,arg[iarg+1],false,lmp); - if (!atom->status_flag) + if (!atom->rheo_status_flag) error->all(FLERR,"Cannot set attribute {} for atom style {}", arg[iarg], atom->get_style()); set(RHEO_STATUS); iarg += 2; @@ -901,7 +901,7 @@ void Set::set(int keyword) else if (keyword == RHEO_STATUS) { if (ivalue != 0 && ivalue != 1) error->one(FLERR,"Invalid value {} in set command for rheo/status", ivalue); - atom->status[i] = ivalue; + atom->rheo_status[i] = ivalue; } else if (keyword == SPH_E) atom->esph[i] = dvalue; From 3b853adaacbe91c703a632d7b138b7dbbb7e3b7f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 01:38:21 -0400 Subject: [PATCH 226/385] add lammps_extract_pair_dimension and lammps_extract_pair to library interface --- examples/COUPLE/plugin/liblammpsplugin.c | 2 + examples/COUPLE/plugin/liblammpsplugin.h | 8 +- python/lammps/core.py | 95 +++++++++++++++++++++++- src/library.cpp | 64 ++++++++++++++++ src/library.h | 3 + tools/swig/lammps.i | 4 + 6 files changed, 172 insertions(+), 4 deletions(-) diff --git a/examples/COUPLE/plugin/liblammpsplugin.c b/examples/COUPLE/plugin/liblammpsplugin.c index 81dcf2cd50..7df23c5b67 100644 --- a/examples/COUPLE/plugin/liblammpsplugin.c +++ b/examples/COUPLE/plugin/liblammpsplugin.c @@ -101,6 +101,8 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) ADDSYM(extract_setting); ADDSYM(extract_global_datatype); ADDSYM(extract_global); + ADDSYM(extract_pair_dimension); + ADDSYM(extract_pair); ADDSYM(map_atom); ADDSYM(extract_atom_datatype); diff --git a/examples/COUPLE/plugin/liblammpsplugin.h b/examples/COUPLE/plugin/liblammpsplugin.h index ea00277083..9f53e4749b 100644 --- a/examples/COUPLE/plugin/liblammpsplugin.h +++ b/examples/COUPLE/plugin/liblammpsplugin.h @@ -144,11 +144,13 @@ struct _liblammpsplugin { int (*get_mpi_comm)(void *); int (*extract_setting)(void *, const char *); - int *(*extract_global_datatype)(void *, const char *); + int (*extract_global_datatype)(void *, const char *); void *(*extract_global)(void *, const char *); - void *(*map_atom)(void *, const void *); + int (*extract_pair_dimension)(void *, const char *); + void *(*extract_pair)(void *, const char *); + int (*map_atom)(void *, const void *); - int *(*extract_atom_datatype)(void *, const char *); + int (*extract_atom_datatype)(void *, const char *); void *(*extract_atom)(void *, const char *); void *(*extract_compute)(void *, const char *, int, int); diff --git a/python/lammps/core.py b/python/lammps/core.py index 8966a77440..ccf5f19d27 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -267,6 +267,9 @@ class lammps(object): self.lib.lammps_extract_global.argtypes = [c_void_p, c_char_p] self.lib.lammps_extract_global_datatype.argtypes = [c_void_p, c_char_p] self.lib.lammps_extract_global_datatype.restype = c_int + self.lib.lammps_extract_pair.argtypes = [c_void_p, c_char_p] + self.lib.lammps_extract_pair_dimension.argtypes = [c_void_p, c_char_p] + self.lib.lammps_extract_pair_dimension.restype = c_int self.lib.lammps_extract_compute.argtypes = [c_void_p, c_char_p, c_int, c_int] self.lib.lammps_map_atom.argtypes = [c_void_p, c_void_p] @@ -848,7 +851,7 @@ class lammps(object): This function returns ``None`` if the keyword is not recognized. Otherwise it will return a positive integer value that corresponds to one of the :ref:`data type ` - constants define in the :py:mod:`lammps` module. + constants defined in the :py:mod:`lammps` module. :param name: name of the property :type name: string @@ -931,6 +934,96 @@ class lammps(object): else: return target_type(ptr[0]) return None + # ------------------------------------------------------------------------- + # extract pair property dimensionality + + def extract_pair_dimension(self, name): + """Retrieve pair style property dimensionality from LAMMPS + + This is a wrapper around the :cpp:func:`lammps_extract_pair_dimension` + function of the C-library interface. The list of supported keywords + depends on the pair style. This function returns ``None`` if the keyword + is not recognized. + + :param name: name of the property + :type name: string + :return: dimensionality of the extractable data (typically 0, 1, or 2) + :rtype: int + """ + if name: + name = name.encode() + else: + return None + dim = self.lib.lammps_extract_pair_dimension(self.lmp, name) + + if dim < 0: + return None + else: + return dim; + + # ------------------------------------------------------------------------- + # get access to pair style extractable data + + def extract_pair(self, name): + """Extract pair style data from LAMMPS. + + This is a wrapper around the :cpp:func:`lammps_extract_pair` function + of the C-library interface. Since there are no pointers in Python, this + method will - unlike the C function - return the value or a list of + values. + Since Python needs to know the dimensionality to be able to interpret + the result, this function will detect the dimensionality by asking the library. + This function returns ``None`` if the keyword is not recognized. + + :param name: name of the property + :type name: string + :return: value of the property or list of values or None + :rtype: float, list of float, list of list of floats, or NoneType + """ + + if name: + name = name.encode() + else: + return None + + dim = self.extract_pair_dimension(name) + if dim == None: + return None + elif dim == 0: + self.lib.lammps_extract_pair.restype = POINTER(c_double) + elif dim == 1: + self.lib.lammps_extract_pair.restype = POINTER(c_double) + elif dim == 2: + self.lib.lammps_extract_pair.restype = POINTER(POINTER(c_double)) + else: + return None + + ntypes = self.extract_setting('ntypes') + ptr = self.lib.lammps_extract_pair(self.lmp, name) + if ptr: + if dim == 0: + return float(ptr[0]) + elif dim == 1: + result = [0.0] + for i in range(1,ntypes+1): + result.append(float(ptr[i])) + return result + elif dim == 2: + result = [] + inner = [] + for i in range(0,ntypes+1): + inner.append(float(0.0)) + result.append(inner) + for i in range(1,ntypes+1): + inner = [0.0] + for j in range(1,ntypes+1): + inner.append(float(ptr[i][j])) + result.append(inner) + return result + else: + return None + return None + # ------------------------------------------------------------------------- # map global atom ID to local atom index diff --git a/src/library.cpp b/src/library.cpp index bb58762563..13563abc02 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -42,6 +42,7 @@ #include "neigh_list.h" #include "neighbor.h" #include "output.h" +#include "pair.h" #if defined(LMP_PLUGIN) #include "plugin.h" #endif @@ -1938,6 +1939,69 @@ void *lammps_extract_global(void *handle, const char *name) /* ---------------------------------------------------------------------- */ +/** Get data dimension of pair style data accesible via Pair::extract(). + * +\verbatim embed:rst + +.. versionadded:: TBD + +This function returns an integer that specified the dimensionality of +the data that can be extracted from the current pair style with ``Pair::extract()``. +Callers of :cpp:func:`lammps_extract_pair` can use this information +to then decide how to cast the ``void *`` pointer and access the data. + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance + * \param name string with the name of the extracted property + * \return integer constant encoding the dimensionality of the + extractable pair style property or -1 if not found. */ + +int lammps_extract_pair_dimension(void * handle, const char *name) +{ + auto lmp = (LAMMPS *) handle; + if (!lmp) return -1; + auto pair = lmp->force->pair; + if (!pair) return -1; + + int dim = -1; + if (lmp->force->pair->extract(name, dim)) return dim; + + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/** Get extract pair style data accesible via Pair::extract(). + * +\verbatim embed:rst + +.. versionadded:: TBD + +This function returns a pointer to data available from the current pair +style with ``Pair::extract()``. The dimensionality of the returned +pointer can be determined with :cpp:func:`lammps_extract_pair_dimension`. + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance + * \param name string with the name of the extracted property + * \return pointer (cast to ``void *``) to the location of the + requested property. NULL if name is not known. */ + +void *lammps_extract_pair(void * handle, const char *name) +{ + auto lmp = (LAMMPS *) handle; + if (!lmp) return nullptr; + auto pair = lmp->force->pair; + if (!pair) return nullptr; + + int dim = -1; + return lmp->force->pair->extract(name, dim); +} + +/* ---------------------------------------------------------------------- */ + /** Map global atom ID to local atom index * \verbatim embed:rst diff --git a/src/library.h b/src/library.h index fa4a3bd0a5..38ecffb772 100644 --- a/src/library.h +++ b/src/library.h @@ -162,6 +162,9 @@ int lammps_extract_setting(void *handle, const char *keyword); int lammps_extract_global_datatype(void *handle, const char *name); void *lammps_extract_global(void *handle, const char *name); +int lammps_extract_pair_dimension(void *handle, const char *name); +void *lammps_extract_pair(void *handle, const char *name); + int lammps_map_atom(void *handle, const void *id); /* ---------------------------------------------------------------------- diff --git a/tools/swig/lammps.i b/tools/swig/lammps.i index d350966c2a..2207a72e36 100644 --- a/tools/swig/lammps.i +++ b/tools/swig/lammps.i @@ -125,6 +125,8 @@ extern int lammps_get_mpi_comm(void *handle); extern int lammps_extract_setting(void *handle, const char *keyword); extern int lammps_extract_global_datatype(void *handle, const char *name); extern void *lammps_extract_global(void *handle, const char *name); +extern int lammps_extract_pair_dimension(void *handle, const char *name); +extern void *lammps_extract_pair(void *handle, const char *name); extern int lammps_map_atom(void *handle, const void *id); extern int lammps_extract_atom_datatype(void *handle, const char *name); @@ -311,6 +313,8 @@ extern int lammps_get_mpi_comm(void *handle); extern int lammps_extract_setting(void *handle, const char *keyword); extern int lammps_extract_global_datatype(void *handle, const char *name); extern void *lammps_extract_global(void *handle, const char *name); +extern int lammps_extract_pair_dimension(void *handle, const char *name); +extern void *lammps_extract_pair(void *handle, const char *name); extern int lammps_map_atom(void *handle, const void *id); extern int lammps_extract_atom_datatype(void *handle, const char *name); From 90dee57aae56a8e161812a21660444741b5cbec0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 01:40:18 -0400 Subject: [PATCH 227/385] try using LJ sigma for particle radius in VDW mode --- tools/lammps-gui/imageviewer.cpp | 36 ++++++++++++++++++++---------- tools/lammps-gui/imageviewer.h | 2 +- tools/lammps-gui/lammpswrapper.cpp | 13 +++++++++++ tools/lammps-gui/lammpswrapper.h | 1 + 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/tools/lammps-gui/imageviewer.cpp b/tools/lammps-gui/imageviewer.cpp index faa18d7faf..9591efcea1 100644 --- a/tools/lammps-gui/imageviewer.cpp +++ b/tools/lammps-gui/imageviewer.cpp @@ -132,7 +132,8 @@ static const QString blank(" "); ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) : QDialog(parent), menuBar(new QMenuBar), imageLabel(new QLabel), scrollArea(new QScrollArea), - lammps(_lammps), group("all"), filename(fileName), useelements(false), usediameter(false) + lammps(_lammps), group("all"), filename(fileName), useelements(false), usediameter(false), + usesigma(false) { imageLabel->setBackgroundRole(QPalette::Base); imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); @@ -214,7 +215,7 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge combo->setObjectName("group"); combo->setToolTip("Select group to display"); combo->setObjectName("group"); - int ngroup = lammps->id_count("group"); + int ngroup = lammps->id_count("group"); constexpr int BUFLEN = 256; char gname[BUFLEN]; for (int i = 0; i < ngroup; ++i) { @@ -271,7 +272,7 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge // properties directly since lookup in reset_view() will have failed dobox->setChecked(showbox); dovdw->setChecked(vdwfactor > 1.0); - dovdw->setEnabled(useelements || usediameter); + dovdw->setEnabled(useelements || usediameter || usesigma); doaxes->setChecked(showaxes); dossao->setChecked(usessao); doanti->setChecked(antialias); @@ -336,7 +337,7 @@ void ImageViewer::edit_size() void ImageViewer::toggle_ssao() { auto *button = qobject_cast(sender()); - usessao = !usessao; + usessao = !usessao; button->setChecked(usessao); createImage(); } @@ -344,7 +345,7 @@ void ImageViewer::toggle_ssao() void ImageViewer::toggle_anti() { auto *button = qobject_cast(sender()); - antialias = !antialias; + antialias = !antialias; button->setChecked(antialias); createImage(); } @@ -363,7 +364,7 @@ void ImageViewer::toggle_vdw() void ImageViewer::toggle_box() { auto *button = qobject_cast(sender()); - showbox = !showbox; + showbox = !showbox; button->setChecked(showbox); createImage(); } @@ -371,7 +372,7 @@ void ImageViewer::toggle_box() void ImageViewer::toggle_axes() { auto *button = qobject_cast(sender()); - showaxes = !showaxes; + showaxes = !showaxes; button->setChecked(showaxes); createImage(); } @@ -443,7 +444,7 @@ void ImageViewer::createImage() // determine elements from masses and set their covalent radii int ntypes = lammps->extract_setting("ntypes"); int nbondtypes = lammps->extract_setting("nbondtypes"); - auto *masses = (double *)lammps->extract_atom("mass"); + auto *masses = (double *)lammps->extract_atom("mass"); QString units = (const char *)lammps->extract_global("units"); QString elements = "element "; QString adiams; @@ -458,9 +459,19 @@ void ImageViewer::createImage() } } usediameter = lammps->extract_setting("radius_flag") != 0; - + // use Lennard-Jones sigma for radius, if available + usesigma = false; + const char *pair_style = (const char *)lammps->extract_global("pair_style"); + if (!useelements && pair_style && (strncmp(pair_style, "lj/", 3) == 0)) { + double **sigma = (double **) lammps->extract_pair("sigma"); + if (sigma) { + usesigma = true; + for (int i = 1; i <= ntypes; ++i) + adiams += QString("adiam %1 %2 ").arg(i).arg(vdwfactor * sigma[i][i]); + } + } // adjust pushbutton state and clear adiams string to disable VDW display, if needed - if (useelements || usediameter) { + if (useelements || usediameter || usesigma) { auto *button = findChild("vdw"); if (button) button->setEnabled(true); } else { @@ -469,7 +480,7 @@ void ImageViewer::createImage() if (button) button->setEnabled(false); } - if (!adiams.isEmpty()) + if (useelements) dumpcmd += blank + "element"; else dumpcmd += blank + settings.value("color", "type").toString(); @@ -503,7 +514,8 @@ void ImageViewer::createImage() dumpcmd += " modify boxcolor " + settings.value("boxcolor", "yellow").toString(); dumpcmd += " backcolor " + settings.value("background", "black").toString(); - if (!adiams.isEmpty()) dumpcmd += blank + elements + blank + adiams + blank; + if (useelements) dumpcmd += blank + elements + blank + adiams + blank; + if (usesigma) dumpcmd += blank + adiams + blank; settings.endGroup(); lammps->command(dumpcmd.toLocal8Bit()); diff --git a/tools/lammps-gui/imageviewer.h b/tools/lammps-gui/imageviewer.h index 1be7790666..72f4c3a1e2 100644 --- a/tools/lammps-gui/imageviewer.h +++ b/tools/lammps-gui/imageviewer.h @@ -88,7 +88,7 @@ private: int xsize, ysize; int hrot, vrot; double zoom, vdwfactor; - bool showbox, showaxes, antialias, usessao, useelements, usediameter; + bool showbox, showaxes, antialias, usessao, useelements, usediameter, usesigma; }; #endif diff --git a/tools/lammps-gui/lammpswrapper.cpp b/tools/lammps-gui/lammpswrapper.cpp index f74a1c6575..1c1b29f2d1 100644 --- a/tools/lammps-gui/lammpswrapper.cpp +++ b/tools/lammps-gui/lammpswrapper.cpp @@ -76,6 +76,19 @@ void *LammpsWrapper::extract_global(const char *keyword) return val; } +void *LammpsWrapper::extract_pair(const char *keyword) +{ + void *val = nullptr; + if (lammps_handle) { +#if defined(LAMMPS_GUI_USE_PLUGIN) + val = ((liblammpsplugin_t *)plugin_handle)->extract_pair(lammps_handle, keyword); +#else + val = lammps_extract_pair(lammps_handle, keyword); +#endif + } + return val; +} + void *LammpsWrapper::extract_atom(const char *keyword) { void *val = nullptr; diff --git a/tools/lammps-gui/lammpswrapper.h b/tools/lammps-gui/lammpswrapper.h index 1d024a94e7..8719ef4491 100644 --- a/tools/lammps-gui/lammpswrapper.h +++ b/tools/lammps-gui/lammpswrapper.h @@ -32,6 +32,7 @@ public: int version(); int extract_setting(const char *keyword); void *extract_global(const char *keyword); + void *extract_pair(const char *keyword); void *extract_atom(const char *keyword); int id_count(const char *idtype); From 615c1bb6235313a683834aac7196c8772de257b8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 05:13:04 -0400 Subject: [PATCH 228/385] more compact and consistent window titles --- tools/lammps-gui/lammpsgui.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 952be3c7da..bc9f4296a0 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -169,7 +169,7 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) : ui->textEdit->setMinimumSize(600, 400); varwindow = new QLabel(QString()); - varwindow->setWindowTitle("LAMMPS-GUI - Current Variables:"); + varwindow->setWindowTitle(QString("LAMMPS-GUI - Current Variables - " + current_file)); varwindow->setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png")); varwindow->setMinimumSize(100, 50); varwindow->setText("(none)"); @@ -272,7 +272,7 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) : if (filename) { open_file(filename); } else { - setWindowTitle(QString("LAMMPS-GUI - *unknown*")); + setWindowTitle("LAMMPS-GUI - Editor - *unknown*"); } resize(settings.value("mainx", "500").toInt(), settings.value("mainy", "320").toInt()); @@ -384,7 +384,7 @@ void LammpsGui::new_document() } lammps.close(); lammpsstatus->hide(); - setWindowTitle(QString("LAMMPS-GUI - *unknown*")); + setWindowTitle("LAMMPS-GUI - Editor - *unknown*"); run_counter = 0; } @@ -609,7 +609,7 @@ void LammpsGui::open_file(const QString &fileName) ui->textEdit->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor); file.close(); } - setWindowTitle(QString("LAMMPS-GUI - " + current_file)); + setWindowTitle(QString("LAMMPS-GUI - Editor - " + current_file)); run_counter = 0; ui->textEdit->document()->setModified(false); ui->textEdit->setGroupList(); @@ -653,7 +653,7 @@ void LammpsGui::write_file(const QString &fileName) QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); return; } - setWindowTitle(QString("LAMMPS-GUI - " + current_file)); + setWindowTitle(QString("LAMMPS-GUI - Editor - " + current_file)); QDir::setCurrent(current_dir); update_recents(path.absoluteFilePath()); @@ -886,7 +886,7 @@ void LammpsGui::logupdate() slideshow->hide(); } else { slideshow->setWindowTitle( - QString("LAMMPS-GUI - Slide Show: %1 - Run %2").arg(current_file).arg(run_counter)); + QString("LAMMPS-GUI - Slide Show - %1 - Run %2").arg(current_file).arg(run_counter)); if (QSettings().value("viewslide", true).toBool()) slideshow->show(); } slideshow->add_image(imagefile); @@ -1046,10 +1046,7 @@ void LammpsGui::do_run(bool use_buffer) logwindow->setCenterOnScroll(true); logwindow->moveCursor(QTextCursor::End); logwindow->setWindowTitle( - QString("LAMMPS-GUI - Output from running LAMMPS on %1 - %2 - Run %3") - .arg(use_buffer ? "buffer" : "file") - .arg(current_file) - .arg(run_counter)); + QString("LAMMPS-GUI - Output - %2 - Run %3").arg(current_file).arg(run_counter)); logwindow->setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png")); QFont text_font; text_font.fromString(settings.value("textfont", text_font.toString()).toString()); @@ -1069,10 +1066,7 @@ void LammpsGui::do_run(bool use_buffer) if (settings.value("chartreplace", true).toBool()) delete chartwindow; chartwindow = new ChartWindow(current_file); chartwindow->setWindowTitle( - QString("LAMMPS-GUI - Thermo charts from running LAMMPS on %1 - %2 - Run %3") - .arg(use_buffer ? "buffer" : "file") - .arg(current_file) - .arg(run_counter)); + QString("LAMMPS-GUI - Charts - %2 - Run %3").arg(current_file).arg(run_counter)); chartwindow->setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png")); chartwindow->setMinimumSize(400, 300); shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), chartwindow); @@ -1085,7 +1079,7 @@ void LammpsGui::do_run(bool use_buffer) chartwindow->hide(); if (slideshow) { - slideshow->setWindowTitle("LAMMPS-GUI - Slide Show"); + slideshow->setWindowTitle(QString("LAMMPS-GUI - Slide Show - " + current_file)); slideshow->clear(); slideshow->hide(); } From 74780e74ef1193c0b8a48642ec4a4758d4375e09 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 07:30:14 -0400 Subject: [PATCH 229/385] update TODO list with new ideas motivated by tutorial paper --- tools/lammps-gui/TODO.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/lammps-gui/TODO.md b/tools/lammps-gui/TODO.md index ee05e67225..a8ce0285b5 100644 --- a/tools/lammps-gui/TODO.md +++ b/tools/lammps-gui/TODO.md @@ -2,6 +2,10 @@ LAMMPS-GUI TODO list: # Short term goals (v1.x) +- add "delete image files" option to Slide Show, plus pushbutton +- add "export YAML data" to Output viewer, if YAML thermo data is detected. +- add "export to YAML" to chart viewer. + - implement indenting regions for (nested) loops? - implement data file manager GUI with the following features: - import coordinates and topology via VMD molfile plugins From d274989843c3d4c7ed80a5cd37585ba47a713cc7 Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Tue, 16 Jul 2024 11:11:31 -0600 Subject: [PATCH 230/385] update indices --- src/KOKKOS/angle_hybrid_kokkos.cpp | 4 ++-- src/KOKKOS/dihedral_hybrid_kokkos.cpp | 4 ++-- src/KOKKOS/improper_hybrid_kokkos.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/KOKKOS/angle_hybrid_kokkos.cpp b/src/KOKKOS/angle_hybrid_kokkos.cpp index ffcc20538f..5146a061b2 100644 --- a/src/KOKKOS/angle_hybrid_kokkos.cpp +++ b/src/KOKKOS/angle_hybrid_kokkos.cpp @@ -75,7 +75,7 @@ void AngleHybridKokkos::compute(int eflag, int vflag) auto d_map = k_map.d_view; Kokkos::parallel_for(nanglelist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_anglelist_orig(i,2)]; + const int m = d_map[d_anglelist_orig(i,3)]; if (m >= 0) Kokkos::atomic_increment(&d_nanglelist[m]); }); @@ -94,7 +94,7 @@ void AngleHybridKokkos::compute(int eflag, int vflag) Kokkos::deep_copy(d_nanglelist,0); Kokkos::parallel_for(nanglelist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_anglelist_orig(i,2)]; + const int m = d_map[d_anglelist_orig(i,3)]; if (m < 0) return; const int n = Kokkos::atomic_fetch_add(&d_nanglelist[m],1); d_anglelist(m,n,0) = d_anglelist_orig(i,0); diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.cpp b/src/KOKKOS/dihedral_hybrid_kokkos.cpp index 5e7c9ac8b8..3b99b6278a 100644 --- a/src/KOKKOS/dihedral_hybrid_kokkos.cpp +++ b/src/KOKKOS/dihedral_hybrid_kokkos.cpp @@ -75,7 +75,7 @@ void DihedralHybridKokkos::compute(int eflag, int vflag) auto d_map = k_map.d_view; Kokkos::parallel_for(ndihedrallist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_dihedrallist_orig(i,2)]; + const int m = d_map[d_dihedrallist_orig(i,4)]; if (m >= 0) Kokkos::atomic_increment(&d_ndihedrallist[m]); }); @@ -94,7 +94,7 @@ void DihedralHybridKokkos::compute(int eflag, int vflag) Kokkos::deep_copy(d_ndihedrallist,0); Kokkos::parallel_for(ndihedrallist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_dihedrallist_orig(i,2)]; + const int m = d_map[d_dihedrallist_orig(i,4)]; if (m < 0) return; const int n = Kokkos::atomic_fetch_add(&d_ndihedrallist[m],1); d_dihedrallist(m,n,0) = d_dihedrallist_orig(i,0); diff --git a/src/KOKKOS/improper_hybrid_kokkos.cpp b/src/KOKKOS/improper_hybrid_kokkos.cpp index 3d4790c818..a1f4be9b4b 100644 --- a/src/KOKKOS/improper_hybrid_kokkos.cpp +++ b/src/KOKKOS/improper_hybrid_kokkos.cpp @@ -76,7 +76,7 @@ void ImproperHybridKokkos::compute(int eflag, int vflag) auto d_map = k_map.d_view; Kokkos::parallel_for(nimproperlist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_improperlist_orig(i,2)]; + const int m = d_map[d_improperlist_orig(i,4)]; if (m >= 0) Kokkos::atomic_increment(&d_nimproperlist[m]); }); @@ -95,7 +95,7 @@ void ImproperHybridKokkos::compute(int eflag, int vflag) Kokkos::deep_copy(d_nimproperlist,0); Kokkos::parallel_for(nimproperlist_orig,LAMMPS_LAMBDA(int i) { - const int m = d_map[d_improperlist_orig(i,2)]; + const int m = d_map[d_improperlist_orig(i,4)]; if (m < 0) return; const int n = Kokkos::atomic_fetch_add(&d_nimproperlist[m],1); d_improperlist(m,n,0) = d_improperlist_orig(i,0); From 9730bb4f10d5893bafd0f41b722b8d1e972597af Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 14:25:41 -0400 Subject: [PATCH 231/385] step LAMMPS GUI version to 1.6.0 --- doc/src/Howto_lammps_gui.rst | 2 +- tools/lammps-gui/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/Howto_lammps_gui.rst b/doc/src/Howto_lammps_gui.rst index 6faac96ce9..d6c98c5b2b 100644 --- a/doc/src/Howto_lammps_gui.rst +++ b/doc/src/Howto_lammps_gui.rst @@ -1,7 +1,7 @@ Using the LAMMPS GUI ==================== -This document describes **LAMMPS GUI version 1.5**. +This document describes **LAMMPS GUI version 1.6**. ----- diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 1e928232f0..2a29f69933 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(lammps-gui VERSION 1.5.12 LANGUAGES CXX) +project(lammps-gui VERSION 1.6.0 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) From a5299b48d97bd93123068ad0d5ef87580b2939aa Mon Sep 17 00:00:00 2001 From: "Megan J. McCarthy" Date: Tue, 16 Jul 2024 12:33:49 -0600 Subject: [PATCH 232/385] update view size --- src/KOKKOS/angle_hybrid_kokkos.cpp | 2 +- src/KOKKOS/dihedral_hybrid_kokkos.cpp | 2 +- src/KOKKOS/improper_hybrid_kokkos.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/KOKKOS/angle_hybrid_kokkos.cpp b/src/KOKKOS/angle_hybrid_kokkos.cpp index 5146a061b2..e2d52a2992 100644 --- a/src/KOKKOS/angle_hybrid_kokkos.cpp +++ b/src/KOKKOS/angle_hybrid_kokkos.cpp @@ -88,7 +88,7 @@ void AngleHybridKokkos::compute(int eflag, int vflag) maxangle_all = h_nanglelist[m] + EXTRA; if (k_anglelist.d_view.extent(1) < maxangle_all) - MemKK::realloc_kokkos(k_anglelist, "angle_hybrid:anglelist", nstyles, maxangle_all, 3); + MemKK::realloc_kokkos(k_anglelist, "angle_hybrid:anglelist", nstyles, maxangle_all, 4); auto d_anglelist = k_anglelist.d_view; Kokkos::deep_copy(d_nanglelist,0); diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.cpp b/src/KOKKOS/dihedral_hybrid_kokkos.cpp index 3b99b6278a..22a965a4e6 100644 --- a/src/KOKKOS/dihedral_hybrid_kokkos.cpp +++ b/src/KOKKOS/dihedral_hybrid_kokkos.cpp @@ -88,7 +88,7 @@ void DihedralHybridKokkos::compute(int eflag, int vflag) maxdihedral_all = h_ndihedrallist[m] + EXTRA; if (k_dihedrallist.d_view.extent(1) < maxdihedral_all) - MemKK::realloc_kokkos(k_dihedrallist, "dihedral_hybrid:dihedrallist", nstyles, maxdihedral_all, 3); + MemKK::realloc_kokkos(k_dihedrallist, "dihedral_hybrid:dihedrallist", nstyles, maxdihedral_all, 5); auto d_dihedrallist = k_dihedrallist.d_view; Kokkos::deep_copy(d_ndihedrallist,0); diff --git a/src/KOKKOS/improper_hybrid_kokkos.cpp b/src/KOKKOS/improper_hybrid_kokkos.cpp index a1f4be9b4b..016b29ea24 100644 --- a/src/KOKKOS/improper_hybrid_kokkos.cpp +++ b/src/KOKKOS/improper_hybrid_kokkos.cpp @@ -89,7 +89,7 @@ void ImproperHybridKokkos::compute(int eflag, int vflag) maximproper_all = h_nimproperlist[m] + EXTRA; if (k_improperlist.d_view.extent(1) < maximproper_all) - MemKK::realloc_kokkos(k_improperlist, "improper_hybrid:improperlist", nstyles, maximproper_all, 3); + MemKK::realloc_kokkos(k_improperlist, "improper_hybrid:improperlist", nstyles, maximproper_all, 5); auto d_improperlist = k_improperlist.d_view; Kokkos::deep_copy(d_nimproperlist,0); From 4daba292d7e1ce78d5a340cf5596c5e66d14139a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 18:30:45 -0400 Subject: [PATCH 233/385] add unit tests for library interface function lammps_extract_pair() and python equivalent --- .../c-library/test_library_properties.cpp | 50 ++++++++++++++++- unittest/python/python-commands.py | 55 +++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index 52460b6b1e..3900265f8c 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -418,7 +418,7 @@ TEST_F(LibraryProperties, global) EXPECT_EQ(map_style, Atom::MAP_ARRAY); EXPECT_NE(sametag, nullptr); - auto *tags = (tagint *)lammps_extract_atom(lmp, "id"); + auto *tags = (tagint *)lammps_extract_atom(lmp, "id"); const tagint sometags[] = {1, 5, 10, 15, 20}; for (const auto &sometag : sometags) { int idx = lammps_map_atom(lmp, (const void *)&sometag); @@ -467,6 +467,54 @@ TEST_F(LibraryProperties, global) EXPECT_EQ(map_style, Atom::MAP_ARRAY); }; +TEST_F(LibraryProperties, pair1) +{ + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_command(lmp, "region box block 0 1 0 1 0 1"); + lammps_command(lmp, "create_box 3 box"); + lammps_command(lmp, "mass * 1.0"); + lammps_command(lmp, "pair_style lj/cut 3.0"); + lammps_command(lmp, "pair_coeff 1 1 1.0 1.0"); + lammps_command(lmp, "pair_coeff 2 2 1.5 2.0"); + lammps_command(lmp, "pair_coeff 3 3 1.0 3.0"); + lammps_command(lmp, "run 0 post no"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_extract_pair_dimension(lmp, "epsilon"), 2); + EXPECT_EQ(lammps_extract_pair_dimension(lmp, "sigma"), 2); + EXPECT_EQ(lammps_extract_pair_dimension(lmp, "cut_coul"), -1); + auto **sigma = (double **)lammps_extract_pair(lmp, "sigma"); + EXPECT_DOUBLE_EQ(sigma[1][1], 1.0); + EXPECT_DOUBLE_EQ(sigma[2][2], 2.0); + EXPECT_DOUBLE_EQ(sigma[3][3], 3.0); + EXPECT_DOUBLE_EQ(sigma[1][2], sqrt(2.0)); +}; + +TEST_F(LibraryProperties, pair2) +{ + if (!lammps_has_style(lmp, "pair", "coul/streitz")) GTEST_SKIP(); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_command(lmp, "units metal"); + lammps_command(lmp, "atom_style charge"); + lammps_command(lmp, "region box block 0 1 0 1 0 1"); + lammps_command(lmp, "create_box 2 box"); + lammps_command(lmp, "mass * 1.0"); + lammps_command(lmp, "pair_style coul/streitz 12.0 wolf 0.31"); + lammps_command(lmp, "pair_coeff * * AlO.streitz Al O"); + lammps_command(lmp, "run 0 post no"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_extract_pair_dimension(lmp, "chi"), 1); + EXPECT_EQ(lammps_extract_pair_dimension(lmp, "scale"), 2); + EXPECT_EQ(lammps_extract_pair_dimension(lmp, "cut_coul"), 0); + EXPECT_DOUBLE_EQ(*((double *)lammps_extract_pair(lmp, "cut_coul")), 12.0); + auto *chi = (double *)lammps_extract_pair(lmp, "chi"); + EXPECT_DOUBLE_EQ(chi[1], 0.0); + EXPECT_FLOAT_EQ(chi[2], 5.484763); + auto **scale = (double **)lammps_extract_pair(lmp, "scale"); + EXPECT_DOUBLE_EQ(scale[1][1], 1.0); + EXPECT_DOUBLE_EQ(scale[1][2], 1.0); + EXPECT_DOUBLE_EQ(scale[2][2], 1.0); +}; + TEST_F(LibraryProperties, neighlist) { if (!lammps_has_style(lmp, "pair", "sw")) GTEST_SKIP(); diff --git a/unittest/python/python-commands.py b/unittest/python/python-commands.py index 3a222dde5a..fcf731bf3f 100644 --- a/unittest/python/python-commands.py +++ b/unittest/python/python-commands.py @@ -3,6 +3,7 @@ import sys,os,unittest,ctypes from lammps import lammps, LMP_VAR_ATOM, LMP_STYLE_GLOBAL, LMP_STYLE_LOCAL from lammps import LMP_TYPE_VECTOR, LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS from lammps import LAMMPS_DOUBLE_2D, LAMMPS_AUTODETECT +import math has_manybody=False try: @@ -15,6 +16,17 @@ try: except: pass +has_streitz=False +try: + machine=None + if 'LAMMPS_MACHINE_NAME' in os.environ: + machine=os.environ['LAMMPS_MACHINE_NAME'] + lmp=lammps(name=machine) + has_streitz = lmp.has_style("pair","coul/streitz") + lmp.close() +except: + pass + class PythonCommand(unittest.TestCase): def setUp(self): @@ -666,6 +678,49 @@ create_atoms 1 single & self.lmp.command("balance 0.1 rcb") self.assertEqual(self.lmp.extract_global("procgrid"), None) + def test_extract_pair1(self): + self.lmp.command("region box block 0 1 0 1 0 1") + self.lmp.command("create_box 3 box") + self.lmp.command("mass * 1.0") + self.lmp.command("pair_style lj/cut 3.0") + self.lmp.command("pair_coeff 1 1 1.0 1.0") + self.lmp.command("pair_coeff 2 2 1.5 2.0") + self.lmp.command("pair_coeff 3 3 1.0 3.0") + self.lmp.command("run 0 post no") + self.assertEqual(self.lmp.extract_pair_dimension("epsilon"), 2) + self.assertEqual(self.lmp.extract_pair_dimension("sigma"), 2) + self.assertEqual(self.lmp.extract_pair_dimension("cut_coul"), None) + sigma = self.lmp.extract_pair("sigma") + self.assertEqual(sigma[1][1], 1.0) + self.assertEqual(sigma[2][2], 2.0) + self.assertEqual(sigma[3][3], 3.0) + self.assertEqual(sigma[1][2], math.sqrt(2.0)) + + @unittest.skipIf(not has_streitz, "Pair extract for coul/streitz test") + def test_extract_pair2(self): + self.lmp.command("units metal") + self.lmp.command("atom_style charge") + self.lmp.command("region box block 0 1 0 1 0 1") + self.lmp.command("create_box 2 box") + self.lmp.command("mass * 1.0") + self.lmp.command("pair_style coul/streitz 12.0 wolf 0.31") + self.lmp.command("pair_coeff * * AlO.streitz Al O") + self.lmp.command("run 0 post no") + + self.assertEqual(self.lmp.extract_pair_dimension("chi"), 1) + self.assertEqual(self.lmp.extract_pair_dimension("scale"), 2) + self.assertEqual(self.lmp.extract_pair_dimension("cut_coul"), 0) + self.assertEqual(self.lmp.extract_pair_dimension("epsilon"), None) + + self.assertEqual(self.lmp.extract_pair("cut_coul"), 12.0) + self.assertEqual(self.lmp.extract_pair("chi"), [0.0, 0.0, 5.484763]) + scale = self.lmp.extract_pair("scale") + self.assertEqual(scale[0][0], 0.0); + self.assertEqual(scale[0][1], 0.0); + self.assertEqual(scale[1][1], 1.0); + self.assertEqual(scale[1][2], 1.0); + self.assertEqual(scale[2][2], 1.0); + def test_create_atoms(self): self.lmp.command("boundary f p m") self.lmp.command("region box block 0 10 0 10 0 10") From 8d4a80729aec11386a9c55217cf183ec93372be7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 19:00:18 -0400 Subject: [PATCH 234/385] don't overwrite string type argument variables with their encoded version --- python/lammps/core.py | 190 +++++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 87 deletions(-) diff --git a/python/lammps/core.py b/python/lammps/core.py index ccf5f19d27..dbadebe7f2 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -533,11 +533,11 @@ class lammps(object): :param error_text: :type error_text: string """ - if error_text: error_text = error_text.encode() - else: error_text = "(unknown error)".encode() + if error_text: new_error_text = error_text.encode() + else: new_error_text = "(unknown error)".encode() with ExceptionCheck(self): - self.lib.lammps_error(self.lmp, error_type, error_text) + self.lib.lammps_error(self.lmp, error_type, new_error_text) # ------------------------------------------------------------------------- @@ -612,11 +612,11 @@ class lammps(object): :param path: Name of the file/path with LAMMPS commands :type path: string """ - if path: path = path.encode() + if path: newpath = path.encode() else: return with ExceptionCheck(self): - self.lib.lammps_file(self.lmp, path) + self.lib.lammps_file(self.lmp, newpath) # ------------------------------------------------------------------------- @@ -629,11 +629,11 @@ class lammps(object): :param cmd: a single lammps command :type cmd: string """ - if cmd: cmd = cmd.encode() + if cmd: newcmd = cmd.encode() else: return with ExceptionCheck(self): - self.lib.lammps_command(self.lmp,cmd) + self.lib.lammps_command(self.lmp, newcmd) # ------------------------------------------------------------------------- @@ -667,10 +667,11 @@ class lammps(object): :param multicmd: text block of lammps commands :type multicmd: string """ - if type(multicmd) is str: multicmd = multicmd.encode() + if type(multicmd) is str: newmulticmd = multicmd.encode() + else: newmulticmd = multicmd with ExceptionCheck(self): - self.lib.lammps_commands_string(self.lmp,c_char_p(multicmd)) + self.lib.lammps_commands_string(self.lmp,c_char_p(newmulticmd)) # ------------------------------------------------------------------------- @@ -757,11 +758,11 @@ class lammps(object): :return: value of thermo keyword :rtype: double or None """ - if name: name = name.encode() + if name: newname = name.encode() else: return None with ExceptionCheck(self): - return self.lib.lammps_get_thermo(self.lmp,name) + return self.lib.lammps_get_thermo(self.lmp, newname) # ------------------------------------------------------------------------- @property @@ -835,9 +836,9 @@ class lammps(object): :return: value of the setting :rtype: int """ - if name: name = name.encode() + if name: newname = name.encode() else: return None - return int(self.lib.lammps_extract_setting(self.lmp,name)) + return int(self.lib.lammps_extract_setting(self.lmp, newname)) # ------------------------------------------------------------------------- # extract global info datatype @@ -858,9 +859,9 @@ class lammps(object): :return: data type of global property, see :ref:`py_datatype_constants` :rtype: int """ - if name: name = name.encode() + if name: newname = name.encode() else: return None - return self.lib.lammps_extract_global_datatype(self.lmp, name) + return self.lib.lammps_extract_global_datatype(self.lmp, newname) # ------------------------------------------------------------------------- # extract global info @@ -904,7 +905,7 @@ class lammps(object): else: veclen = 1 - if name: name = name.encode() + if name: newname = name.encode() else: return None if dtype == LAMMPS_INT: @@ -922,7 +923,7 @@ class lammps(object): else: target_type = None - ptr = self.lib.lammps_extract_global(self.lmp, name) + ptr = self.lib.lammps_extract_global(self.lmp, newname) if ptr: if dtype == LAMMPS_STRING: return ptr.decode('utf-8') @@ -940,6 +941,8 @@ class lammps(object): def extract_pair_dimension(self, name): """Retrieve pair style property dimensionality from LAMMPS + .. versionadded:: TBD + This is a wrapper around the :cpp:func:`lammps_extract_pair_dimension` function of the C-library interface. The list of supported keywords depends on the pair style. This function returns ``None`` if the keyword @@ -951,10 +954,10 @@ class lammps(object): :rtype: int """ if name: - name = name.encode() + newname = name.encode() else: return None - dim = self.lib.lammps_extract_pair_dimension(self.lmp, name) + dim = self.lib.lammps_extract_pair_dimension(self.lmp, newname) if dim < 0: return None @@ -967,6 +970,8 @@ class lammps(object): def extract_pair(self, name): """Extract pair style data from LAMMPS. + .. versionadded:: TBD + This is a wrapper around the :cpp:func:`lammps_extract_pair` function of the C-library interface. Since there are no pointers in Python, this method will - unlike the C function - return the value or a list of @@ -982,7 +987,7 @@ class lammps(object): """ if name: - name = name.encode() + newname = name.encode() else: return None @@ -999,7 +1004,7 @@ class lammps(object): return None ntypes = self.extract_setting('ntypes') - ptr = self.lib.lammps_extract_pair(self.lmp, name) + ptr = self.lib.lammps_extract_pair(self.lmp, newname) if ptr: if dim == 0: return float(ptr[0]) @@ -1061,9 +1066,9 @@ class lammps(object): :return: data type of per-atom property (see :ref:`py_datatype_constants`) :rtype: int """ - if name: name = name.encode() + if name: newname = name.encode() else: return None - return self.lib.lammps_extract_atom_datatype(self.lmp, name) + return self.lib.lammps_extract_atom_datatype(self.lmp, newname) # ------------------------------------------------------------------------- # extract per-atom info @@ -1104,7 +1109,7 @@ class lammps(object): if dtype == LAMMPS_AUTODETECT: dtype = self.extract_atom_datatype(name) - if name: name = name.encode() + if name: newname = name.encode() else: return None if dtype == LAMMPS_INT: @@ -1121,7 +1126,7 @@ class lammps(object): self.lib.lammps_extract_atom.restype = POINTER(POINTER(c_int64)) else: return None - ptr = self.lib.lammps_extract_atom(self.lmp, name) + ptr = self.lib.lammps_extract_atom(self.lmp, newname) if ptr: return ptr else: return None @@ -1149,47 +1154,47 @@ class lammps(object): :return: requested data as scalar, pointer to 1d or 2d double array, or None :rtype: c_double, ctypes.POINTER(c_double), ctypes.POINTER(ctypes.POINTER(c_double)), or NoneType """ - if cid: cid = cid.encode() + if cid: newcid = cid.encode() else: return None if ctype == LMP_TYPE_SCALAR: if cstyle == LMP_STYLE_GLOBAL: self.lib.lammps_extract_compute.restype = POINTER(c_double) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype) + ptr = self.lib.lammps_extract_compute(self.lmp,newcid,cstyle,ctype) return ptr[0] elif cstyle == LMP_STYLE_ATOM: return None elif cstyle == LMP_STYLE_LOCAL: self.lib.lammps_extract_compute.restype = POINTER(c_int) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype) + ptr = self.lib.lammps_extract_compute(self.lmp,newcid,cstyle,ctype) return ptr[0] elif ctype == LMP_TYPE_VECTOR: self.lib.lammps_extract_compute.restype = POINTER(c_double) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype) + ptr = self.lib.lammps_extract_compute(self.lmp,newcid,cstyle,ctype) return ptr elif ctype == LMP_TYPE_ARRAY: self.lib.lammps_extract_compute.restype = POINTER(POINTER(c_double)) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype) + ptr = self.lib.lammps_extract_compute(self.lmp,newcid,cstyle,ctype) return ptr elif ctype == LMP_SIZE_COLS: if cstyle == LMP_STYLE_GLOBAL or cstyle == LMP_STYLE_ATOM or cstyle == LMP_STYLE_LOCAL: self.lib.lammps_extract_compute.restype = POINTER(c_int) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype) + ptr = self.lib.lammps_extract_compute(self.lmp,newcid,cstyle,ctype) return ptr[0] elif ctype == LMP_SIZE_VECTOR or ctype == LMP_SIZE_ROWS: if cstyle == LMP_STYLE_GLOBAL or cstyle == LMP_STYLE_LOCAL: self.lib.lammps_extract_compute.restype = POINTER(c_int) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype) + ptr = self.lib.lammps_extract_compute(self.lmp,newcid,cstyle,ctype) return ptr[0] return None @@ -1234,21 +1239,21 @@ class lammps(object): :rtype: c_double, ctypes.POINTER(c_double), ctypes.POINTER(ctypes.POINTER(c_double)), or NoneType """ - if fid: fid = fid.encode() + if fid: newfid = fid.encode() else: return None if fstyle == LMP_STYLE_GLOBAL: if ftype in (LMP_TYPE_SCALAR, LMP_TYPE_VECTOR, LMP_TYPE_ARRAY): self.lib.lammps_extract_fix.restype = POINTER(c_double) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol) + ptr = self.lib.lammps_extract_fix(self.lmp,newfid,fstyle,ftype,nrow,ncol) result = ptr[0] self.lib.lammps_free(ptr) return result elif ftype in (LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS): self.lib.lammps_extract_fix.restype = POINTER(c_int) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol) + ptr = self.lib.lammps_extract_fix(self.lmp,newfid,fstyle,ftype,nrow,ncol) return ptr[0] else: return None @@ -1263,7 +1268,7 @@ class lammps(object): else: return None with ExceptionCheck(self): - ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol) + ptr = self.lib.lammps_extract_fix(self.lmp,newfid,fstyle,ftype,nrow,ncol) if ftype == LMP_SIZE_COLS: return ptr[0] else: @@ -1279,7 +1284,7 @@ class lammps(object): else: return None with ExceptionCheck(self): - ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol) + ptr = self.lib.lammps_extract_fix(self.lmp,newfid,fstyle,ftype,nrow,ncol) if ftype in (LMP_TYPE_VECTOR, LMP_TYPE_ARRAY): return ptr else: @@ -1320,15 +1325,16 @@ class lammps(object): :return: the requested data :rtype: c_double, (c_double), or NoneType """ - if name: name = name.encode() + if name: newname = name.encode() else: return None - if group: group = group.encode() + if group: newgroup = group.encode() + else: newgroup = None if vartype is None : - vartype = self.lib.lammps_extract_variable_datatype(self.lmp, name) + vartype = self.lib.lammps_extract_variable_datatype(self.lmp, newname) if vartype == LMP_VAR_EQUAL: self.lib.lammps_extract_variable.restype = POINTER(c_double) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_variable(self.lmp,name,group) + ptr = self.lib.lammps_extract_variable(self.lmp, newname, newgroup) if ptr: result = ptr[0] else: return None self.lib.lammps_free(ptr) @@ -1338,7 +1344,7 @@ class lammps(object): result = (c_double*nlocal)() self.lib.lammps_extract_variable.restype = POINTER(c_double) with ExceptionCheck(self): - ptr = self.lib.lammps_extract_variable(self.lmp,name,group) + ptr = self.lib.lammps_extract_variable(self.lmp, newname, newgroup) if ptr: for i in range(nlocal): result[i] = ptr[i] self.lib.lammps_free(ptr) @@ -1347,27 +1353,27 @@ class lammps(object): elif vartype == LMP_VAR_VECTOR : nvector = 0 self.lib.lammps_extract_variable.restype = POINTER(c_int) - ptr = self.lib.lammps_extract_variable(self.lmp,name, + ptr = self.lib.lammps_extract_variable(self.lmp, newname, 'LMP_SIZE_VECTOR'.encode()) if ptr : nvector = ptr[0] self.lib.lammps_free(ptr) - else : + else: return None self.lib.lammps_extract_variable.restype = POINTER(c_double) result = (c_double*nvector)() - values = self.lib.lammps_extract_variable(self.lmp,name,group) + values = self.lib.lammps_extract_variable(self.lmp, newname, newgroup) if values : for i in range(nvector) : result[i] = values[i] # do NOT free the values pointer (points to internal vector data) return result - else : + else: return None elif vartype == LMP_VAR_STRING : self.lib.lammps_extract_variable.restype = c_char_p with ExceptionCheck(self) : - ptr = self.lib.lammps_extract_variable(self.lmp, name, group) + ptr = self.lib.lammps_extract_variable(self.lmp, newname, newgroup) return ptr.decode('utf-8') return None @@ -1398,12 +1404,12 @@ class lammps(object): :return: either 0 on success or -1 on failure :rtype: int """ - if name: name = name.encode() + if name: newname = name.encode() else: return -1 - if value: value = str(value).encode() + if value: newvalue = str(value).encode() else: return -1 with ExceptionCheck(self): - return self.lib.lammps_set_variable(self.lmp,name,value) + return self.lib.lammps_set_variable(self.lmp, newname, newvalue) # ------------------------------------------------------------------------- @@ -1422,12 +1428,12 @@ class lammps(object): :return: either 0 on success or -1 on failure :rtype: int """ - if name: name = name.encode() + if name: newname = name.encode() else: return -1 - if value: value = str(value).encode() + if value: newvalue = str(value).encode() else: return -1 with ExceptionCheck(self): - return self.lib.lammps_set_string_variable(self.lmp,name,value) + return self.lib.lammps_set_string_variable(self.lmp,newname,newvalue) # ------------------------------------------------------------------------- @@ -1446,10 +1452,10 @@ class lammps(object): :return: either 0 on success or -1 on failure :rtype: int """ - if name: name = name.encode() + if name: newname = name.encode() else: return -1 with ExceptionCheck(self): - return self.lib.lammps_set_internal_variable(self.lmp,name,value) + return self.lib.lammps_set_internal_variable(self.lmp,newname,value) # ------------------------------------------------------------------------- @@ -1463,15 +1469,16 @@ class lammps(object): # e.g. for Python list or NumPy or ctypes def gather_atoms(self,name,dtype,count): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None natoms = self.get_natoms() with ExceptionCheck(self): if dtype == 0: data = ((count*natoms)*c_int)() - self.lib.lammps_gather_atoms(self.lmp,name,dtype,count,data) + self.lib.lammps_gather_atoms(self.lmp,newname,dtype,count,data) elif dtype == 1: data = ((count*natoms)*c_double)() - self.lib.lammps_gather_atoms(self.lmp,name,dtype,count,data) + self.lib.lammps_gather_atoms(self.lmp,newname,dtype,count,data) else: return None return data @@ -1479,28 +1486,30 @@ class lammps(object): # ------------------------------------------------------------------------- def gather_atoms_concat(self,name,dtype,count): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None natoms = self.get_natoms() with ExceptionCheck(self): if dtype == 0: data = ((count*natoms)*c_int)() - self.lib.lammps_gather_atoms_concat(self.lmp,name,dtype,count,data) + self.lib.lammps_gather_atoms_concat(self.lmp,newname,dtype,count,data) elif dtype == 1: data = ((count*natoms)*c_double)() - self.lib.lammps_gather_atoms_concat(self.lmp,name,dtype,count,data) + self.lib.lammps_gather_atoms_concat(self.lmp,newname,dtype,count,data) else: return None return data def gather_atoms_subset(self,name,dtype,count,ndata,ids): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None with ExceptionCheck(self): if dtype == 0: data = ((count*ndata)*c_int)() - self.lib.lammps_gather_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data) + self.lib.lammps_gather_atoms_subset(self.lmp,newname,dtype,count,ndata,ids,data) elif dtype == 1: data = ((count*ndata)*c_double)() - self.lib.lammps_gather_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data) + self.lib.lammps_gather_atoms_subset(self.lmp,newname,dtype,count,ndata,ids,data) else: return None return data @@ -1517,16 +1526,18 @@ class lammps(object): # e.g. for Python list or NumPy or ctypes def scatter_atoms(self,name,dtype,count,data): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None with ExceptionCheck(self): - self.lib.lammps_scatter_atoms(self.lmp,name,dtype,count,data) + self.lib.lammps_scatter_atoms(self.lmp,newname,dtype,count,data) # ------------------------------------------------------------------------- def scatter_atoms_subset(self,name,dtype,count,ndata,ids,data): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None with ExceptionCheck(self): - self.lib.lammps_scatter_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data) + self.lib.lammps_scatter_atoms_subset(self.lmp,newname,dtype,count,ndata,ids,data) # ------------------------------------------------------------------------- @@ -1632,42 +1643,45 @@ class lammps(object): # NOTE: need to ensure are converting to/from correct Python type # e.g. for Python list or NumPy or ctypes def gather(self,name,dtype,count): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None natoms = self.get_natoms() with ExceptionCheck(self): if dtype == 0: data = ((count*natoms)*c_int)() - self.lib.lammps_gather(self.lmp,name,dtype,count,data) + self.lib.lammps_gather(self.lmp,newname,dtype,count,data) elif dtype == 1: data = ((count*natoms)*c_double)() - self.lib.lammps_gather(self.lmp,name,dtype,count,data) + self.lib.lammps_gather(self.lmp,newname,dtype,count,data) else: return None return data def gather_concat(self,name,dtype,count): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None natoms = self.get_natoms() with ExceptionCheck(self): if dtype == 0: data = ((count*natoms)*c_int)() - self.lib.lammps_gather_concat(self.lmp,name,dtype,count,data) + self.lib.lammps_gather_concat(self.lmp,newname,dtype,count,data) elif dtype == 1: data = ((count*natoms)*c_double)() - self.lib.lammps_gather_concat(self.lmp,name,dtype,count,data) + self.lib.lammps_gather_concat(self.lmp,newname,dtype,count,data) else: return None return data def gather_subset(self,name,dtype,count,ndata,ids): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None with ExceptionCheck(self): if dtype == 0: data = ((count*ndata)*c_int)() - self.lib.lammps_gather_subset(self.lmp,name,dtype,count,ndata,ids,data) + self.lib.lammps_gather_subset(self.lmp,newname,dtype,count,ndata,ids,data) elif dtype == 1: data = ((count*ndata)*c_double)() - self.lib.lammps_gather_subset(self.lmp,name,dtype,count,ndata,ids,data) + self.lib.lammps_gather_subset(self.lmp,newname,dtype,count,ndata,ids,data) else: return None return data @@ -1682,14 +1696,16 @@ class lammps(object): # e.g. for Python list or NumPy or ctypes def scatter(self,name,dtype,count,data): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None with ExceptionCheck(self): - self.lib.lammps_scatter(self.lmp,name,dtype,count,data) + self.lib.lammps_scatter(self.lmp,newname,dtype,count,data) def scatter_subset(self,name,dtype,count,ndata,ids,data): - if name: name = name.encode() + if name: newname = name.encode() + else: newname = None with ExceptionCheck(self): - self.lib.lammps_scatter_subset(self.lmp,name,dtype,count,ndata,ids,data) + self.lib.lammps_scatter_subset(self.lmp,newname,dtype,count,ndata,ids,data) # ------------------------------------------------------------------------- @@ -2442,9 +2458,9 @@ class lammps(object): :rtype: int """ - style = style.encode() + newstyle = style.encode() exact = int(exact) - idx = self.lib.lammps_find_pair_neighlist(self.lmp, style, exact, nsub, reqid) + idx = self.lib.lammps_find_pair_neighlist(self.lmp, newstyle, exact, nsub, reqid) return idx # ------------------------------------------------------------------------- @@ -2465,8 +2481,8 @@ class lammps(object): :rtype: int """ - fixid = fixid.encode() - idx = self.lib.lammps_find_fix_neighlist(self.lmp, fixid, reqid) + newfixid = fixid.encode() + idx = self.lib.lammps_find_fix_neighlist(self.lmp, newfixid, reqid) return idx # ------------------------------------------------------------------------- @@ -2488,6 +2504,6 @@ class lammps(object): :rtype: int """ - computeid = computeid.encode() - idx = self.lib.lammps_find_compute_neighlist(self.lmp, computeid, reqid) + newcomputeid = computeid.encode() + idx = self.lib.lammps_find_compute_neighlist(self.lmp, newcomputeid, reqid) return idx From 5b298711986856d681a2e22c44df701ceb77dfa1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 19:08:01 -0400 Subject: [PATCH 235/385] update docs for new library function --- doc/src/Library_properties.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/src/Library_properties.rst b/doc/src/Library_properties.rst index 73abcbbe1b..129acb1a32 100644 --- a/doc/src/Library_properties.rst +++ b/doc/src/Library_properties.rst @@ -13,6 +13,8 @@ This section documents the following functions: - :cpp:func:`lammps_extract_setting` - :cpp:func:`lammps_extract_global_datatype` - :cpp:func:`lammps_extract_global` +- :cpp:func:`lammps_extract_pair_dimension` +- :cpp:func:`lammps_extract_pair` - :cpp:func:`lammps_map_atom` -------------------- @@ -123,6 +125,16 @@ subdomains and processors. ----------------------- +.. doxygenfunction:: lammps_extract_pair_dimension + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_extract_pair + :project: progguide + +----------------------- + .. doxygenfunction:: lammps_map_atom :project: progguide From dc84078156de7eece4bf7ca29842fa9699392393 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 19:15:31 -0400 Subject: [PATCH 236/385] spelling --- doc/utils/sphinx-config/false_positives.txt | 1 + src/library.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index c300cf608d..4ce6700d42 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -1099,6 +1099,7 @@ excv exe executables extep +extractable extrema extxyz exy diff --git a/src/library.cpp b/src/library.cpp index 13563abc02..fbe78b9646 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -1939,7 +1939,7 @@ void *lammps_extract_global(void *handle, const char *name) /* ---------------------------------------------------------------------- */ -/** Get data dimension of pair style data accesible via Pair::extract(). +/** Get data dimension of pair style data accessible via Pair::extract(). * \verbatim embed:rst @@ -1972,7 +1972,7 @@ int lammps_extract_pair_dimension(void * handle, const char *name) /* ---------------------------------------------------------------------- */ -/** Get extract pair style data accesible via Pair::extract(). +/** Get extract pair style data accessible via Pair::extract(). * \verbatim embed:rst From ccfdb4aee4458e207eed57226c92891d2dd001fc Mon Sep 17 00:00:00 2001 From: alphataubio Date: Tue, 16 Jul 2024 19:45:47 -0400 Subject: [PATCH 237/385] https://matsci.org/t/a-few-kokkos-development-questions/56598 --- src/KOKKOS/angle_spica_kokkos.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/KOKKOS/angle_spica_kokkos.cpp b/src/KOKKOS/angle_spica_kokkos.cpp index 0e89c13967..6c8c8b8aba 100644 --- a/src/KOKKOS/angle_spica_kokkos.cpp +++ b/src/KOKKOS/angle_spica_kokkos.cpp @@ -87,7 +87,6 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) d_vatom = k_vatom.template view(); } - atomKK->sync(execution_space,datamask_read); k_k.template sync(); k_theta0.template sync(); k_repscale.template sync(); @@ -99,15 +98,20 @@ void AngleSPICAKokkos::compute(int eflag_in, int vflag_in) k_rminsq.template sync(); k_emin.template sync(); - if (eflag || vflag) atomKK->modified(execution_space,datamask_modify); - else atomKK->modified(execution_space,F_MASK); + + // "It has to do with overlapping host/device in verlet_kokkos.cpp. For this reason, all topology styles (bond, angle, etc.) must set DATAMASK_READ, DATAMASK_MODIFY in the constructor and must not use atomKK->sync/modified. This is a gotcha that needed to be better documented." + // https://matsci.org/t/a-few-kokkos-development-questions/56598 + // + // atomKK->sync(execution_space,datamask_read); + // if (eflag || vflag) atomKK->modified(execution_space,datamask_modify); + // else atomKK->modified(execution_space,F_MASK); + //atomKK->k_type.template sync(); x = atomKK->k_x.template view(); f = atomKK->k_f.template view(); neighborKK->k_anglelist.template sync(); anglelist = neighborKK->k_anglelist.template view(); int nanglelist = neighborKK->nanglelist; - atomKK->k_type.template sync(); d_type = atomKK->k_type.template view(); nlocal = atom->nlocal; newton_bond = force->newton_bond; From 1b9302299a409b858aa3ef365d5c3e3e105be8d6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 22:54:38 -0400 Subject: [PATCH 238/385] implement delete-all-images function with pushbutton in slideshow viewer --- tools/lammps-gui/TODO.md | 1 - tools/lammps-gui/icons/trash.png | Bin 0 -> 3648 bytes tools/lammps-gui/lammpsgui.qrc | 1 + tools/lammps-gui/slideshow.cpp | 16 +++++++++++++++- tools/lammps-gui/slideshow.h | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tools/lammps-gui/icons/trash.png diff --git a/tools/lammps-gui/TODO.md b/tools/lammps-gui/TODO.md index a8ce0285b5..7af2a4a4c6 100644 --- a/tools/lammps-gui/TODO.md +++ b/tools/lammps-gui/TODO.md @@ -2,7 +2,6 @@ LAMMPS-GUI TODO list: # Short term goals (v1.x) -- add "delete image files" option to Slide Show, plus pushbutton - add "export YAML data" to Output viewer, if YAML thermo data is detected. - add "export to YAML" to chart viewer. diff --git a/tools/lammps-gui/icons/trash.png b/tools/lammps-gui/icons/trash.png new file mode 100644 index 0000000000000000000000000000000000000000..723fc1435ae07bf1dfb622081fdb8de3eec00ec2 GIT binary patch literal 3648 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/system-box.png icons/system-help.png icons/system-run.png + icons/trash.png icons/utilities-terminal.png icons/vdw-style.png icons/vmd.png diff --git a/tools/lammps-gui/slideshow.cpp b/tools/lammps-gui/slideshow.cpp index 9275842b78..dcc85fc34a 100644 --- a/tools/lammps-gui/slideshow.cpp +++ b/tools/lammps-gui/slideshow.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,9 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) : tomovie->setToolTip("Export to movie file"); tomovie->setEnabled(has_exe("ffmpeg")); + auto *totrash = new QPushButton(QIcon(":/icons/trash.png"), ""); + totrash->setToolTip("Delete all image files"); + auto *gofirst = new QPushButton(QIcon(":/icons/go-first.png"), ""); gofirst->setToolTip("Go to first Image"); auto *goprev = new QPushButton(QIcon(":/icons/go-previous-2.png"), ""); @@ -101,6 +105,7 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) : normal->setToolTip("Reset zoom to normal"); connect(tomovie, &QPushButton::released, this, &SlideShow::movie); + connect(totrash, &QPushButton::released, this, &SlideShow::delete_images); connect(gofirst, &QPushButton::released, this, &SlideShow::first); connect(goprev, &QPushButton::released, this, &SlideShow::prev); connect(goplay, &QPushButton::released, this, &SlideShow::play); @@ -115,6 +120,7 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) : navLayout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum)); navLayout->addWidget(dummy); navLayout->addWidget(tomovie); + navLayout->addWidget(totrash); navLayout->addWidget(gofirst); navLayout->addWidget(goprev); navLayout->addWidget(goplay); @@ -157,6 +163,14 @@ void SlideShow::add_image(const QString &filename) } } +void SlideShow::delete_images() +{ + for (const auto &file : imagefiles) { + QFile::remove(file); + } + clear(); +} + void SlideShow::clear() { imagefiles.clear(); @@ -316,7 +330,7 @@ void SlideShow::prev() void SlideShow::loop() { auto *button = qobject_cast(sender()); - do_loop = !do_loop; + do_loop = !do_loop; button->setChecked(do_loop); } diff --git a/tools/lammps-gui/slideshow.h b/tools/lammps-gui/slideshow.h index 1b5e977643..4b13ff2e29 100644 --- a/tools/lammps-gui/slideshow.h +++ b/tools/lammps-gui/slideshow.h @@ -33,6 +33,7 @@ public: private slots: void quit(); + void delete_images(); void stop_run(); void movie(); void first(); From 2a1447ff037249de071f90cbfd2ea294735eec4a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 23:38:18 -0400 Subject: [PATCH 239/385] extract YAML format thermo data from output window text --- tools/lammps-gui/CMakeLists.txt | 2 +- tools/lammps-gui/TODO.md | 1 - tools/lammps-gui/lammpsgui.qrc | 1 + tools/lammps-gui/logwindow.cpp | 32 ++++++++++++++++++++++++++++++++ tools/lammps-gui/logwindow.h | 1 + 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 2a29f69933..381799bfb4 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(lammps-gui VERSION 1.6.0 LANGUAGES CXX) +project(lammps-gui VERSION 1.6.1 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) diff --git a/tools/lammps-gui/TODO.md b/tools/lammps-gui/TODO.md index 7af2a4a4c6..323c46fc57 100644 --- a/tools/lammps-gui/TODO.md +++ b/tools/lammps-gui/TODO.md @@ -2,7 +2,6 @@ LAMMPS-GUI TODO list: # Short term goals (v1.x) -- add "export YAML data" to Output viewer, if YAML thermo data is detected. - add "export to YAML" to chart viewer. - implement indenting regions for (nested) loops? diff --git a/tools/lammps-gui/lammpsgui.qrc b/tools/lammps-gui/lammpsgui.qrc index 8b8f7f950e..fe1129a4a3 100644 --- a/tools/lammps-gui/lammpsgui.qrc +++ b/tools/lammps-gui/lammpsgui.qrc @@ -59,5 +59,6 @@ icons/vmd.png icons/window-close.png icons/x-office-drawing.png + icons/yaml-file-icon.png diff --git a/tools/lammps-gui/logwindow.cpp b/tools/lammps-gui/logwindow.cpp index 05887c329c..9997f51bfc 100644 --- a/tools/lammps-gui/logwindow.cpp +++ b/tools/lammps-gui/logwindow.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,8 @@ LogWindow::LogWindow(const QString &_filename, QWidget *parent) : auto *action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_S), this); connect(action, &QShortcut::activated, this, &LogWindow::save_as); + action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y), this); + connect(action, &QShortcut::activated, this, &LogWindow::extract_yaml); action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this); connect(action, &QShortcut::activated, this, &LogWindow::quit); action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), this); @@ -94,6 +97,31 @@ void LogWindow::save_as() file.close(); } +void LogWindow::extract_yaml() +{ + QString defaultname = filename + ".yaml"; + if (filename.isEmpty()) defaultname = "lammps.yaml"; + QString yamlFileName = QFileDialog::getSaveFileName(this, "Save YAML data to File", defaultname, + "YAML files (*.yaml *.yml)"); + if (yamlFileName.isEmpty()) return; + + QFileInfo path(yamlFileName); + QFile file(path.absoluteFilePath()); + + if (!file.open(QIODevice::WriteOnly | QFile::Text)) { + QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); + return; + } + + QRegularExpression is_yaml("^(keywords:.*$|data:$|---$|\\.\\.\\.$| - \\[.*\\]$)"); + QTextStream out(&file); + QStringList lines = toPlainText().split('\n'); + for (const auto &line : lines) { + if (is_yaml.match(line).hasMatch()) out << line << '\n'; + } + file.close(); +} + void LogWindow::contextMenuEvent(QContextMenuEvent *event) { // show augmented context menu @@ -103,6 +131,10 @@ void LogWindow::contextMenuEvent(QContextMenuEvent *event) action->setIcon(QIcon(":/icons/document-save-as.png")); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S)); connect(action, &QAction::triggered, this, &LogWindow::save_as); + action = menu->addAction(QString("&Export YAML Data to File ...")); + action->setIcon(QIcon(":/icons/yaml-file-icon.png")); + action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y)); + connect(action, &QAction::triggered, this, &LogWindow::extract_yaml); action = menu->addAction("&Close Window", this, &QWidget::close); action->setIcon(QIcon(":/icons/window-close.png")); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W)); diff --git a/tools/lammps-gui/logwindow.h b/tools/lammps-gui/logwindow.h index ad0691d0cc..93ba06fbe7 100644 --- a/tools/lammps-gui/logwindow.h +++ b/tools/lammps-gui/logwindow.h @@ -23,6 +23,7 @@ public: LogWindow(const QString &filename, QWidget *parent = nullptr); private slots: + void extract_yaml(); void quit(); void save_as(); void stop_run(); From d277a12e43b0dd1b7228a50c5acd8012256ac3ee Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 16 Jul 2024 23:44:46 -0400 Subject: [PATCH 240/385] add missing icon file --- tools/lammps-gui/icons/yaml-file-icon.png | Bin 0 -> 4403 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/lammps-gui/icons/yaml-file-icon.png diff --git a/tools/lammps-gui/icons/yaml-file-icon.png b/tools/lammps-gui/icons/yaml-file-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a936100b8d85750582310bde5b4ae4721c8f78fc GIT binary patch literal 4403 zcmeHLYj6|S6<)<=ENpCEo?sqL*7Ahd46A+WwUPY55|)A`gkP}>1XlZyH%Qt=T3fOq zA(+&L4&~8?*5eQu6Oy>01w1h(PRNikDJE%$($F|0(4@&^h*J`rsVNXbp?4*}m}aK& zO!Ln>v)aAqe&@UAeD~Ztd$rB$DM?SAmkL2py31)V15Zr7wMpQ2?WL*5z@xXZqFO0q zqOcs61TnzFN`uV9d`uJ|DE3j%yK>ekSbO`6Ok0!nKy1PJgXEhKM?Jv}H zuiAd?fnGYTvUknN?YRqwwpl;v?P#8Peg-z}qnlOlR{rr{X;=0M16q03^L=-E=3M-^ z`@$ooU1XRL`f+H3R(|zhR*qllYVLO&S=;*Ik~?3237ybfT2Yg};qhJV5TtoZEH3uC zii=0G0Xgh_a<|R7WJOl<{td|XftEAb2R_Z{e|DLJ`t_7qSzG6J7?e%#B@eoIV`K=v>g3qQu<-fw6?mOXH&D3tH|Jx1bo58oDf2cdTW7UoCvNkT4MZ@j+ zm94j+H7~YLncf~vJ9}haTX))=i`X~S-r%u?-$IsOZ9ZN;;3>MBuIM-Pygz8^X|c~e z@WIhdP)^OjYOym~5((YC{@0=JG-O}+7k{35w+GZ)OaygR?JlKRDX3>S$;azsK^YVr z1X&AWGQ+Op71+o7#gI)m_{K>cEOIv8V+J?omW%mX(b*X0%NsovY~woC!s!a~Q>`%? z5CnOJfn&iyC_=|WIgX0ioolRHm_QJ(dn1?AnrN3d@M?D`>a>i3|?5Mw77Y@YJ;aHRp@Ie5LfKl;#hAeTpy`vtg1b#6n$Gw2q z_aGHf7!&KB*wmhQI^zQY?xVc-pht3#g8|CzrtK12r-tXU+jQ#qG$*klN5@}{M&4k? zZ~`HX1dmV*Z$x}P0!IXvr%X6b5}ZJdqjH5J3KL>^l?ssSMZja^FhQ_zBqETMfKWJV zMl41`Kv|5T6kPRA!Tam`#is5iA%_ zaRv)+Ah*EMn-VLkoL`@4C7J;-zLa1%z9?vhO{5TE>iLAifGg3()-oYK4|b2? zaviaY-%|<}Gr{;s5I@EFID}#;24Q>_9N~>TDVQ(=$(R#ajj~51L5VV9zQ_-B1X_Xe zjB5qw#wRK-uGuI$TFa}m00cuY6EY?kIV>1DoG_~H86z26(f`uK8V8KqWPo471~xCS z7oww^;jm^Pf*SONEt|(nUtBH|KPis!1TP!UR2@i`?`Nw z#?zQK`P`>>ep7#b(LeLHteA6J-Xa0=z-7oDre5QWs!YX*0z9@6`7I+o( z;E|_Sdhcu9S(%ihmG93hEW0*;bM~||8P}5T*P4|5M}3~I*vyV0I5zt$d2ywUyqsLP zYH(-EjEEGAo!Y_E}@xw~m-z|mR11VDet!7bkeemtg=}J;E U`dG%*eIQWC Date: Wed, 17 Jul 2024 01:16:37 -0400 Subject: [PATCH 241/385] Update pair_lj_spica_coul_long.cpp --- src/CG-SPICA/pair_lj_spica_coul_long.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CG-SPICA/pair_lj_spica_coul_long.cpp b/src/CG-SPICA/pair_lj_spica_coul_long.cpp index ed6cb17e7c..176c076da9 100644 --- a/src/CG-SPICA/pair_lj_spica_coul_long.cpp +++ b/src/CG-SPICA/pair_lj_spica_coul_long.cpp @@ -358,7 +358,7 @@ void PairLJSPICACoulLong::coeff(int narg, char **arg) void PairLJSPICACoulLong::init_style() { - if (!atom->q_flag) error->all(FLERR, "Pair style lj/cut/coul/long requires atom attribute q"); + if (!atom->q_flag) error->all(FLERR, "Pair style lj/spica/coul/long requires atom attribute q"); neighbor->add_request(this); From 5afde3f0f5cc85217592cf8048d6c8d0739f6ba6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 17 Jul 2024 04:14:51 -0400 Subject: [PATCH 242/385] export to YAML functionality is only available if there is YAML format data --- tools/lammps-gui/CMakeLists.txt | 2 +- tools/lammps-gui/logwindow.cpp | 29 +++++++++++++++++++++++------ tools/lammps-gui/logwindow.h | 2 ++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 381799bfb4..c03cb58a69 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(lammps-gui VERSION 1.6.1 LANGUAGES CXX) +project(lammps-gui VERSION 1.6.2 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) diff --git a/tools/lammps-gui/logwindow.cpp b/tools/lammps-gui/logwindow.cpp index 9997f51bfc..fa12dcf483 100644 --- a/tools/lammps-gui/logwindow.cpp +++ b/tools/lammps-gui/logwindow.cpp @@ -30,6 +30,8 @@ #include #include +const QString LogWindow::yaml_regex = QStringLiteral("^(keywords:.*$|data:$|---$|\\.\\.\\.$| - \\[.*\\]$)"); + LogWindow::LogWindow(const QString &_filename, QWidget *parent) : QPlainTextEdit(parent), filename(_filename) { @@ -97,23 +99,35 @@ void LogWindow::save_as() file.close(); } +bool LogWindow::check_yaml() +{ + QRegularExpression is_yaml(yaml_regex); + QStringList lines = toPlainText().split('\n'); + for (const auto &line : lines) + if (is_yaml.match(line).hasMatch()) return true; + return false; +} + void LogWindow::extract_yaml() { + // ignore if no YAML format lines in buffer + if (!check_yaml()) return; + QString defaultname = filename + ".yaml"; if (filename.isEmpty()) defaultname = "lammps.yaml"; QString yamlFileName = QFileDialog::getSaveFileName(this, "Save YAML data to File", defaultname, "YAML files (*.yaml *.yml)"); + // cannot save without filename if (yamlFileName.isEmpty()) return; QFileInfo path(yamlFileName); QFile file(path.absoluteFilePath()); - if (!file.open(QIODevice::WriteOnly | QFile::Text)) { QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); return; } - QRegularExpression is_yaml("^(keywords:.*$|data:$|---$|\\.\\.\\.$| - \\[.*\\]$)"); + QRegularExpression is_yaml(yaml_regex); QTextStream out(&file); QStringList lines = toPlainText().split('\n'); for (const auto &line : lines) { @@ -131,10 +145,13 @@ void LogWindow::contextMenuEvent(QContextMenuEvent *event) action->setIcon(QIcon(":/icons/document-save-as.png")); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S)); connect(action, &QAction::triggered, this, &LogWindow::save_as); - action = menu->addAction(QString("&Export YAML Data to File ...")); - action->setIcon(QIcon(":/icons/yaml-file-icon.png")); - action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y)); - connect(action, &QAction::triggered, this, &LogWindow::extract_yaml); + // only show export-to-yaml entry if there is YAML format content. + if (check_yaml()) { + action = menu->addAction(QString("&Export YAML Data to File ...")); + action->setIcon(QIcon(":/icons/yaml-file-icon.png")); + action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y)); + connect(action, &QAction::triggered, this, &LogWindow::extract_yaml); + } action = menu->addAction("&Close Window", this, &QWidget::close); action->setIcon(QIcon(":/icons/window-close.png")); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W)); diff --git a/tools/lammps-gui/logwindow.h b/tools/lammps-gui/logwindow.h index 93ba06fbe7..b6cf78c48f 100644 --- a/tools/lammps-gui/logwindow.h +++ b/tools/lammps-gui/logwindow.h @@ -32,9 +32,11 @@ protected: void closeEvent(QCloseEvent *event) override; void contextMenuEvent(QContextMenuEvent *event) override; bool eventFilter(QObject *watched, QEvent *event) override; + bool check_yaml(); private: QString filename; + static const QString yaml_regex; }; #endif From de95eb907af9979519cdfa5a76630b7a22e8b6fd Mon Sep 17 00:00:00 2001 From: jtclemm Date: Wed, 17 Jul 2024 11:53:01 -0600 Subject: [PATCH 243/385] Clarifying comment on breakage in bond hybrid --- src/bond_hybrid.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bond_hybrid.cpp b/src/bond_hybrid.cpp index 1e3e3c66f9..307cbd72fd 100644 --- a/src/bond_hybrid.cpp +++ b/src/bond_hybrid.cpp @@ -142,8 +142,10 @@ void BondHybrid::compute(int eflag, int vflag) } } - // if bond type can be set to zero and deleted, update bondlist_orig - tagint *tag = atom->tag; + // If bond style can be deleted by setting type to zero (BPM or quartic), update bondlist_orig + // Otherwise, bond type could be restored back to its original value during reneighboring + // Use orig_map to propagate changes from temporary bondlist array back to original array + if (partial_flag) { for (m = 0; m < nstyles; m++) { for (i = 0; i < nbondlist[m]; i++) { From 1e7569555821406f5f895328ae727c52deb61825 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 17 Jul 2024 05:48:04 -0400 Subject: [PATCH 244/385] Updating LAMMPS GUI documentation for version 1.6 --- doc/src/Howto_lammps_gui.rst | 137 ++++++++++++++++------------- doc/src/JPG/lammps-gui-chart.png | Bin 107306 -> 89581 bytes doc/src/JPG/lammps-gui-log.png | Bin 97687 -> 105351 bytes doc/src/JPG/lammps-gui-main.png | Bin 92717 -> 95633 bytes doc/src/JPG/lammps-gui-running.png | Bin 21391 -> 24963 bytes doc/src/JPG/lammps-gui-yaml.png | Bin 0 -> 174862 bytes doc/src/Tools.rst | 54 ++++++------ 7 files changed, 104 insertions(+), 87 deletions(-) create mode 100644 doc/src/JPG/lammps-gui-yaml.png diff --git a/doc/src/Howto_lammps_gui.rst b/doc/src/Howto_lammps_gui.rst index d6c98c5b2b..dd85df5498 100644 --- a/doc/src/Howto_lammps_gui.rst +++ b/doc/src/Howto_lammps_gui.rst @@ -19,25 +19,28 @@ to the online LAMMPS documentation for known LAMMPS commands and styles. Pre-compiled, ready-to-use LAMMPS GUI executables for Linux (Ubuntu 20.04LTS or later and compatible), macOS (version 11 aka Big Sur or later), and Windows (version 10 or later) :ref:`are available - ` for download. They may be linked to a - development version of LAMMPS in case they need features not yet - available in a released version. Serial LAMMPS executables of the - same LAMMPS version are included as well. The source code for the - LAMMPS GUI is included in the LAMMPS source code and can be found in - the ``tools/lammps-gui`` folder. It can be compiled alongside LAMMPS - when :doc:`compiling with CMake `. + ` for download. None-MPI LAMMPS executables of + the same LAMMPS version are included in these packages as well. The + source code for the LAMMPS GUI is included in the LAMMPS source code + distribution and can be found in the ``tools/lammps-gui`` folder. It + can be compiled alongside LAMMPS when :doc:`compiling with CMake + `. LAMMPS GUI tries to provide an experience similar to what people -traditionally would do to run LAMMPS using a command line window: +traditionally would do to run LAMMPS using a command line window +but just rolled into a single executable: + +- editing LAMMPS input files with a text editor +- run LAMMPS on those input file with selected command line flags +- use or extract data from the created files and visualize it with + either a molecular visualization program or a plotting program -- editing inputs with a text editor -- run LAMMPS on the input with selected command line flags -- and then use or extract data from the created files and visualize it That procedure is quite effective for people proficient in using the command line, as that allows them to use tools for the individual steps -which they are most comfortable with. It is often required when running -LAMMPS on high-performance computing facilities. +that they are most comfortable with. It is often *required* to adopt +this workflow when running LAMMPS simulations on high-performance +computing facilities. The main benefit of using the LAMMPS GUI application instead is that many basic tasks can be done directly from the GUI without switching to @@ -51,23 +54,22 @@ since you only need to learn how to use a single program for most tasks and thus time can be saved and people can focus on learning LAMMPS. It is also designed to keep the barrier low when you decide to switch to a full featured, standalone programming editor and more sophisticated -visualization and analysis tools and run LAMMPS from a command line. +visualization and analysis tools, and run LAMMPS from the command line +or a batch script. The following text provides a detailed tour of the features and -functionality of the LAMMPS GUI. - -Suggestions for new features and reports of bugs are always welcome. -You can use the :doc:`the same channels as for LAMMPS itself -` for that purpose. +functionality of the LAMMPS GUI. Suggestions for new features and +reports of bugs are always welcome. You can use the :doc:`the same +channels as for LAMMPS itself ` for that purpose. ----- Main window ----------- -When LAMMPS GUI starts, it will show a main window with either an -empty buffer or the contents of a loaded file. In the latter case it -may look like the following: +When LAMMPS GUI starts, it will show a main window, the editor, with +either an empty buffer or the contents of a loaded file. In the latter +case it may look like the following: .. image:: JPG/lammps-gui-main.png :align: center @@ -91,10 +93,12 @@ argument as a LAMMPS input script, further arguments are ignored. When no argument is given, LAMMPS GUI will start with an empty buffer. Files can also be opened via the ``File`` menu or by drag-and-drop of a file from a graphical file manager into the editor window. Only one -file can be open at a time, so opening a new file with a filled buffer -will close the buffer. If the buffer has unsaved modifications, you +file can be edited at a time, so opening a new file with a filled buffer +will close that buffer. If the buffer has unsaved modifications, you will be asked to either cancel the operation, discard the changes, or -save them. +save them. A buffer with modifications can be saved any time from the +"File" menu, by the keyboard shortcut `Ctrl-S` (`Command-S` on macOS), +or by clicking on the "Save" button at the very left in the status bar. Running LAMMPS ^^^^^^^^^^^^^^ @@ -103,9 +107,9 @@ From within the LAMMPS GUI main window LAMMPS can be started either from the ``Run`` menu using the ``Run LAMMPS from Editor Buffer`` entry, by the keyboard shortcut `Ctrl-Enter` (`Command-Enter` on macOS), or by clicking on the green "Run" button in the status bar. All of these -operations will cause LAMMPS to process the entire input script, which -may contain multiple :doc:`run ` or :doc:`minimize ` -commands. +operations will cause LAMMPS to process the entire input script in the +editor buffer, which may contain multiple :doc:`run ` or +:doc:`minimize ` commands. LAMMPS runs in a separate thread, so the GUI stays responsive and is able to interact with the running calculation and access data it @@ -131,15 +135,11 @@ the left side there is a text indicating that LAMMPS is running, which will also show the number of active threads, if thread-parallel acceleration was selected in the ``Preferences`` dialog. On the right side, a progress bar is shown that displays the estimated progress for -the current :doc:`run command `. +the current :doc:`run ` or :doc:`minimize ` command. Also, the line number of the currently executed command will be highlighted in green. -.. image:: JPG/lammps-gui-run-highlight.png - :align: center - :scale: 75% - If an error occurs (in the example below the command :doc:`label 5_>7`4}_|JjdHOu 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 F{{?51w&MT* diff --git a/doc/src/JPG/lammps-gui-main.png b/doc/src/JPG/lammps-gui-main.png index f700b4264f71bb428b983c37662e9a56d529f071..69efe3db68036c1a833af6fee22f1d40089b5a37 100644 GIT binary patch literal 95633 zcmZsC1yEeg67Jc>9YU}WBxr)WdvJogTY%seT!T9S5?lho-QC>@?rwnv7Pmzn|9|hT zdavr8Jyknr>TFeS&-8SE{dI>cDM(?UzCi^507FJvTm=B&A^-q%jtqX8p#T-oy?nu2 zh{}rsKvgW-gE7KC(_baDzN*@re|0lIspVHqL7t(GOE%GVgvUf!_sRy2>y$`8M!(2s2$d<>I_{Tw^xyY%ts7uR*#q zcQcO>MT;b021_Wv{^x$IGw?dT%AcozJ>xSQ%rq!w<>pe=={(*bNdET)$XfyTLHSLM zijoG}qI5xS5^mR(T$uztJ-w%s)AtcMFL$9|()aHhPmj2=Bg6Msk^BziDG1na-wK%Y zo_6rF{QJuLLql1bgt7Kre5{{HfZf@a#C8QSbbI^4P3nJ=csahMjSKU6^p?0LE@r%W zJR2aBGh9PooSJGqU^HULSUrCK5`a3_v-~W@Zva-?v&{I*F>P5j#tv?s=n=WmT9Wg^}>$izZ{$$=( zK1u`s<}!~@KhFRC%Y#v2{bDOdh*d&(G9$}hP7Q;y$uHNmSvn5u*dfMGbFTkUjqBoDH7W!BFCNhPQu$|QN zUDRFq^ud<$d%3)OoDyo`n-yY>k}G>F%>O9Dg%P`MRZaaInO+t>f>$rqD`CYpKIxf0 z{c28q{WOSWlGXXKhihJ=-MVlc?{$JfreBE`{ytfK6^DKE6ii#QW1!-5A=rqFw^RR~ zu>CB!hgE)`?})w=n+;4Q#0%Xnc%txp^{b_z_`JigiWt=KtR;tt*=9szHx3eF{rp6-rg^ly zKUKC9e5ks+UqjC+SrZ&45jCv8L%c(eMFJl;Wl8&&9&JPsinKw(zcR*L%}z2q($oQfeRskJ<^4HXVx5|O400<`#b z{|x%}fxUO3IKi8FRy_OuG7H8gTkL_&0w7_3Dcx%AK0`){P~$reLKUoP@cfGH2+@;r zsm{_}Ly5tUV;#rj!ubLZU?T%xHnTyL!Ncu0?i!0t>=wK+X@WP*@`@zgf4_lIIKa7L zw3x?XA7dYnnF=hErt#%mFh{H<)*Sa;#I2~Ubo1T`Pg7fca??Vv$ zuMP(qJyKuWy?G5{$>A>%Z77A2ygm*Dak#t1&t7Tjnw^XSLpx~ zU=j>K7WXz{mZo?M=wCNUO`u1PhK`vq3a7a?GmYT8ShK{*>KcGi;4zF4AQ)i)I2*O{ zn>t+Cvz1%Pg|45%Xdb7_HN)e*+I8Ht-sE8f2JxZ4<9jMYF~CFvu3#v0rT*xO+o_<1{<+voCf; ze}Hb4=Ev@YhNrM8Yew;V??Gno$ofOm!0V424xyV%l*@I(cWaq)iXOl7f8~(+Q~Zi8 zr>Yt5oY#Ead{^&jFcg+6PQK`ohZ61?rZ-_>f$JaFh%1-z(K18$Rp;eX=G%eUrB>g& zGXeX#-5+z9@W2nNXuyQx2c_vQIw4ro87h5DZ4nc9X{s#=X31%++Qtpkd(+<_dHdt? z21olTMAx5?3iWjdf9%MJR3)czjclJ`FPN?#8D92^LR7f1(Xd&&_ zo0kla^17<1_AI*(=ANoKc0EeT2_BbppUuTzwz3lxTe)Y3wgjL=MyiHj07@Ayg;dN9 z22!P56gcccR*ql9!26CxI5b?÷o$p0gwdL$(xRi!+V+n+?Hu*fUC8C6%ZC9~<- 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