diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index fe6c17801e..38da364903 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -109,6 +109,11 @@ if(PKG_KSPACE) endif() endif() + +if(PKG_PHONON) + list(APPEND KOKKOS_PKG_SOURCES ${KOKKOS_PKG_SOURCES_DIR}/dynamical_matrix_kokkos.cpp) +endif() + set_property(GLOBAL PROPERTY "KOKKOS_PKG_SOURCES" "${KOKKOS_PKG_SOURCES}") # detects styles which have KOKKOS version diff --git a/src/Depend.sh b/src/Depend.sh index af88f24bb4..15a8f84d23 100755 --- a/src/Depend.sh +++ b/src/Depend.sh @@ -131,6 +131,10 @@ if (test $1 = "PYTHON") then depend ML-IAP fi +if (test $1 = "PHONON") then + depend KOKKOS +fi + if (test $1 = "RIGID") then depend KOKKOS depend OPENMP diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index 04bf84ed31..cc3f3907af 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -106,6 +106,8 @@ action dihedral_opls_kokkos.cpp dihedral_opls.cpp action dihedral_opls_kokkos.h dihedral_opls.h action domain_kokkos.cpp action domain_kokkos.h +action dynamical_matrix_kokkos.cpp dynamical_matrix.cpp +action dynamical_matrix_kokkos.h dynamical_matrix.h action fftdata_kokkos.h fft3d.h action fft3d_kokkos.cpp fft3d.cpp action fft3d_kokkos.h fft3d.h diff --git a/src/KOKKOS/dynamical_matrix_kokkos.cpp b/src/KOKKOS/dynamical_matrix_kokkos.cpp new file mode 100644 index 0000000000..f9f871d01a --- /dev/null +++ b/src/KOKKOS/dynamical_matrix_kokkos.cpp @@ -0,0 +1,338 @@ +// clang-format off +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, 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. + ----------------------------------------------------------------------- */ + +// +// Created by charlie sievers on 6/21/18. +// + +#include "dynamical_matrix_kokkos.h" + +#include "angle.h" +#include "atom_kokkos.h" +#include "atom_masks.h" +#include "bond.h" +#include "comm.h" +#include "compute.h" +#include "dihedral.h" +#include "domain.h" +#include "error.h" +#include "finish.h" +#include "force.h" +#include "group.h" +#include "improper.h" +#include "kokkos.h" +#include "kspace.h" +#include "memory.h" +#include "modify.h" +#include "neighbor.h" +#include "pair.h" +#include "timer.h" +#include "update.h" + +#include +#include +#include + +using namespace LAMMPS_NS; +enum{REGULAR,ESKM}; + +template +struct ForceAdder { + ViewA a; + ViewB b; + ForceAdder(const ViewA& a_, const ViewB& b_):a(a_),b(b_) {} + KOKKOS_INLINE_FUNCTION + void operator() (const int& i) const { + a(i,0) += b(i,0); + a(i,1) += b(i,1); + a(i,2) += b(i,2); + } +}; + +/* ---------------------------------------------------------------------- */ + +template +struct Zero { + View v; + Zero(const View &v_):v(v_) {} + KOKKOS_INLINE_FUNCTION + void operator()(const int &i) const { + v(i,0) = 0; + v(i,1) = 0; + v(i,2) = 0; + } +}; + +/* ---------------------------------------------------------------------- */ + +DynamicalMatrixKokkos::DynamicalMatrixKokkos(LAMMPS *lmp) : DynamicalMatrix(lmp) +{ + atomKK = (AtomKokkos *) atom; +} + +/* ---------------------------------------------------------------------- */ + +DynamicalMatrixKokkos::~DynamicalMatrixKokkos() +{ + +} + +/* ---------------------------------------------------------------------- */ + +void DynamicalMatrixKokkos::command(int narg, char **arg) +{ + atomKK->sync(Host, X_MASK|RMASS_MASK|TYPE_MASK); + DynamicalMatrix::command(narg, arg); +} + +/* ---------------------------------------------------------------------- + setup without output or one-time post-init setup + flag = 0 = just force calculation + flag = 1 = reneighbor and force calculation +------------------------------------------------------------------------- */ + +void DynamicalMatrixKokkos::setup() +{ + lmp->kokkos->auto_sync = 1; + + // setup domain, communication and neighboring + // acquire ghosts + // build neighbor lists + if (triclinic) domain->x2lamda(atom->nlocal); + domain->pbc(); + domain->reset_box(); + if (neighbor->style) neighbor->setup_bins(); + comm->exchange(); + comm->borders(); + if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); + domain->image_check(); + domain->box_too_small_check(); + neighbor->build(1); + + // compute all forces + if (!modify->get_fix_by_id("package_omp")) external_force_clear = 1; + eflag=0; + vflag=0; + update_force(); + + if (pair_compute_flag) { + atomKK->sync(force->pair->execution_space,force->pair->datamask_read); + force->pair->compute(eflag,vflag); + atomKK->modified(force->pair->execution_space,force->pair->datamask_modify); + } + else if (force->pair) force->pair->compute_dummy(eflag,vflag); + update->setupflag = 0; + + lmp->kokkos->auto_sync = 0; +} + +/* ---------------------------------------------------------------------- + evaluate potential energy and forces + may migrate atoms due to reneighboring + return new energy, which should include nextra_global dof + return negative gradient stored in atom->f + return negative gradient for nextra_global dof in fextra +------------------------------------------------------------------------- */ + +void DynamicalMatrixKokkos::update_force() +{ + int n_pre_force = modify->n_pre_force; + int n_pre_reverse = modify->n_pre_reverse; + int n_post_force = modify->n_post_force; + + lmp->kokkos->auto_sync = 0; + + f_merge_copy = DAT::t_f_array("DynamicalMatrixKokkos::f_merge_copy",atomKK->k_f.extent(0)); + + atomKK->sync(Device,X_MASK); + + force_clear(); + + neighbor->decide(); // needed for intel potentials to work + + + if (n_pre_force) { + modify->pre_force(vflag); + timer->stamp(Timer::MODIFY); + } + + bool execute_on_host = false; + unsigned int datamask_read_device = 0; + unsigned int datamask_modify_device = 0; + unsigned int datamask_read_host = 0; + + if (pair_compute_flag) { + if (force->pair->execution_space==Host) { + execute_on_host = true; + datamask_read_host |= force->pair->datamask_read; + datamask_modify_device |= force->pair->datamask_modify; + } else { + datamask_read_device |= force->pair->datamask_read; + datamask_modify_device |= force->pair->datamask_modify; + } + } + if (atomKK->molecular && force->bond) { + if (force->bond->execution_space==Host) { + execute_on_host = true; + datamask_read_host |= force->bond->datamask_read; + datamask_modify_device |= force->bond->datamask_modify; + } else { + datamask_read_device |= force->bond->datamask_read; + datamask_modify_device |= force->bond->datamask_modify; + } + } + if (atomKK->molecular && force->angle) { + if (force->angle->execution_space==Host) { + execute_on_host = true; + datamask_read_host |= force->angle->datamask_read; + datamask_modify_device |= force->angle->datamask_modify; + } else { + datamask_read_device |= force->angle->datamask_read; + datamask_modify_device |= force->angle->datamask_modify; + } + } + if (atomKK->molecular && force->dihedral) { + if (force->dihedral->execution_space==Host) { + execute_on_host = true; + datamask_read_host |= force->dihedral->datamask_read; + datamask_modify_device |= force->dihedral->datamask_modify; + } else { + datamask_read_device |= force->dihedral->datamask_read; + datamask_modify_device |= force->dihedral->datamask_modify; + } + } + if (atomKK->molecular && force->improper) { + if (force->improper->execution_space==Host) { + execute_on_host = true; + datamask_read_host |= force->improper->datamask_read; + datamask_modify_device |= force->improper->datamask_modify; + } else { + datamask_read_device |= force->improper->datamask_read; + datamask_modify_device |= force->improper->datamask_modify; + } + } + if (kspace_compute_flag) { + if (force->kspace->execution_space==Host) { + execute_on_host = true; + datamask_read_host |= force->kspace->datamask_read; + datamask_modify_device |= force->kspace->datamask_modify; + } else { + datamask_read_device |= force->kspace->datamask_read; + datamask_modify_device |= force->kspace->datamask_modify; + } + } + + + if (pair_compute_flag) { + atomKK->sync(force->pair->execution_space,force->pair->datamask_read); + atomKK->sync(force->pair->execution_space,~(~force->pair->datamask_read|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + Kokkos::Timer ktimer; + force->pair->compute(eflag,vflag); + atomKK->modified(force->pair->execution_space,force->pair->datamask_modify); + atomKK->modified(force->pair->execution_space,~(~force->pair->datamask_modify|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + timer->stamp(Timer::PAIR); + } + + if (execute_on_host) { + if (pair_compute_flag && force->pair->datamask_modify!=(F_MASK | ENERGY_MASK | VIRIAL_MASK)) + Kokkos::fence(); + atomKK->sync_overlapping_device(Host,~(~datamask_read_host|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + if (pair_compute_flag && force->pair->execution_space!=Host) { + Kokkos::deep_copy(LMPHostType(),atomKK->k_f.h_view,0.0); + } + } + + if (atomKK->molecular) { + if (force->bond) { + atomKK->sync(force->bond->execution_space,~(~force->bond->datamask_read|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + force->bond->compute(eflag,vflag); + atomKK->modified(force->bond->execution_space,~(~force->bond->datamask_modify|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + } + if (force->angle) { + atomKK->sync(force->angle->execution_space,~(~force->angle->datamask_read|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + force->angle->compute(eflag,vflag); + atomKK->modified(force->angle->execution_space,~(~force->angle->datamask_modify|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + } + if (force->dihedral) { + atomKK->sync(force->dihedral->execution_space,~(~force->dihedral->datamask_read|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + force->dihedral->compute(eflag,vflag); + atomKK->modified(force->dihedral->execution_space,~(~force->dihedral->datamask_modify|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + } + if (force->improper) { + atomKK->sync(force->improper->execution_space,~(~force->improper->datamask_read|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + force->improper->compute(eflag,vflag); + atomKK->modified(force->improper->execution_space,~(~force->improper->datamask_modify|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + } + timer->stamp(Timer::BOND); + } + + if (kspace_compute_flag) { + atomKK->sync(force->kspace->execution_space,~(~force->kspace->datamask_read|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + force->kspace->compute(eflag,vflag); + atomKK->modified(force->kspace->execution_space,~(~force->kspace->datamask_modify|(F_MASK | ENERGY_MASK | VIRIAL_MASK))); + timer->stamp(Timer::KSPACE); + } + + if (execute_on_host && !std::is_same::value) { + if (f_merge_copy.extent(0)k_f.extent(0)) { + f_merge_copy = DAT::t_f_array("DynamicalMatrixKokkos::f_merge_copy",atomKK->k_f.extent(0)); + } + f = atomKK->k_f.d_view; + Kokkos::deep_copy(LMPHostType(),f_merge_copy,atomKK->k_f.h_view); + Kokkos::parallel_for(atomKK->k_f.extent(0), + ForceAdder(atomKK->k_f.d_view,f_merge_copy)); + atomKK->k_f.clear_sync_state(); // special case + atomKK->k_f.modify(); + } + if (n_pre_reverse) { + modify->pre_reverse(eflag,vflag); + timer->stamp(Timer::MODIFY); + } + if (force->newton) { + comm->reverse_comm(); + timer->stamp(Timer::COMM); + } + // force modifications + + if (n_post_force) modify->post_force(vflag); + timer->stamp(Timer::MODIFY); + + atomKK->sync(Host,F_MASK); + lmp->kokkos->auto_sync = 1; + + ++ update->nsteps; +} + +/* ---------------------------------------------------------------------- + clear force on own & ghost atoms + clear other arrays as needed +------------------------------------------------------------------------- */ + +void DynamicalMatrixKokkos::force_clear() +{ + if (external_force_clear) return; + + atomKK->k_f.clear_sync_state(); // ignore host forces/torques since device views + + // clear force on all particles + // if either newton flag is set, also include ghosts + // when using threads always clear all forces. + + int nall = atomKK->nlocal; + if (force->newton) nall += atomKK->nghost; + + Kokkos::parallel_for(nall, Zero::t_f_array>(atomKK->k_f.view())); + atomKK->modified(Device,F_MASK); + +} diff --git a/src/KOKKOS/dynamical_matrix_kokkos.h b/src/KOKKOS/dynamical_matrix_kokkos.h new file mode 100644 index 0000000000..9e9268423d --- /dev/null +++ b/src/KOKKOS/dynamical_matrix_kokkos.h @@ -0,0 +1,45 @@ +// +// Created by charlie sievers on 6/21/18. +// + +#ifdef COMMAND_CLASS +// clang-format off +CommandStyle(dynamical_matrix/kk,DynamicalMatrixKokkos); +CommandStyle(dynamical_matrix/kk/device,DynamicalMatrixKokkos); +CommandStyle(dynamical_matrix/kk/host,DynamicalMatrixKokkos); +// clang-format on +#else + +#ifndef LMP_DYNAMICAL_MATRIX_KOKKOS_H +#define LMP_DYNAMICAL_MATRIX_KOKKOS_H + +#include "dynamical_matrix.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +class DynamicalMatrixKokkos : public DynamicalMatrix { + public: + DynamicalMatrixKokkos(class LAMMPS *); + virtual ~DynamicalMatrixKokkos(); + void command(int, char **); + void setup(); + + KOKKOS_INLINE_FUNCTION + void operator() (const int& i) const { + f(i,0) += f_merge_copy(i,0); + f(i,1) += f_merge_copy(i,1); + f(i,2) += f_merge_copy(i,2); + } + + protected: + void update_force(); + void force_clear(); + DAT::t_f_array f_merge_copy,f; + + +}; +} // namespace LAMMPS_NS + +#endif //LMP_DYNAMICAL_MATRIX_KOKKOS_H +#endif diff --git a/src/PHONON/dynamical_matrix.h b/src/PHONON/dynamical_matrix.h index 0d1ba0c4d4..ceb717943d 100644 --- a/src/PHONON/dynamical_matrix.h +++ b/src/PHONON/dynamical_matrix.h @@ -19,8 +19,8 @@ class DynamicalMatrix : public Command { public: DynamicalMatrix(class LAMMPS *); virtual ~DynamicalMatrix(); - void command(int, char **); - void setup(); + virtual void command(int, char **); + virtual void setup(); protected: int eflag, vflag; // flags for energy/virial computation @@ -34,11 +34,10 @@ class DynamicalMatrix : public Command { int nvec; // local atomic dof = length of xvec - void update_force(); - void force_clear(); + virtual void update_force(); + virtual void force_clear(); virtual void openfile(const char *filename); - private: void options(int, char **); void calculateMatrix(); void dynmat_clear(double **dynmat);