// 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: Trung Nguyen (U Chicago) Mitch Murphy (alphataubio at gmail) ------------------------------------------------------------------------- */ #include "fix_efield_kokkos.h" #include "atom_kokkos.h" #include "atom_masks.h" #include "domain_kokkos.h" #include "error.h" #include "input.h" #include "kokkos_base.h" #include "memory_kokkos.h" #include "modify_kokkos.h" #include "region.h" #include "update.h" #include "variable.h" using namespace LAMMPS_NS; using namespace FixConst; enum{NONE,CONSTANT,EQUAL,ATOM}; /* ---------------------------------------------------------------------- */ template FixEfieldKokkos::FixEfieldKokkos(LAMMPS *lmp, int narg, char **arg) : FixEfield(lmp, narg, arg) { kokkosable = 1; atomKK = (AtomKokkos *) atom; execution_space = ExecutionSpaceFromDevice::space; datamask_read = X_MASK | F_MASK | TORQUE_MASK | Q_MASK | MU_MASK | IMAGE_MASK | MASK_MASK; datamask_modify = F_MASK | TORQUE_MASK; memory->destroy(efield); memoryKK->create_kokkos(k_efield,efield,maxatom,4,"efield:efield"); d_efield = k_efield.template view(); } /* ---------------------------------------------------------------------- */ template FixEfieldKokkos::~FixEfieldKokkos() { if (copymode) return; memoryKK->destroy_kokkos(k_efield,efield); memoryKK->destroy_kokkos(k_vatom,vatom); } /* ---------------------------------------------------------------------- */ template void FixEfieldKokkos::init() { FixEfield::init(); if (utils::strmatch(update->integrate_style,"^respa")) error->all(FLERR,"Cannot (yet) use respa with Kokkos"); } /* ---------------------------------------------------------------------- */ template void FixEfieldKokkos::post_force(int vflag) { atomKK->sync(execution_space, datamask_read); d_x = atomKK->k_x.template view(); d_f = atomKK->k_f.template view(); d_q = atomKK->k_q.template view(); d_mu = atomKK->k_mu.template view(); d_torque = atomKK->k_torque.template view(); d_image = atomKK->k_image.template view(); d_mask = atomKK->k_mask.template view(); int nlocal = atomKK->nlocal; // virial setup v_init(vflag); // reallocate per-atom arrays if necessary if (vflag_atom) { memoryKK->destroy_kokkos(k_vatom,vatom); memoryKK->create_kokkos(k_vatom,vatom,maxvatom,"efield:vatom"); d_vatom = k_vatom.template view(); } // update region if necessary if (region) { if (!utils::strmatch(region->style, "^block")) error->all(FLERR,"Cannot (yet) use {}-style region with fix efield/kk",region->style); region->prematch(); DAT::tdual_int_1d k_match = DAT::tdual_int_1d("efield:k_match",nlocal); KokkosBase* regionKKBase = dynamic_cast(region); regionKKBase->match_all_kokkos(groupbit,k_match); k_match.template sync(); d_match = k_match.template view(); } // reallocate sforce array if necessary if (varflag == ATOM && atom->nmax > maxatom) { maxatom = atom->nmax; memoryKK->destroy_kokkos(k_efield,efield); memoryKK->create_kokkos(k_efield,efield,maxatom,4,"efield:efield"); d_efield = k_efield.view(); } force_flag = 0; double result[10] = {0.0}; if (varflag == CONSTANT) { prd = domain->prd; h = domain->h; triclinic = domain->triclinic; copymode = 1; if(qflag && muflag) Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); else if(qflag && !muflag) Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); else if(!qflag && muflag) Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); else Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); copymode = 0; // variable force, wrap with clear/add } else { atomKK->sync(Host,ALL_MASK); // this can be removed when variable class is ported to Kokkos FixEfield::update_efield_variables(); if (varflag == ATOM) { // this can be removed when variable class is ported to Kokkos k_efield.modify(); k_efield.sync(); } copymode = 1; if(qflag && muflag) Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); else if(qflag && !muflag) Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); else if(!qflag && muflag) Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); else Kokkos::parallel_reduce(Kokkos::RangePolicy >(0,nlocal),*this,result); copymode = 0; } atomKK->modified(execution_space, datamask_modify); fsum[0]=result[0]; fsum[1]=result[1]; fsum[2]=result[2]; fsum[3]=result[3]; if (vflag_global) { virial[0] += result[4]; virial[1] += result[5]; virial[2] += result[6]; virial[3] += result[7]; virial[4] += result[8]; virial[5] += result[9]; } if (vflag_atom) { k_vatom.template modify(); k_vatom.template sync(); } } template template KOKKOS_INLINE_FUNCTION void FixEfieldKokkos::operator()(TagFixEfieldConstant, const int &i, value_type result) const { if ( QFLAG && (d_mask(i) & groupbit)) { if (region && !d_match[i]) return; Few x_i; x_i[0] = d_x(i,0); x_i[1] = d_x(i,1); x_i[2] = d_x(i,2); auto unwrapKK = DomainKokkos::unmap(prd,h,triclinic,x_i,d_image(i)); const F_FLOAT fx = d_q(i) * ex; const F_FLOAT fy = d_q(i) * ey; const F_FLOAT fz = d_q(i) * ez; d_f(i,0) += fx; d_f(i,1) += fy; d_f(i,2) += fz; result[0] -= fx * unwrapKK[0] + fy * unwrapKK[1] + fz * unwrapKK[2]; result[1] += fx; result[2] += fy; result[3] += fz; if (evflag) { double v[6]; v[0] = fx * unwrapKK[0]; v[1] = fy * unwrapKK[1]; v[2] = fz * unwrapKK[2]; v[3] = fx * unwrapKK[1]; v[4] = fx * unwrapKK[2]; v[5] = fy * unwrapKK[2]; v_tally(result, i, v); } } if (MUFLAG && (d_mask(i) & groupbit)) { if (region && !d_match[i]) return; d_torque(i,0) += ez * d_mu(i,1) - ey * d_mu(i,2); d_torque(i,1) += ex * d_mu(i,2) - ez * d_mu(i,0); d_torque(i,2) += ey * d_mu(i,0) - ex * d_mu(i,1); result[0] -= d_mu(i,0) * ex + d_mu(i,1) * ey + d_mu(i,2) * ez; } } template template KOKKOS_INLINE_FUNCTION void FixEfieldKokkos::operator()(TagFixEfieldNonConstant, const int &i, value_type result) const { if ( QFLAG && (d_mask(i) & groupbit)) { if (region && !d_match[i]) return; F_FLOAT fx, fy, fz; if (xstyle == ATOM) fx = qe2f * d_q(i) * d_efield(i,0); else fx = d_q(i) * ex; if (ystyle == ATOM) fy = qe2f * d_q(i) * d_efield(i,1); else fy = d_q(i) * ey; if (zstyle == ATOM) fz = qe2f * d_q(i) * d_efield(i,2); else fz = d_q(i) * ez; d_f(i,0) += fx; d_f(i,1) += fy; d_f(i,2) += fz; result[1] += fx; result[2] += fy; result[3] += fz; if (pstyle == ATOM) result[0] += qe2f * d_q(i) * d_efield(i,3); else if (estyle == ATOM) result[0] += d_efield(i,3); } if (MUFLAG && (d_mask(i) & groupbit)) { if (region && !d_match[i]) return; d_torque(i,0) += ez * d_mu(i,1) - ey * d_mu(i,2); d_torque(i,1) += ex * d_mu(i,2) - ez * d_mu(i,0); d_torque(i,2) += ey * d_mu(i,0) - ex * d_mu(i,1); } } /* ---------------------------------------------------------------------- tally virial into global and per-atom accumulators i = local index of atom v = total virial for the interaction increment global virial by v increment per-atom virial by v this method can be used when fix computes forces in post_force() and the force depends on a distance to some external object e.g. fix wall/lj93: compute virial only on owned atoms ------------------------------------------------------------------------- */ template KOKKOS_INLINE_FUNCTION void FixEfieldKokkos::v_tally(value_type result, int i, double *v) const { if (vflag_global) { result[4] += v[0]; result[5] += v[1]; result[6] += v[2]; result[7] += v[3]; result[8] += v[4]; result[9] += v[5]; } if (vflag_atom) { Kokkos::atomic_add(&(d_vatom(i,0)),v[0]); Kokkos::atomic_add(&(d_vatom(i,1)),v[1]); Kokkos::atomic_add(&(d_vatom(i,2)),v[2]); Kokkos::atomic_add(&(d_vatom(i,3)),v[3]); Kokkos::atomic_add(&(d_vatom(i,4)),v[4]); Kokkos::atomic_add(&(d_vatom(i,5)),v[5]); } } namespace LAMMPS_NS { template class FixEfieldKokkos; #ifdef LMP_KOKKOS_GPU template class FixEfieldKokkos; #endif }